使用 C# XmlDocument 选择相对 XPath 节点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/955979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:12:29  来源:igfitidea点击:

Relative XPath node selection with C# XmlDocument

c#xpathxmldocument

提问by

Imagine the following XML document:

想象一下以下 XML 文档:

<root>
    <person_data>
        <person>
            <name>John</name>
            <age>35</age>
        </person>
        <person>
            <name>Jim</name>
            <age>50</age>
        </person>
    </person_data>
    <locations>
        <location>
            <name>John</name>
            <country>USA</country>
        </location>
        <location>
            <name>Jim</name>
            <country>Japan</country>
        </location>
    </locations>
</root>

I then select the person node for Jim:

然后我为 Jim 选择 person 节点:

XmlNode personNode = doc.SelectSingleNode("//person[name = 'Jim']");

And now from this node with a single XPath select I would like to retrieve Jim's location node. Something like:

现在从这个带有单个 XPath 选择的节点中,我想检索 Jim 的位置节点。就像是:

XmlNode locationNode = personNode.SelectSingleNode("//location[name = {reference to personNode}/name]");

Since I am selecting based on the personNode it would be handy if I could reference it in the select. Is this possible?.. is the connection there?

由于我是根据 personNode 进行选择的,如果我可以在选择中引用它会很方便。这可能吗?..有联系吗?

Sure I could put in a few extra lines of code and put the name into a variable and use this in the XPath string but that is not what I am asking.

当然,我可以添加一些额外的代码行并将名称放入一个变量中,然后在 XPath 字符串中使用它,但这不是我要问的。

采纳答案by Tomalak

This is not very efficient, but it should work. The larger the file gets, the slower will this be.

这不是很有效,但它应该有效。文件越大,速度就越慢。

string xpath = "//location[name = //person[name='Jim']/name]";
XmlNode locationNode = doc.SelectSingleNode(xpath);

Here is why this is inefficient:

这就是效率低下的原因:

  • The "//" shorthand causes a document-wide scan of all nodes.
  • The "[]" predicate runs in a loop, once for each <person>matched by "//person".
  • The second "//" causes a causes a document-wide scan again, this time once for each <person>.
  • " //" 速记会导致对所有节点进行文档范围的扫描。
  • " []" 谓词在循环中运行,每次<person>与 " //person"匹配。
  • 第二个“ //”会导致再次进行文档范围的扫描,这次是每个<person>.

This means you get quadratic O(n2) worst-case performance, which is bad. If there are n <person>s and n <location>s in your document, n x n document wide scans happen. All out of one innocent looking XPath expression.

这意味着您将获得二次 O(n2) 最坏情况的性能,这很糟糕。如果您的文档中有 n <person>s 和 n <location>s,则会发生 nxn 文档宽扫描。完全出于一种看起来很无辜的 XPath 表达式。

I'd recommend against that approach. A two-step selection (first, find the person, then the location) will perform better.

我建议反对这种方法。两步选择(首先找到人,然后是位置)会表现得更好。

回答by Cerebrus

You are not selecting the locationnode based on the personnode, rather you are selecting it based on the valueof the node. The value is just a string and in this case, it can be used to formulate a predicate condition that selects the locationnode based on the value within ("Jim").

您不是location根据person节点选择节点,而是根据节点的选择它。该值只是一个字符串,在这种情况下,它可用于制定一个谓词条件,该条件location根据(“Jim”)中的值选择节点。

回答by aJ.

I am not very sure why you want refer location from personNode. Since, the name already exists in locationnode you can very well use the same to get the location node corresponding to 'Jim'.

我不太确定您为什么要从personNode. 由于该名称已存在于location节点中,因此您可以很好地使用它来获取与“Jim”对应的位置节点。

XPath would be: //location[name = 'Jim']

回答by Tomalak

XmlNode locationNode = personNode.SelectSingleNode(".."); 

Should do it.

应该做。

回答by Christian Hayter

I appreciate that your real XML document is more complex than your example, but one thing does strike me about it. It resembles a relational data store containing the following:

我很欣赏您真正的 XML 文档比您的示例更复杂,但有一件事确实让我印象深刻。它类似于包含以下内容的关系数据存储:

  • A persontable with two columns - nameand age.
  • A locationtable with two columns - nameand country.
  • A 1-1 relationship between the two tables joining on the two namecolumns.
  • 一个person包含两列的表 -nameage
  • 一个location包含两列的表 -namecountry
  • 连接两name列的两个表之间的 1-1 关系。

With that in mind, the XPath becomes obvious. You just select on the primary key value of the table whose data you want.

考虑到这一点,XPath 变得显而易见。您只需选择所需数据的表的主键值。

//location[name = 'Jim']

I know that aJ already proposed that solution, and it was rejected, but if you generalise the idea to the real XML schema, you get this:

我知道 aJ 已经提出了这个解决方案,但被拒绝了,但是如果你将这个想法推广到真正的 XML 模式,你会得到这个:

//real_2nd_table_name[real_2nd_pk_column_name_1 = real_1st_pk_column_value_1 and real_2nd_pk_column_name_2 = real_1st_pk_column_value_2 and real_2nd_pk_column_name_3 = real_1st_pk_column_value_3 ...]

In other words:

换句话说:

  1. You already know the PK values used to find the row in the first table.
  2. You know how the two tables are related.
  3. Therefore you should be able to work out how to express a PK query on the second table using the same values that you would have used to select the row in the first table.
  1. 您已经知道用于在第一个表中查找行的 PK 值。
  2. 你知道这两个表是如何相关的。
  3. 因此,您应该能够计算出如何使用与在第一个表中选择行时相同的值在第二个表上表达 PK 查询。