Click here to Skip to main content
Click here to Skip to main content
Go to top

A Sortable XmlDocument Class

, 1 Feb 2009
Rate this:
Please Sign up or sign in to vote.
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

public enum SortType
{
    Ascending,
    Descending
}

TAXmlDocument.TAXmlSorter Abstract Class

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.

public sealed class TAXSNodeName : TAXmlSorter 

This class compares node names.

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.

public sealed class TAXSAttributeCount : TAXmlSorter

This class compares attribute counts.

public sealed class TAXSInnerText : TAXmlSorter

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

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

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

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.

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 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
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), new TAXmlDocument.TAXSNodeName() ); 

Output

<?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
TAXmlDocument doc = new TAXmlDocument();
doc.Load("c:\\xmlfile1.xml");
doc.Sort(doc.SelectSingleNode("root"), 
new TAXmlDocument.TAXSNodeName( TAXmlDocument.SortType.Descending ));

Output

?<?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)

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

Output

?<?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)

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

Output

?<?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

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

Output

?<?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

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

Output

?<?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)

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

Output

<?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):

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 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)

Share

About the Author

Tolgahan ALBAYRAK
Software Developer (Senior)
Turkey Turkey
No Biography provided

Comments and Discussions

 
GeneralVery nice Pinmemberandrew.chudley29-Jan-09 3:51 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140922.1 | Last Updated 1 Feb 2009
Article Copyright 2009 by Tolgahan ALBAYRAK
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid