【问题标题】:Sorting XML nodes based on DateTime attribute C#, XPath基于 DateTime 属性 C#、XPath 对 XML 节点进行排序
【发布时间】:2010-09-25 13:49:27
【问题描述】:

我有一个看起来像这样的 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 属性对节点进行排序,该属性是 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 节点进行排序,然后将所有属性放入适当的数组中以供以后使用。

    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++;

      }

【问题讨论】:

  • 你可以添加另一个属性,这是时间的可排序版本吗?刻度或 YYYYMMDD
  • 我正在使用 Web 服务,我打电话给管理员让他们将排序添加到存储过程中,但如果我无法获得它们,我必须尝试使用现有的 XML 格式找到解决方案。不过建议很好。
  • 所有这些答案都以不同的方式起作用。多谢你们。所有这些都很有用。
  • 为什么,除了简单的无知,还有人会编写一个 Web 服务来发出没有​​要符合的架构的 XML 吗?这就像编写一个 API,然后用便利贴记录它。

标签: c# xml sorting xpath


【解决方案1】:

给你:

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);
}

这是一个完美运行的控制台应用程序。

【讨论】:

  • 嗨@Timothy。您的代码似乎可以满足我的需求。你能帮我看看我之前在这里发的帖子吗:stackoverflow.com/questions/12943635/… 另外,我从来没有使用过 Linq,所以我不确定你的代码是否可以在我的 VB.NET 环境中运行。谢谢!
【解决方案2】:

有一个 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 );
                }
            }
        }

【讨论】:

  • 我试过了,但出现错误无法将类型 System.DateTime 转换为 System.Collections.IComparer
  • 另一个棘手的部分是我需要对节点进行排序而不仅仅是属性。
  • 查看代码。您需要选择要排序的节点(项目节点,而不是 sTime 属性),并使用表示排序键表达式(sTime 属性)的表达式以及自定义比较器。
【解决方案3】:

这是一个 XSLT 解决方案:

【讨论】:

    【解决方案4】:

    如果正确构造了 XML,那么您尝试做的事情会更容易完成。 XML Schema 建议指出日期/时间值应以 ISO8601 格式表示,即CCCC-MM-DD HH:MM:SS。 (实际上XML Schema希望日期和时间之间的分隔符是T,现在我不记得为什么了。)

    以这种方式格式化日期和时间的两个主要优点是:

    • 这正是其他 XML 用户所期望的,并且
    • 您可以对它们的字符串值进行排序。

    在将由 XSLT 处理的 XML 中以任何其他方式格式化日期是一种残忍行为。

    让 .NET 以这种格式发出 DateTime 值很容易(使用“s”格式说明符,它代表 - 等待它 - “可排序”)。

    【讨论】:

      【解决方案5】:

      假设你的日期时间是这种格式

      2010-06-01T15:16:29+05:00

      那么最简单的方法是

      在日期时间只需替换额外的字符 在我的日期时间格式中,我有多余的字符( - T : 和 + )所以只需替换它 然后您的日期时间将采用可以轻松排序的数字格式

      【讨论】:

        【解决方案6】:

        我知道这个问题很老了,你可能有一个解决方案,但我想分享我的答案:

              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" />
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多