2017-02-03 46 views
0

如何引用XPath在XPath中進行評估的節點?在節點= /Root/Foo/Ref執行等效於當前XPath的XPath()

例如爲:

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

的XPath:

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

不幸的是,在條件引用.Bar元件,而不是原來Ref節點在其上予執行中的XPath。如何從XPath內引用原始上下文節點?

+0

你需要輸出什麼? –

回答

4

您至少需要XPath 2.0才能使用單個純XPath表達式來解決此問題:for $current in . return ../Bar[Ref=$current]/Elem

Microsoft不支持XPath 2.0,但有第三方XPath 2實現插入到現有的.NET體系結構中,並在例如Web服務器上提供擴展方法。 XmlNode(需要using Wmhelp.XPath2;和NuGet包https://www.nuget.org/packages/XPath2/1.0.2/):let $c := . return ../Bar[Ref=$c]/Elem

  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到可變結合單一,純XPath表達式做到這一點。

如果你想使用上的System.Xml在.NET框架,那麼你可以例如安裝和使用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/SelectNodesXmlNamespaceManager這是一個基類的XsltContext其中有一個方法ResolveVariablehttps://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltcontext.resolvevariable(v=vs.110).aspx。有project on Codeplex實現該XsltContextpublic class DynamicContext : XsltContext可變分辨率,所以你可以使用:

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

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

      DynamicContext context = new DynamicContext(); 
      context.AddVariable("current", refEl); 

      XmlNode elem = refEl.SelectSingleNode("../Bar[Ref = $current]/Elem", context); 

      Console.WriteLine(elem.OuterXml); 

查看文檔中https://weblogs.asp.net/cazzu/30888

+0

我正在使用.NET 4.6.2框架的'System.Xml'組件 - 是否有任何替代方案與該庫的支持XPath標準兼容? –

+0

感謝您的指點,upvoted你的答案!不能接受它,因爲它不能幫助我的(開源)項目......買不起這樣一個庫。非常感謝您的支持! –

+0

至於用'SelectSingleNode'做,它具有服用的XmlNamespaceManager過載https://msdn.microsoft.com/en-us/library/h0hw012b(v=vs.110).aspx,這是一個基類的https://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltcontext(v=vs.110).aspx您可以擴展和實現以提供您的功能和/或可變分辨率像'current()'或'$ current'那樣工作。然而,這是相當大的努力。 –

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

變化.到初始的XPath

+0

只能正確工作,如果這是唯一的 –

2

如果你正在使用XPath 1.0,那麼你最好的選擇可能是綁定變量,像下面的東西,這取決於你的API:

但是您已經達到了XPath 1.0的限制,所以現在是時候繼續前進了。 .NET上有各種完美的XPath 2.0和3.0引擎。

+0

新的XPath()不能在.NET中使用System.Xml - >你知道他們是否有某種支持變量綁定的API嗎?我找不到一個... –

+0

不,我不能。相當根本性的遺漏 - 也許人們在這些API定義的黑暗時期並不擔心注入攻擊。 –

+0

@ D.R。正如我在回答中的評論中所說的那樣,API是(隱藏的)XmlNamespaceManager的參數,它是XsltContext的基類,它允許可變的解析/綁定。如果您需要使用https://weblogs.asp.net/cazzu/30888和https://mvpxml.codeplex.com/releases/view/4894項目的源代碼,它會執行一個'公共類DynamicContext:XsltContext'。 –

1

如果foo元素的結構始終是相同的,則下面的查詢應該足夠了:

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

(試過http://xpather.com/vjXDytGy - 此XPath在線測試儀支持XPath 2。0)

我希望它XPath 1.0中工作過。