如何使用多个 XPath 查询在 c# 中选择单个 XML 节点

Posted

技术标签:

【中文标题】如何使用多个 XPath 查询在 c# 中选择单个 XML 节点【英文标题】:How to select a single XML node in c# using multiple XPath queries 【发布时间】:2021-01-05 05:14:07 【问题描述】:

我正在尝试根据两个查询从 XML 文件中选择一个节点,我有一个产品 ID,我需要它的最新条目 - 最高问题编号。

这是我的 XML 文件的格式:

<MyProducts>  
  <Product code="1011234">
    <ProductName>Product Name A</ProductName>
    <ProductId>101</ProductId>
    <IssueNumber>1234</IssueNumber>
  </Product>
  <Product code="1029999">
    <ProductName>Product Name B</ProductName>
    <ProductId>102</ProductId>
    <IssueNumber>9999</IssueNumber>
  </Product>
  <Product code="1015678">
    <ProductName>Product Name A2</ProductName>
    <ProductId>101</ProductId>
    <IssueNumber>5678</IssueNumber>
  </Product>
</MyProducts>

我需要从具有最高 IssueNumber 的 ProductId 中获取 &lt;product&gt; 节点。例如,如果 ProductId 是 101,我想要第三个节点,如果是 102,我想要第二个节点。该文件中有大约 50 种不同的产品,分为三个不同的产品 ID。

我已经尝试了许多使用 SelectSingleNode 的 XPath 组合,方法是使用特定的 ProductID 和 IssueNumber 节点,或者使用产品节点的 code 属性(它是 Id 和 Issue 的组合),但均未成功。 该代码当前使用 code 属性,但这只是因为我们还传递了问题编号,我希望能够在没有问题编号的情况下执行此操作(以减少前端维护),因为它始终是我们想要的最高问题。 当前代码是这样的:

XmlNode productNode = productXml.SelectSingleNode("/MyProducts/Product[@code='" + productCode + "']");

我也使用过这些,它们有点用,但是选择内部节点,而不是外部 Product 节点:

XmlNodeList productNodes = productXml.SelectNodes("/MyProducts/Product/ProductId[text()='101']");
XmlNodeList productNodes = productXml.SelectNodes("/MyProducts/Product[not (../Product/IssueNumber > IssueNumber)]/IssueNumber");

我想将两者结合使用,如下所示:

XmlNode productNode = productXml.SelectSingleNode("/MyProducts/Product/ProductId[text()='101'] and /MyProducts/Product[not (../Product/IssueNumber > IssueNumber)]/IssueNumber");

但这会返回错误“...引发了类型为 'System.Xml.XPath.XPathException' 的异常”,但我也希望它不会返回 Product 节点。 这甚至可以在一行中完成,还是我必须遍历节点才能找到正确的节点?

【问题讨论】:

【参考方案1】:

使用 Xml Linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication167

    class Program
    
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        
            XDocument doc = XDocument.Load(FILENAME);

            var products = doc.Descendants("Product")
                .OrderByDescending(x => (int)x.Element("IssueNumber"))
                .GroupBy(x => (int)x.Element("ProductId"))
                .Select(x => x.First())
                .ToList();

            Dictionary<int, XElement> dict = products
                .GroupBy(x => (int)x.Element("ProductId"), y => y)
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            XElement highestId = dict[101];

        
    


 

【讨论】:

【参考方案2】:

你的最后一个想法几乎就在那里。您需要将两个子句 放入 [] 选择器中。还有max() 可用,我认为它阐明了逻辑。这应该有效:

/MyProducts/Product[ProductId='101'
   and IssueNumber=max(/MyProducts/Product[ProductId='101']/IssueNumber)]

这会选择Product,其中两个 的 id 为 101 并且 在所有 id-101 产品中具有最高的 IssueNumber。

【讨论】:

以上是关于如何使用多个 XPath 查询在 c# 中选择单个 XML 节点的主要内容,如果未能解决你的问题,请参考以下文章

更新与 Xpath 查询匹配的多个 XML 节点 C#

如何通过oracle在c#中使用多个选择查询

使用 XPath 和 WebBrowser 控件选择多个节点

无论特定 Id 如何,如何使用 XPath 选择类别 XML 节点?

如何在单个过程中编写多个选择查询?

如何在 C# 中使用 XPath 包含