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 (parentNode.ChildNodes.Count < 2)
return;
XmlNode[] nodes = new XmlNode[parentNode.ChildNodes.Count];
for (int i = 0; i < nodes.Length; i++)
nodes[i] = parentNode.ChildNodes[i];
sorter.InitArray(nodes);
Array.Sort(nodes, sorter);
parentNode.InnerXml = "";
for (int i = 0; i < nodes.Length; i++)
parentNode.AppendChild(nodes[i]);
}
Using the Code
XmlFile1.xml Content
="1.0"="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
="1.0"="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
?="1.0"="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
?="1.0"="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
?="1.0"="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
?="1.0"="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
?="1.0"="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
="1.0"="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
?="1.0"="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