XPath等效于current()

时间:2017-02-03 20:34:26

标签: xml xpath

如何在XPath中引用评估XPath的节点?

E.g:

<Root>
    <Foo>
        <Bar><Elem>X</Elem><Ref>1</Ref></Bar>
        <Bar><Elem>Y</Elem><Ref>2</Ref></Bar>
        <Ref>2</Ref>
    </Foo>

在Node = /Root/Foo/Ref上执行XPath:

var myNode = GetNodeRootFooRef();
var xpath = "../Bar[Ref=.]/Elem";
myNode.SelectSingleNode(xpath); // does not work, see below

不幸的是,条件中的.引用Bar元素而不是我执行XPath的原始Ref节点。如何在XPath中引用原始上下文节点?

4 个答案:

答案 0 :(得分:4)

您需要至少XPath 2.0才能使用单个纯XPath表达式来解决它:for $current in . return ../Bar[Ref=$current]/Elem

Microsoft没有XPath 2.0支持,但有第三方XPath 2实现插入现有的.NET体系结构并提供扩展方法,例如, XmlNode(需要using Wmhelp.XPath2;和NuGet包https://www.nuget.org/packages/XPath2/1.0.2/):

            string xml = @"<Root>
    <Foo>
        <Bar><Elem>X</Elem><Ref>1</Ref></Bar>
        <Bar><Elem>Y</Elem><Ref>2</Ref></Bar>
        <Ref>2</Ref>
    </Foo>
</Root>";
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);

            XmlNode refEl = doc.SelectSingleNode("/Root/Foo/Ref");

            XmlNode elem = refEl.XPath2SelectSingleNode("for $current in . return ../Bar[Ref=$current]/Elem");

            Console.WriteLine(elem.OuterXml);

或者您可以使用XPath 3.0或更高版本,使用let绑定变量let $c := . return ../Bar[Ref=$c]/Elem的单个纯XPath表达式。

如果你想在.NET框架中的System.Xml上使用它,那么你可以安装和使用XmlPrime,它提供了扩展方法(http://www.xmlprime.com/xmlprime/doc/4.0/using-xpath.htm#extension):

            string xml = @"<Root>
    <Foo>
        <Bar><Elem>X</Elem><Ref>1</Ref></Bar>
        <Bar><Elem>Y</Elem><Ref>2</Ref></Bar>
        <Ref>2</Ref>
    </Foo>
</Root>";
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);

            XmlNode refEl = doc.SelectSingleNode("/Root/Foo/Ref");

            XmlNode elem = refEl.XPathSelectSingleNode("let $c := . return ../Bar[Ref=$c]/Elem");

            Console.WriteLine(elem.OuterXml);

输出<Elem>Y</Elem>

如果你想在.NET框架XPath API中拥有可变分辨率,那么SelectSingleNode/SelectNodes的第二个参数是XmlNamespaceManager,它是XsltContext的基类,它有一个方法{ {1}} https://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltcontext.resolvevariable(v=vs.110).aspx。有project on CodeplexResolveVariable中实现了XsltContext的可变分辨率,因此您可以使用它:

public class DynamicContext : XsltContext

请参阅https://weblogs.asp.net/cazzu/30888中的文档。

答案 1 :(得分:2)

如果您正在使用XPath 1.0,那么您最好的选择是绑定变量,如下所示,具体取决于您的API:

var myNode = GetNodeRootFooRef();
var xpath = "../Bar[Ref=$current]/Elem";
XPath x = new XPath():
x.bindVariable("current", myNode);
x.evaluate(xpath, myNode);

但是你已经达到了XPath 1.0的极限,所以现在是时候向前迈进了。 .NET上提供了各种非常好的XPath 2.0和3.0引擎。

答案 2 :(得分:1)

如果Foo元素的结构始终相同,那么以下查询就足够了:

../Bar[Ref=(../Ref)]/Elem

(试过http://xpather.com/vjXDytGy - 这个xpath在线测试人员支持XPath 2.0)

我希望它也适用于XPath 1.0。

答案 3 :(得分:0)

../Bar[Ref=/Root/Foo/Ref]/Elem

.更改为原始xpath