#region NodeSorter : IComparer
// Reference: http://msdn2.microsoft.com/en-us/library/aw9s5t8f(VS.80).aspx
public class NodeSorter : IComparer
{
// The relative XPath from the node to the element used for comparison.
string sXpathSortBy;
// Reverse multiplier
int iReverse = 1;
// Convenience constructors
public NodeSorter(string relativeXPath) : this(relativeXPath, false) { }
// Actual constructor
public NodeSorter(string relativeXPath, bool reverse)
{
sXpathSortBy = relativeXPath;
if (reverse)
iReverse = -1;
}
/// <summary>
/// Sorts the DOM in place.
/// </summary>
/// <param name="ListToBeSorted"></param>
public void SortNodes(IXMLDOMNodeList ListToBeSorted)
{
if (ListToBeSorted == null)
throw new ArgumentException("List to be sorted must not be null.");
if (ListToBeSorted.length == 0)
return;
IXMLDOMNode nParent = ListToBeSorted[0].parentNode;
IXMLDOMNode[] arNodeList = new IXMLDOMNode[ListToBeSorted.length];
// Read the nodes from the NodeList into the array of nodes
for (int i = 0; i < ListToBeSorted.length; i++)
{
arNodeList[i] = ListToBeSorted[i];
}
// reset the iterator as a convenience for whoever called this method
ListToBeSorted.reset();
// Sort the array
Array.Sort(arNodeList, this);
// Remove all of the old, unsorted nodes
((IXMLDOMSelection)ListToBeSorted).removeAll();
// Add the sorted nodes back in
for (int i = 0; i < arNodeList.Length; i++)
nParent.appendChild(arNodeList[i]);
}
/// <summary>
/// Sorts the nodes in place.
/// </summary>
/// <param name="ListToBeSorted">The list to be sorted.</param>
/// <param name="xpath">The relative XPath to the node (underneath each child) to be used for comparison.</param>
public static void SortNodes(IXMLDOMNodeList ListToBeSorted, string xpath)
{
SortNodes(ListToBeSorted, xpath, false);
}
/// <summary>
/// Sorts the nodes in place.
/// </summary>
/// <param name="ListToBeSorted">The list to be sorted.</param>
/// <param name="xpath">The relative XPath to the node (underneath each child) to be used for comparison.</param>
/// <param name="reverse">If true, reverse the order of the sort</param>
public static void SortNodes(IXMLDOMNodeList ListToBeSorted, string xpath, bool reverse)
{
NodeSorter ns = new NodeSorter(xpath, reverse);
ns.SortNodes(ListToBeSorted);
}
int IComparer.Compare(Object left, Object right)
{
// This might throw an InvalidCastException,
// but that will be up to the programmer to catch.
IXMLDOMNode lhs = ((IXMLDOMNode)left).selectSingleNode(sXpathSortBy);
IXMLDOMNode rhs = ((IXMLDOMNode)right).selectSingleNode(sXpathSortBy);
if (lhs == null || rhs == null)
throw new NullReferenceException("XPath string provided resulted in a null node.");
// try numeric sorting first
try
{
double dLhs = Double.Parse(lhs.text);
double dRhs = Double.Parse(rhs.text);
// If we reach this statement, both values are numeric
if (dLhs > dRhs)
return 1 * iReverse;
else if (dLhs < dRhs)
return -1 * iReverse;
else
return 0;
}
catch (Exception ex) { }
// If we reach this statement, both values are non-numeric
// so we will treat them as strings
return String.Compare(lhs.text, rhs.text) * iReverse;
}
}
#endregion