XPathNavigator 如何尊重相对上下文?

How does XPathNavigator respect relative context?

简介:

如果我 运行 内部 XPath 查询,我得到与外部 XPath 查询的上下文无关的文本节点 (先前接收的节点)。这是否意味着 XPathNavigator 始终有整个树可用,因此它不考虑当前上下文?这是否意味着查询总是在根目录下执行?请看下面的例子:

这是book.xml的例子:

<bookstore>
  <book genre="autobiography" publicationdate="1981-03-22" ISBN="1-861003-11-0">  
    <title>The Autobiography of Benjamin Franklin</title>  
    <author>  
      <first-name>Benjamin</first-name>  
      <last-name>Franklin</last-name>  
    </author>  
    <price>8.99</price>  
  </book>  
  <book genre="novel" publicationdate="1967-11-17" ISBN="0-201-63361-2">  
    <title>The Confidence Man</title>  
    <author>  
      <first-name>Herman</first-name>  
      <last-name>Melville</last-name>  
    </author>  
    <price>11.99</price>  
  </book>  
  <book genre="philosophy" publicationdate="1991-02-15" ISBN="1-861001-57-6">  
    <title>The Gorgias</title>  
    <author>  
      <name>Plato</name>  
    </author>  
    <price>9.99</price>  
  </book>  
</bookstore>

XPath 查询:

I would expect that If I run the second query (inner one) in the context of the first one, I would not get any results. However I was wrong.

测试代码:

var xpath1 = "/bookstore/book/title";
var xpath2 = "/bookstore/book/author/first-name/text()";

var xDocument = new XPathDocument(new StreamReader("./book.xml"));
var navigator = xDocument.CreateNavigator();
navigator.MoveToChild(XPathNodeType.Element);
    
var iterator = navigator.Select(xpath1) as XPathNodeIterator;
while (iterator?.MoveNext() ?? false)
{
    var result = iterator.Current.Evaluate(xpath2) as XPathNodeIterator;
    while (result?.MoveNext() ?? false)
    {
        Console.WriteLine(result.Current.Value);
    }
}

我得到的结果:

xpath1 returns 3个节点,resp.迭代器有 3 个元素,因为 <title> 显然在 XML 文档中出现了三次。然后我希望后续查询 xpath2 将 return 没有数据,因为我在 <title> 节点的上下文中。然而,似乎并非如此。在输出中我得到了 Benjamin Herman.

的 3 倍

问题:

How did I get <first-name> text values in the results even though I ran the query in the context of the <title> node? Does it mean that XPathNavigator always performs over the entire tree?

不,XPathNavigator 不会采用绝对 XPath,例如

/bookstore/book/author/first-name/text()

并相对应用。如果要在上下文节点为 title 时达到 author 等,则使用

../author/first-name/text()

following-sibling::author/first-name/text()

我更喜欢 xml linq :

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


namespace ConsoleApplication11
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            var results = doc.Descendants("book")
                .Where(x => (string)x.Element("title") == "The Autobiography of Benjamin Franklin")
                .Select(x => new
                {
                    author_first_name = (string)x.Descendants("first-name").FirstOrDefault(),
                    author_last_name = (string)x.Descendants("last-name").FirstOrDefault(),
                    price = (decimal)x.Element("price"),
                    genre = (string)x.Attribute("genre"),
                    publication = (DateTime)x.Attribute("publicationdate"),
                    isbn = (string)x.Attribute("ISBN")
                }).ToList();
          
        }
  
    }
    //------------------------------------------------------------------------------
 
}