Click here to Skip to main content
15,881,757 members
Articles / Web Development / ASP.NET

A Sortable XmlDocument Class

Rate me:
Please Sign up or sign in to vote.
4.88/5 (10 votes)
1 Feb 2009CPOL1 min read 40.1K   324   39   7
Sort the nodes of XmlDocument by many methods easily

Introduction

This class makes XmlDocument class sortable. Actually, I did not search much to see if there is something like this already. I needed it and I wrote it. And, I thought that someone might find this useful.

Background

Basically, this class runs a TAXmlSorter class to sort nodes. TAXmlSorter is an abstract class that implements IComparer<XmlNode> interface. Other comparison classes are based on TAXmlSorter

TAXmlDocument.SortType Enumeration

C#
public enum SortType
{
    Ascending,
    Descending
}

TAXmlDocument.TAXmlSorter Abstract Class

C#
public abstract class TAXmlSorter:IComparer<XmlNode>
{
    Comparison<XmlNode> comparisonDelegate;
    protected TAXmlSorter(SortType st)
    {
        switch (st)
        {
            case SortType.Ascending:
                comparisonDelegate = CompareAsc;
                break;
            case SortType.Descending:
                comparisonDelegate = CompareDesc;
                break;
        }
    }
     protected abstract int CompareAsc(XmlNode x, XmlNode y);
    protected abstract int CompareDesc(XmlNode x, XmlNode y);
     public abstract void InitArray(XmlNode[] array);
     #region IComparer<XmlNode> Members
     int IComparer<XmlNode>.Compare(XmlNode x, XmlNode y)
    {
        return comparisonDelegate(x, y);
    }
     #endregion
}

I used a comparison delegate to better performance. In this way, the application will determine the comparison function on initialize, so it won't check every time if it is an ascending sort.

C#
public sealed class TAXSNodeName : TAXmlSorter 

This class compares node names.

C#
public sealed class TAXSNodeAttribute<AttributeType> : TAXmlSorter
       where AttributeType : IComparable, IConvertible

This class compares attribute of current node.

public sealed class TAXSChildCount : TAXmlSorter

This class compares child node counts.

C#
public sealed class TAXSAttributeCount : TAXmlSorter

This class compares attribute counts.

C#
public sealed class TAXSInnerText : TAXmlSorter

This class compares nodes' inner text values (string comparison).

C#
public sealed class TAXSInnerValue<ValueType> : TAXmlSorter
    where ValueType : IComparable, IConvertible 

This class compares nodes' inner text values (firstly converts to given type).

C#
public sealed class TAXSMulti : TAXmlSorter

This class is a multi comparison class.

Sorting

Actually this class does not use any special sort algorithm. It is based on Array.Sort function.

C#
public void Sort(XmlNode parentNode, TAXmlSorter sorter)
{
    if (parentNode == null)
        throw new ArgumentNullException("parentNode");
    if (sorter == null)
        throw new ArgumentNullException("sorter");
    if (parentNode.OwnerDocument != this)
        throw new Exception(
            "parentNode value is not child of this document");
    //if childcount less than 2 then it is not necessary to sort
    if (parentNode.ChildNodes.Count < 2)
        return;
    //copy the child of parent
    XmlNode[] nodes = new XmlNode[parentNode.ChildNodes.Count];
    for (int i = 0; i < nodes.Length; i++)
        nodes[i] = parentNode.ChildNodes[i];
    
    //call abstract initarray method of sorter
    sorter.InitArray(nodes);
     //call array.sort to sort nodes
    Array.Sort(nodes, sorter);
      //remove all child nodes of parent
    parentNode.InnerXml = "";
     //add sorted nodes
    for (int i = 0; i < nodes.Length; i++)
        parentNode.AppendChild(nodes[i]);
}

Using the Code

XmlFile1.xml Content

XML
<?xml version="1.0" encoding="utf-8" ?>
<root>
  <q>5</q>
  <s/>
  <a/>
  <a id="1">
    <b>
      <c>123</c>
    </b>
  </a>
  <r num="0.1" id="2">false</r>
  <tolgahan id="0" />
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <zoom/>
  <zoom id="-1"/>
</root>

Sort By Node Name

Ascending
C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), new TAXmlDocument.TAXSNodeName() ); 

Output

XML
<?xml version="1.0" encoding="utf-8"?>
<root>
  <a id="1">
    <b>
      <c>
      </c>
    </b>
  </a>
  <a />
  <q>
  </q>
  <r num="0.1" id="2">
  </r>
  <s />
  <tolgahan id="0" />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <zoom id="-1" />
  <zoom />
</root>
Descending
C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
new TAXmlDocument.TAXSNodeName( TAXmlDocument.SortType.Descending ));

Output

XML
?<?xml version="1.0" encoding="utf-8"?>
<root>
  <zoom />
  <zoom id="-1" />
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <tolgahan id="0" />
  <s />
  <r num="0.1" id="2">
  </r>
  <q>
  </q>
  <a />
  <a id="1">
    <b>
      <c>
      </c>
    </b>
  </a>
