1
votes

Can any one help me to sort the XmlDocument based on attribute value.

I have given a sample xml having few attr elements. So I want to sort it based on "value" attribute of elements having attribute Name="from" I am trying to achieve this using linq to xml.

Here is one sample code I tried. But it is retaining only the "from" attributes in sorted order. I want all the attributes as shown below under expected xml.

container.ReplaceNodes(
            from childEl in container.Elements().Elements()
            where childEl.Attribute("Name")?.Value == "from"
            orderby childEl.Attribute("Value")?.Value descending
            select childEl
        );
        foreach (XElement childEl in container.Elements().Where(e => e.HasElements))
    {
        SortByName(childEl);
    }

Input XML:

`<Attrs>
  <Attr Name="zddressprevious" isVerified="false">
    <Attr Name="from" Value="2014-01-01" isVerified="false" />
    <Attr Name="house" Value="3" isVerified="false" />
    <Attr Name="street" Value="Test Street" isVerified="false" />
  </Attr>
  <Attr Name="addressprevious" isVerified="false">
    <Attr Name="from" Value="2015-01-01" isVerified="false" />
    <Attr Name="house" Value="1" isVerified="false" />
    <Attr Name="street" Value="Acacia Avenue" isVerified="false" />
  </Attr>
  <Attr Name="addressprevious" isVerified="false">
    <Attr Name="from" Value="2016-01-01" isVerified="false" />
    <Attr Name="house" Value="1" isVerified="false" />
    <Attr Name="street" Value="Test Street" isVerified="false" />
   </Attr>
</Attrs>`

Expected output:

`<?xml version="1.0" encoding="utf-8"?>
<Attrs>
  <Attr <Attr Name="addressprevious" isVerified="false">
    <Attr Name="from" Value="2016-01-01" isVerified="false" />
    <Attr Name="house" Value="1" isVerified="false" />
    <Attr Name="street" Value="Test Street" isVerified="false" />
   </Attr>
   <Attr Name="addressprevious" isVerified="false">
    <Attr Name="from" Value="2015-01-01" isVerified="false" />
    <Attr Name="house" Value="1" isVerified="false" />
    <Attr Name="street" Value="Acacia Avenue" isVerified="false" />
  </Attr>
  <Attr Name="zddressprevious" isVerified="false">
    <Attr Name="from" Value="2014-01-01" isVerified="false" />
    <Attr Name="house" Value="3" isVerified="false" />
    <Attr Name="street" Value="Test Street" isVerified="false" />
  </Attr>
</Attrs>`
1

1 Answers

0
votes

Your LINQ statement has to return the parent element (of the one containing the from-attribute) via childEl.Parent.

From your question is not completely clear whether your container is an XDocumentor an XElement.

In case of an XElement the LINQstatement looks like:

var q =
    from childEl in container.Elements("Attr").Elements("Attr")                
    where childEl.Attribute("Name")?.Value == "from"
    orderby childEl.Attribute("Value")?.Value descending
    select childEl.Parent
    ;

and the replace as:

container.ReplaceNodes(q);

Note that the LINQ statement without explicitly specifying the Attrelement names will also do the job:

var q =
    from childEl in container.Elements().Elements()                
    where childEl.Attribute("Name")?.Value == "from"
    orderby childEl.Attribute("Value")?.Value descending
    select childEl.Parent
    ;



In case of an XDocument your query must look like:

var q =
    from childEl in container.Element("Attrs").Elements("Attr").Elements("Attr")                
    where childEl.Attribute("Name")?.Value == "from"
    orderby childEl.Attribute("Value")?.Value descending
    select childEl.Parent
    ;

and you have to replace the nodes via:

container.Element("Attrs").ReplaceAll(q);