1

I have tried using Linq to xml it seems it is not working.in brief i want sorting based on Code attribute in code tag i want the xml as desired one i have tried doing it as below but it is not working Please help me out.

C#: Sort xml node using attribute value

Attempted Code: I have attempted this code i am not sure if it is proper way.

var orderedTabs = document.Root
    .Element("component")
    .Elements("intial")
    .Elements("second")
    .Elements("component")
    .Elements("observation")
    .OrderBy(xtab => (string)xtab.Element("code").Attribute("code").Value) 
    .ToList();

XML:

<component>
   <intial>
        <second>
            <component>
                <observation>
                    <templateId root="01"/>
                    <id root="01" />
                    <code code="BC3" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC1" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC2" />
                    <statusCode code="completed" />
                </observation>
            </component>
        </second>
    </intial>
    <intial>
        <second>
            <component>
                <observation>
                    <templateId root="01"/>
                    <id root="01" />
                    <code code="BC6" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC4" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC5" />
                    <statusCode code="completed" />
                </observation>
            </component>
        </second>
    </intial>
</component>

Desired output:

<component>
   <intial>
        <second>
            <component>
                <observation>
                    <templateId root="01"/>
                    <id root="01" />
                    <code code="BC1" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC2" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC3" />
                    <statusCode code="completed" />
                </observation>
            </component>
        </second>
    </intial>
    <intial>
        <second>
            <component>
                <observation>
                    <templateId root="01"/>
                    <id root="01" />
                    <code code="BC4" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC5" />
                    <statusCode code="completed" />
                </observation>
            </component>
            <component>
                <observation>
                    <templateId root="01" />
                    <id root="01" />
                    <code code="BC6" />
                    <statusCode code="completed" />
                </observation>
            </component>
        </second>
    </intial>
</component>
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • Welcome to StackOverflow. Please share with us what have you tried so far and where did you get stuck. – Peter Csala Jul 16 '21 at 10:31
  • Thank you for responding @PeterCsala I have tried this but i do not know i am doing it in right way if this is wrong may i know the right way so i can sort the XML `code` var orderedTabs = document.Root.Element("component").Elements("intial").Elements("second").Elements("component").Elements("observation") .OrderBy(xtab => (string)xtab.Element("code").Attribute("code").Value) .ToList(); – pranayrebel Jul 16 '21 at 11:19
  • Please amend/edit your post to include code – Peter Csala Jul 16 '21 at 11:20
  • I am confused this is my first ever question to post in Stackoverflow may i know what exactly you are referring to – pranayrebel Jul 16 '21 at 11:31
  • There is an `Edit` link under each post. You can click on that to alter your question to include more details. – Peter Csala Jul 16 '21 at 11:34
  • Is `document` an `XDocument`, right? – Peter Csala Jul 16 '21 at 11:51
  • Yes It is an `XDocument` – pranayrebel Jul 16 '21 at 11:56

2 Answers2

1

You are only getting the elements and performing sort on it. This will just give a sorted output, but it won't change the xml document. You have to sort and then replace the unsorted elements with the sorted ones.

Given your structure you can do it like this -

var items = document.Element("component")
            .Elements("intial")
            .Elements("second");
foreach (var item in items)
{
    var tabs = item.Elements("component").Elements("observation");
    var orderedTabs = tabs
        .OrderBy(xtab => xtab.Element("code").Attribute("code").Value)
        .Select(s => new XElement("component", s))
        .ToList();
    item.ReplaceAll(orderedTabs);
}
Nikhil Patil
  • 2,480
  • 1
  • 7
  • 20
0

My solution:

var unorderedDocument = XDocument.Load("sample.xml");

var seconds = unorderedDocument.Descendants("second");
foreach (var second in seconds)
{
    var orderedComponents = second.Elements().OrderBy(t => t.Descendants("code").First().Attribute("code").ToString());
    second.ReplaceAll(orderedComponents.ToList());
}

using var memory = new MemoryStream();
unorderedDocument.Save(memory);
string orderedXml = Encoding.UTF8.GetString(memory.ToArray());
Console.WriteLine(orderedXml.ToString());

How does it work?

  • It parses the xml from a file (Descendants("second"))
  • It retrieves the <second> elements and all their children (Descendants("second"))
  • It iterates through the <second> nodes (foreach var second)
  • It orders the <component> (Elements) nodes based on the <code> node's code attribute
  • It replaces the original <second> node's children with the newly ordered <component> nodes (ReplaceAll)
  • It writes the whole document into a MemoryStream (Save)
  • It converts the MemoryStream to a string (Encoding.UTF8.GetString)
  • It prints out the result to the output
<?xml version="1.0" encoding="utf-8"?>
<component>
  <intial>
    <second>
      <component>
        <observation>
          <templateId root="01" />
          <id root="01" />
          <code code="BC1" />
          <statusCode code="completed" />
        </observation>
      </component>
      <component>
        <observation>
          <templateId root="01" />
          <id root="01" />
          <code code="BC2" />
          <statusCode code="completed" />
        </observation>
      </component>
      <component>
        <observation>
          <templateId root="01" />
          <id root="01" />
          <code code="BC3" />
          <statusCode code="completed" />
        </observation>
      </component>
    </second>
  </intial>
  <intial>
    <second>
      <component>
        <observation>
          <templateId root="01" />
          <id root="01" />
          <code code="BC4" />
          <statusCode code="completed" />
        </observation>
      </component>
      <component>
        <observation>
          <templateId root="01" />
          <id root="01" />
          <code code="BC5" />
          <statusCode code="completed" />
        </observation>
      </component>
      <component>
        <observation>
          <templateId root="01" />
          <id root="01" />
          <code code="BC6" />
          <statusCode code="completed" />
        </observation>
      </component>
    </second>
  </intial>
</component>
Peter Csala
  • 17,736
  • 16
  • 35
  • 75