![](/img/trans.png)
[英]Sorting XML nodes based on DateTime attribute C#, XPath (refer to an old post)
[英]Sorting XML nodes based on DateTime attribute C#, XPath
我有一个看起来像这样的XML结构。
<sales>
<item name="Games" sku="MIC28306200" iCat="28"
sTime="11/26/2008 8:41:12 AM"
price="1.00" desc="Item Name" />
<item name="Games" sku="MIC28307100" iCat="28"
sTime="11/26/2008 8:42:12 AM"
price="1.00" desc="Item Name" />
...
</sales>
我试图找到一种方法来根据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++;
}
干得好:
XmlDocument myDoc = new XmlDocument();
myDoc.LoadXml(@"
<sales>
<item name=""Games""
sku=""MIC28306200""
iCat=""28""
sTime=""11/26/2008 8:41:12 AM""
price=""1.00""
desc=""Item Name"" />
<item name=""Games""
sku=""MIC28307100""
iCat=""28""
sTime=""11/26/2008 8:42:12 AM""
price=""1.00""
desc=""Item Name"" />
</sales>
");
var sortedItems = myDoc.GetElementsByTagName("item").OfType<XmlElement>()
.OrderBy(item => DateTime.ParseExact(item.GetAttribute("sTime"), "MM/dd/yyyy h:mm:ss tt", null));
foreach (var item in sortedItems)
{
Console.WriteLine(item.OuterXml);
}
这是一个完美运行的控制台应用程序。
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 );
}
}
}
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="sales"> <sales> <xsl:for-each select="item"> <xsl:sort select="substring(@sTime,7,4)" data-type="number"/> <xsl:sort select="substring(@sTime,1,2)" data-type="number"/> <xsl:sort select="substring(@sTime,4,2)" data-type="number"/> <xsl:sort select="substring-after(substring-after(@sTime,' '),' ')" /> <xsl:sort data-type="number" select= "translate( substring-before(substring-after(@sTime,' '),' '), ':', '' ) " /> <xsl:copy-of select="."/> </xsl:for-each> </sales> </xsl:template> </xsl:stylesheet>
将此转换应用于以下XML文档时 :
<sales> <item name="Games" sku="MIC28306200" iCat="28" sTime="11/26/2008 8:41:12 PM" price="1.00" desc="Item Name" /> <item name="Games" sku="MIC28307100" iCat="28" sTime="11/26/2008 8:42:12 AM" price="1.00" desc="Item Name" /> <item name="Games" sku="MIC28307100" iCat="28" sTime="11/26/2008 11:42:12 AM" price="1.00" desc="Item Name" /> <item name="Games" sku="MIC28306200" iCat="28" sTime="12/23/2008 8:41:12 PM" price="1.00" desc="Item Name" /> <item name="Games" sku="MIC28307100" iCat="28" sTime="12/23/2008 8:42:12 AM" price="1.00" desc="Item Name" /> </sales>
产生了正确的结果:
<sales> <item name="Games" sku="MIC28307100" iCat="28" sTime="11/26/2008 8:42:12 AM" price="1.00" desc="Item Name"/> <item name="Games" sku="MIC28307100" iCat="28" sTime="11/26/2008 11:42:12 AM" price="1.00" desc="Item Name"/> <item name="Games" sku="MIC28306200" iCat="28" sTime="11/26/2008 8:41:12 PM" price="1.00" desc="Item Name"/> <item name="Games" sku="MIC28307100" iCat="28" sTime="12/23/2008 8:42:12 AM" price="1.00" desc="Item Name"/> <item name="Games" sku="MIC28306200" iCat="28" sTime="12/23/2008 8:41:12 PM" price="1.00" desc="Item Name"/> </sales>
如果正确构造XML,那么您正在尝试做的事情会轻松完成。 XML Schema建议说日期/时间值应以ISO8601格式表示,即CCCC-MM-DD HH:MM:SS
。 (实际上,XML Schema希望日期和时间之间的分隔符为T,而目前我不记得为什么。)
以这种方式格式化日期和时间的两个主要优点是:
在XSLT处理的XML中以任何其他方式格式化日期是一种残酷。
使.NET以这种格式发出DateTime值很容易(使用“s”格式说明符,代表 - 等待它 - “可排序”)。
假设你的日期时间是这种格式
2010-06-01T15:16:29 + 05:00
那么最简单的方法就是
<xsl:sort select =“translate(XPATH_RETURNING_DATE,' - T:+','')”order =“descending”data-type =“number”/>
在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提供的示例
<sales>
<item name="Games" sku="MIC28306200" iCat="28"
sTime="11/26/2008 8:41:12 PM"
price="1.00" desc="Item Name" />
<item name="Games" sku="MIC28307100" iCat="28"
sTime="11/26/2008 8:42:12 AM"
price="1.00" desc="Item Name" />
<item name="Games" sku="MIC28307100" iCat="28"
sTime="11/26/2008 11:42:12 AM"
price="1.00" desc="Item Name" />
<item name="Games" sku="MIC28306200" iCat="28"
sTime="12/23/2008 8:41:12 PM"
price="1.00" desc="Item Name" />
<item name="Games" sku="MIC28307100" iCat="28"
sTime="12/23/2008 8:42:12 AM"
price="1.00" desc="Item Name" />
产量
<item name="Games" sku="MIC28307100" iCat="28" sTime="11/26/2008 8:42:12 AM" price="1.00" desc="Item Name" /><item name="Games" sku="MIC28307100" iCat="28" sTime="11/26/2008 11:42:12 AM" price="1.00" desc="Item Name" /><item name="Games" sku="MIC28306200" iCat="28" sTime="11/26/2008 8:41:12 PM" price="1.00" desc="Item Name" /><item name="Games" sku="MIC28307100" iCat="28" sTime="12/23/2008 8:42:12 AM" price="1.00" desc="Item Name" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.