簡體   English   中英

基於DateTime屬性C#,XPath對XML節點進行排序

[英]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有一個重載,它接受一個I​​Comparer接口。 如果您自己將比較實現為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 );
                }
            }
        }

這是一個XSLT解決方案:

<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,而目前我不記得為什么。)

以這種方式格式化日期和時間的兩個主要優點是:

  • 這就是XML的其他用戶所期望的
  • 您可以對其字符串值進行排序。

在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM