Search code examples
c#xelement

Formatting an elements text using descendants of XElement


Im wondering how to select a specific element from the heirarchy so that I can format its text.

In the example below I would like to format the specific element to remove the time portion of the date, but I am also looking for a way to format any of the elements for example to add a currency symbol to the text between each price tag.

My example

<orders>
  <order>
    <type> tools </type> //I would like the ability to select this element
    <text> screwdriver </text>
    <id> 100981 </id>
    <price> 5.00 </price>
    <date> 01/01/15 12:51:36 </date>
 </order>

  <order>
    <type> uniform </type>
    <text> boots </text>
    <id> 100546 </id>
    <price> 25.00 </price>
    <date> 12/01/15 15:30:41 </date>
  </order>
</orders>

What I have so far

foreach (XElement element in doc.Descendants())
{
    var nodes = element.Nodes().Where(p => p.NodeType == XmlNodeType.Text);

    foreach (XText node in nodes)
    {
      node.Value = FirstLetterToUpper( node.Value );// set the first letter of each output to be uppercase
     }
}

What I have tried

foreach (XElement element in doc.Descendants())
{
    var nodes = element.Nodes().Where(p => p.NodeType == XmlNodeType.Text);

    if( element.Descendants() == element.Element("date"))
    {
         element.Value = Convert.ToDateTime(element.Value).ToShortDateString();
    }

    foreach (XText node in nodes)
    {
      node.Value = FirstLetterToUpper( node.Value );
    }
}

I have some XML experience but have never worked with XElement before.

I've been searching SO for a while now but cant find what Im looking for. The answers below are some of the suggested answers from typing this question but they dont provide a solution as the XML elements are generated dynamically in a loop.

XElement node with text node has its formatting ignored

string.Format in XElement not formatting

Any help with this would be great as I have not attempted this before. Thanks.


Solution

  • You can get the text node's parent using Parent property and check it's name:

    foreach (XText node in doc.DescendantNodes()
                              .Where(x => NodeType == XmlNodeType.Text))
    {
           if(node.Parent.Name == "date") { ... }
           if(node.Parent.Name == "price") { ... }
    }
    

    BTW, don't forget the save the document using XDocument.Save method after you made the changes.