基于DateTime属性C#,XPath对XML节点进行排序
我有一个看起来像这样的XML结构。
...
我试图找到一种方法来根据sTime属性SORT节点,这是一个DateTime.ToString()值。 诀窍是我需要保持节点的机智,由于某种原因,我找不到办法做到这一点。 我很确定LINQ和XPath有办法做到这一点,但我被卡住了,因为我似乎无法根据DateTime.ToString()值进行排序。
XPathDocument saleResults = new XPathDocument(@"temp/salesData.xml"); XPathNavigator navigator = saleResults.CreateNavigator(); XPathExpression selectExpression = navigator.Compile("sales/item/@sTime"); selectExpression.AddSort("@sTime", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Number); XPathNodeIterator nodeIterator = navigator.Select(selectExpression); while( nodeIterator.MoveNext() ) { string checkMe = nodeIterator.Current.Value; }
我还需要维护一个指向NODE的指针来检索其他属性的值。
也许这并不像我想的那么简单。
谢谢。
解决方案 :这是我最终使用的内容。 获取所选答案和IComparable类,这就是我如何根据sTime属性对XML节点进行排序,然后将所有属性放入相应的Arrays中以便稍后使用。
XPathDocument saleResults = new XPathDocument(@"temp/salesData.xml"); XPathNavigator navigator = saleResults.CreateNavigator(); XPathExpression selectExpression = navigator.Compile("sales/item"); XPathExpression sortExpr = navigator.Compile("@sTime"); selectExpression.AddSort(sortExpr, new DateTimeComparer()); XPathNodeIterator nodeIterator = navigator.Select(selectExpression); int i = 0; while (nodeIterator.MoveNext()) { if (nodeIterator.Current.MoveToFirstAttribute()) { _iNameList.SetValue(nodeIterator.Current.Value, i); } if (nodeIterator.Current.MoveToNextAttribute()) { _iSkuList.SetValue(nodeIterator.Current.Value, i); } ... nodeIterator.Current.MoveToParent(); i++; }
XPathExpression.Addsort超载,它采用IComparer接口。 如果您自己将比较实现为IComparer,则可以使用此机制。
class Program { static void Main(string[] args) { XPathDocument saleResults = new XPathDocument( @"salesData.xml" ); XPathNavigator navigator = saleResults.CreateNavigator( ); XPathExpression selectExpression = navigator.Compile( "sales/item" ); XPathExpression sortExpr = navigator.Compile("@sTime"); selectExpression.AddSort(sortExpr, new DateTimeComparer()); XPathNodeIterator nodeIterator = navigator.Select( selectExpression ); while ( nodeIterator.MoveNext( ) ) { string checkMe = nodeIterator.Current.Value; } } public class DateTimeComparer : IComparer { public int Compare(object x, object y) { DateTime dt1 = DateTime.Parse( x.ToString( ) ); DateTime dt2 = DateTime.Parse( y.ToString( ) ); return dt1.CompareTo( dt2 ); } } }
干得好:
XmlDocument myDoc = new XmlDocument(); myDoc.LoadXml(@" "); var sortedItems = myDoc.GetElementsByTagName("item").OfType() .OrderBy(item => DateTime.ParseExact(item.GetAttribute("sTime"), "MM/dd/yyyy h:mm:ss tt", null)); foreach (var item in sortedItems) { Console.WriteLine(item.OuterXml); }
这是一个完美运行的控制台应用程序。
这是一个XSLT解决方案:
<销售> 的xsl:for-each>的 销售> XSL:模板> XSL:样式>
将此转换应用于以下XML文档时 :
<销售>- 销售>
产生了正确的结果:
<销售>- 销售>
如果正确构造XML,那么您正在尝试做的事情会轻松完成。 XML Schema建议说日期/时间值应以ISO8601格式表示,即CCCC-MM-DD HH:MM:SS
。 (实际上,XML Schema希望日期和时间之间的分隔符为T,而此刻我不记得原因。)
以这种方式格式化日期和时间的两个主要优点是:
- 这就是XML的其他用户所期望的,以及
- 您可以对其字符串值进行排序。
在XSLT处理的XML中以任何其他方式格式化日期是一种残酷的做法。
使.NET以这种格式发出DateTime值很容易(使用“s”格式说明符,代表 – 等待它 – “可排序”)。
假设你的日期时间是这种格式
2010-06-01T15:16:29 + 05:00
那么最简单的方法就是
在DATETIME中我只能以我的日期时间格式替换额外的字符我有额外的字符( – T:和+)所以只需更换它然后您的日期时间将是数字格式,可以轻松排序
我知道这个问题很老,你可能有一个解决方案,但我想分享我的答案:
private static void SortElementAttributesBasis(XmlNode rootNode) { for (int j = 0; j < rootNode.ChildNodes.Count; j++) { for (int i = 1; i < rootNode.ChildNodes.Count; i++) { Console.WriteLine(rootNode.OuterXml); DateTime dt1 = DateTime.ParseExact(rootNode.ChildNodes[i].Attributes["sTime"].Value, "M/d/yyyy h:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture); DateTime dt2 = DateTime.ParseExact(rootNode.ChildNodes[i-1].Attributes["sTime"].Value, "M/d/yyyy h:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture); int compare = DateTime.Compare(dt1,dt2); if (compare < 0) { rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]); Console.WriteLine(rootNode.OuterXml); } // Provide the name of Attribute in .Attribute["Name"] based on value you want to sort. //if (String.Compare(rootNode.ChildNodes[i].Attributes["sTime"].Value, rootNode.ChildNodes[1 - 1].Attributes["sTime"].Value) < 0) //{ // rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]); //} } } }
输入XML是由@Dimitre Novatchev提供的示例
产量