Sort using LINQ to XML

The hobby for the last few days was to “play” with XML and LINQ syntax.

Something that I’ve tried doing was to sort an XML document not using XSL stylesheet¬†but using LINQ. I’ve start by sorting the root elements from the XML documents.

        private static XElement Sort(XElement element)
        {
            return new XElement(element.Name,
                    element.Attributes(),
                    from child in element.Nodes()
                    where child.NodeType != XmlNodeType.Element
                    select child,
                    from child in element.Elements()
                    orderby child.Name.ToString()
                    select Sort(child));
        }

        private static XDocument Sort(XDocument file)
        {
            return new XDocument(
                    file.Declaration,
                    from child in file.Nodes()
                    where child.NodeType != XmlNodeType.Element
                    select child,
                    Sort(file.Root));
        }

Next step was to sort  deep XNodes. In order to this we need to identify the node:

                IEnumerable<XElement> currentNode =
                    (from el in xDocReport.Root.Elements("Incident")
                     where (string)el.Attribute("INumber") == refrence.ToString()
                     select el                  
                     );

… then based on the node we just do the sorting

                var xmlQuery = from item in currentNode.First().Descendants("Update")
                            orderby (Int32)item.Attribute("UNumber") descending
                            select item;

… then just replace the container with the one sorted

currentNode.First().Element("Updates").ReplaceWith(new XElement ("Updates", xmlQuery.Take(5)));

Take.(5) means that we are just taking the lsat 5 elemenst from the query.

All the above will be done in a foreach statement:

// Normal

foreach (var itemTest in xDocReport.Root.Elements("Incident").Attributes("INumber")) { }

// multi threading 

Parallel.ForEach(xDocReport.Root.Elements("Incident").Attributes("INumber"), itemTest => { });

The full schema based on which the XML was created and the LINQ query applied was looking as the one below:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Report">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="Incident">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Company" type="xs:string" />
              <xs:element name="Description" type="xs:string" />
              <xs:element name="Priority" type="xs:unsignedByte" />
              <xs:element name="RemainingSLA" type="xs:string" />
              <xs:element name="SLA-Stage" type="xs:string" />
              <xs:element name="Updates">
                <xs:complexType>
                  <xs:sequence minOccurs="0">
                    <xs:element maxOccurs="unbounded" name="Update">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="Text" type="xs:string" />
                          <xs:element name="UpdatedBy" type="xs:string" />
                          <xs:element name="UpdateTime" type="xs:string" />
                        </xs:sequence>
                        <xs:attribute name="UNumber" type="xs:unsignedShort" use="required" />
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="INumber" type="xs:string" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *