【问题标题】:XPath find all matches C# XmlDocumentXPath 查找所有匹配 C# XmlDocument
【发布时间】:2012-02-23 15:57:42
【问题描述】:

我正在尝试找出如何在 XmlDocument 中找到所有匹配的字符串。

XmlNodeList results 
      = document.SelectNodes("Products/Product/fn:matches(.,'" + SearchWord + "')");

我正在尝试比较 Product 的 innerText

虽然上面的例子不起作用,但我想我使用 XPath 函数的方式非常错误。

【问题讨论】:

标签: c# xpath xmldocument


【解决方案1】:

评估此 XPath 1.0 表达式(您知道吗matches() 是 XPath 2.0 函数,在 .NET 中不受支持):

Products/Product/descendant::*[contains(text(), 'YourSearchWord')]

这将选择所有具有包含字符串 'YourSearchWord' 的 text-node-child 的元素,并且这些元素是 Product 元素的后代,Products 元素是当前 (上下文)节点。

您可以使用来编写 XPath 表达式:

string.Format("Products/Product/descendant::*[contains(text(), '{0}')]", 
              SearchWord )

但是,如果SearchWord是从用户输入中获得的,建议不要像上面那样将它包含在骨架字符串中,这样可以避免XPath注入。

如果是这种情况,推荐的方法是使用预编译的 XPath 表达式,其中用户输入将作为变量引用,并且该变量的值将从 XPath 评估上下文中使用。

有关如何防止 XPath 注入的更多详细信息,请参阅此答案

https://stackoverflow.com/a/6393690/36305

【讨论】:

  • 这就解释了为什么使用匹配对我来说永远不起作用。我将在今天晚些时候尝试您的代码示例,看起来这就是我需要的!我会在几个小时内通知你。非常感谢
  • 嗨 Dimitre,我刚刚测试了 XPath,但它失败了,因为 'Products/Product/descendant::*[contains(text(), 'ra']' has an invalid token. 我需要对其进行任何更改以便在 C# XmlDocument 上下文中工作?
  • @user750508:是的,缺少右括号——应该是:/Product/descendant::*[contains(text(), 'ra')]
  • @user750508:我修正了答案中的错字——现在试试吧。
  • 这是处理 xPath 注入问题的 +1。
【解决方案2】:

假设你有以下 xml

<Names>
    <Name>
        <FirstName>John</FirstName>
        <LastName>Smith</LastName>
    </Name>
    <Name>
        <FirstName>James</FirstName>
        <LastName>White</LastName>
    </Name>
</Names>

要获取所有节点,请使用 XPath 表达式 /Names/Name。第一个斜线表示该节点必须是根节点。 SelectNodes 方法返回将包含节点的集合 XmlNodeList。要获取子节点的值,您可以简单地使用节点名称索引 XmlNode:xmlNode["FirstName"].InnerText.

XmlDocument xml = new XmlDocument();
xml.LoadXml(myXmlString); // suppose that myXmlString contains "<Names>...</Names>"

XmlNodeList xnList = xml.SelectNodes("/Names/Name");
foreach (XmlNode xn in xnList)
{
  string firstName = xn["FirstName"].InnerText;
  string lastName = xn["LastName"].InnerText;
  Console.WriteLine("Name: {0} {1}", firstName, lastName);
}

输出是:

姓名:约翰·史密斯 姓名:詹姆斯·怀特

以此为例子/起点。谢谢

【讨论】:

  • 有没有办法直接在SelectNodes调用中做?
  • 我要做的基本上是获取与搜索查询匹配的所有产品,但我不想浏览所有产品。我希望 XPath 为我处理它
  • +1。虽然使用 XPath 完成所有事情都很有趣,但您最好使用 XPath 和其他 DJ 建议的代码过滤来完成简单的部分。 IE。原始问题包含“XPath injection”错误(类似于“SQL injection”),即如果 SearchWord 包含双引号,您的 XPath 将分崩离析。
  • @AlexeiLevenkov:避免 XPath 注入并仍然构造和评估单个 XPath 表达式的方法是使用预编译的 XPath 表达式,其中用户输入将作为变量引用,并且该变量的值将从 XPath 评估上下文中使用。
【解决方案3】:

如果我正确理解您的问题,您可以使用以下内容:

"Products/Product/[.='" + SearchWord + "']"

或使用contains()starts-with()normalize-space()等函数(修剪并用一个空格替换连续的空白)

"Products/Product/[contains(normalize-space(.), '" + SearchWord + "')]"

【讨论】:

    【解决方案4】:

    来自this duplicate question的回复:

    给定的表达式计算为布尔值,而不是节点集。我假设 您想检查 ProjectName 是否等于参数化的 文本。在这种情况下,您需要编写

    //ErrorTable/ProjectName[text()='{0}']
    

    这会为您提供与给定匹配的所有节点(节点集)的列表 健康)状况。此列表可能为空,在这种情况下,C#-Expression 中的 您的示例将返回 null。

    事后考虑:您可以使用原始的 xpath 表达式,但是 不是使用 SelectSingleNode,而是使用 Evaluate,如下所示:

    (bool)xmlDocument.CreateNavigator().Evaluate(String.Format("//ErrorTable/ProjectName/text()='{0}'", projectName));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-31
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 2012-05-30
      相关资源
      最近更新 更多