对xml数据排序的方法多种多样, 例如可以把xml数据转换为DataTable,然后进行排序;也可以使用xslt进行排序等等。
这里介绍如何使用XPathExpression 对xml数据根据某节点或者某一个attribute进行排序。
例如,我们根据PublishDate(发表时间) 节点对以下数据进行倒序排序:
Code
<?xml version="1.0" encoding="utf-8" ?>
<Articles>
<Article>
<ID>1</ID>
<Title>Article1</Title>
<PublishDate>2009-06-05 08:45:25</PublishDate>
</Article>
<Article>
<ID>2</ID>
<Title>Article2</Title>
<PublishDate>2009-06-07 06:43:16</PublishDate>
</Article>
<Article>
<ID>3</ID>
<Title>Article3</Title>
<PublishDate>2009-11-05 01:01:40</PublishDate>
</Article>
<Article>
<ID>4</ID>
<Title>Article4</Title>
<PublishDate>2009-08-05 14:01:01</PublishDate>
</Article>
<Article>
<ID>5</ID>
<Title>Article5</Title>
<PublishDate>2009-12-05 09:25:34</PublishDate>
</Article>
</Articles>
Code
XmlDocument SortXMLDoc(XmlDocument xmldoc)
{
XmlDocument xmlDocCopy = new XmlDocument();
xmlDocCopy.LoadXml(xmldoc.OuterXml);
XmlNode XmlNodeCopy = xmlDocCopy.SelectSingleNode("//Articles");
XmlNodeCopy.RemoveAll();
//XmlNodeCopy.InnerXml = "<NewsCategory Category=\"NA\"></NewsCategory>";
XmlNode node = xmldoc.SelectSingleNode("//Articles");
XPathNavigator navigator = node.CreateNavigator();
XPathExpression selectExpression = navigator.Compile("Article/PublishDate");
selectExpression.AddSort(".", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Text);
//DateTimeComparer datesort = new DateTimeComparer();
//selectExpression.AddSort(".", datesort);
XPathNodeIterator nodeIterator = navigator.Select(selectExpression);
while (nodeIterator.MoveNext())
{
//XmlNode currentNode = (XmlNode)nodeIterator.Current.ValueAs( typeof(XmlNode)) ;
XmlNode linkNode = xmldoc.SelectSingleNode("//Article[PublishDate=\"" + nodeIterator.Current.Value + "\"]");
XmlNode importedLinkNode = xmlDocCopy.ImportNode(linkNode, true);
xmlDocCopy.SelectSingleNode("//Articles").AppendChild(importedLinkNode);
}
return xmlDocCopy;
}
留意selectExpression.AddSort(".", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Text); 这句代码。
XmlDataType只支持Text 和 Number, 而我们需要排序的字段是DateTime类型,显然排序出来的数据肯定是不对的。
如何解决这个问题呢? 我们发现AddSort方法有重载,定义如下:
public abstract void AddSort(object expr, IComparer comparer);
我们可以实现自己的Comparer, 马上察看IComparer接口:
Code
namespace System.Collections
{
// Summary:
// Exposes a method that compares two objects.
[ComVisible(true)]
public interface IComparer
{
// Summary:
// Compares two objects and returns a value indicating whether one is less than,
// equal to, or greater than the other.
//
// Parameters:
// x:
// The first object to compare.
//
// y:
// The second object to compare.
//
// Returns:
// Value Condition Less than zero x is less than y. Zero x equals y. Greater
// than zero x is greater than y.
//
// Exceptions:
// System.ArgumentException:
// Neither x nor y implements the System.IComparable interface.-or- x and y
// are of different types and neither one can handle comparisons with the other.
int Compare(object x, object y);
}
}
我们只要实现Compare接口就可以了,代码如下:
Code
public class DateTimeComparer : IComparer
{
int IComparer.Compare(Object x, Object y)
{
return DateTime.Compare(Convert.ToDateTime(y), Convert.ToDateTime(x));
}
}
然后把selectExpression.AddSort(".", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Text);
代码替换成
DateTimeComparer datesort = new DateTimeComparer();
selectExpression.AddSort(".", datesort);
就大功告成了!