</root>

All comparison classes have SortType (ascending or descending) parameter on constructor.

Sort by Attribute Value (If it is boolean)

C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
         new TAXmlDocument.TAXSNodeAttribute<Boolean>( "bool" ));

Output

XML
?<?xml version="1.0" encoding="utf-8"?>
<root>
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <tolgahan id="0" />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <zoom id="-1" />
  <zoom />
  <a />
  <s />
  <q>
  </q>
  <r num="0.1" id="2">
  </r>
  <a id="1">
    <b>
      <c>
      </c>
    </b>
  </a>
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
</root>

Sort by Attribute Value (If it is date)

C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
         new TAXmlDocument.TAXSNodeAttribute<DateTime>( "date", 
                           TAXmlDocument.SortType.Descending ));

Output

XML
?<?xml version="1.0" encoding="utf-8"?>
<root>
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <zoom id="-1" />
  <zoom />
  <tolgahan id="0" />
  <s />
  <q>
  </q>
  <a />
  <r num="0.1" id="2">
  </r>
  <a id="1">
    <b>
      <c>
      </c>
    </b>
  </a>
</root>

Sort by ChildCount

C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
    new TAXmlDocument.TAXSChildCount());

Output

XML
?<?xml version="1.0" encoding="utf-8"?>
<root>
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <zoom id="-1" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <zoom />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <tolgahan id="0" />
  <s />
  <a />
  <q>5</q>
  <a id="1">
    <b>
      <c>123</c>
    </b>
  </a>
  <r num="0.1" id="2">false</r>
</root>

Sort by Attribute Count

C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
    new TAXmlDocument.TAXSAttributeCount());

Output

XML
?<?xml version="1.0" encoding="utf-8"?>
<root>
  <a />
  <zoom />
  <q>5</q>
  <s />
  <zoom id="-1" />
  <tolgahan id="0" />
  <a id="1">
    <b>
      <c>123</c>
    </b>
  </a>
  <r num="0.1" id="2">false</r>
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
</root>

Sort by Inner Value (Try to Sort Integer Value)

C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
    new TAXmlDocument.TAXSInnerValue<Int32>());

Output

XML
<?xml version="1.0" encoding="utf-8"?>
<root>
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <zoom id="-1" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
  <zoom />
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <s />
  <tolgahan id="0" />
  <a />
  <r num="0.1" id="2">false</r>
  <q>5</q>
  <a id="1">
    <b>
      <c>123</c>
    </b>
  </a>
</root>

Multi Sorting 

(Try to sort firstly boolean attribute "bool" desc, then date attribute "date" asc, then inner value):

C#
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"),
    new TAXmlDocument.TAXSMulti(
        new TAXmlDocument.TAXSNodeAttribute<Boolean>("bool",
        TAXmlDocument.SortType.Descending),
        new TAXmlDocument.TAXSNodeAttribute<DateTime>("date"),
        new TAXmlDocument.TAXSInnerValue<Int32>()
    )
);

Output

XML
?<?xml version="1.0" encoding="utf-8"?>
<root>
  <tolgahanAlbayrak bool="true" date="01.01.2008 15:13:10" />
  <r num="0.1" id="2">false</r>
  <zoom id="-1" />
  <zoom />
  <s />
  <tolgahan id="0" />
  <a />
  <q>5</q>
  <a id="1">
    <b>
      <c>123</c>
    </b>
  </a>
  <tolgahanAlbayrak bool="false" date="01.01.2008 11:13:10" />
  <tolgahanAlbayrak bool="false" date="01.02.2008 15:13:10" />
</root> 

History

  • 02 Feb 2009: Added sorting operation for child element's one of child value by Andrew Chudley
  • 13 Jan 2009: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Turkey Turkey
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionEXCELENT Pin
Member 1078077726-Jan-15 11:50
Member 1078077726-Jan-15 11:50 
GeneralSort By XPath Pin
James Hutchison28-Nov-12 7:30
James Hutchison28-Nov-12 7:30 
Generalfor sorting elements by their child elements [modified] Pin
andrew.chudley29-Jan-09 5:46
professionalandrew.chudley29-Jan-09 5:46 
GeneralRe: for sorting elements by their child elements Pin
Tolgahan ALBAYRAK1-Feb-09 14:11
Tolgahan ALBAYRAK1-Feb-09 14:11 
GeneralVery nice Pin
andrew.chudley29-Jan-09 3:51
professionalandrew.chudley29-Jan-09 3:51 
GeneralCool way Pin
Dr.Luiji14-Jan-09 12:21
professionalDr.Luiji14-Jan-09 12:21 
GeneralRe: Cool way Pin
Tolgahan ALBAYRAK19-Jan-09 3:53
Tolgahan ALBAYRAK19-Jan-09 3:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.