使用 XPath 导航选择节点

发布时间 2023-11-09 17:07:25作者: 不及格的程序员-八神
 

使用 XPath 导航选择节点

 

本文内容

  1. XPath 选择方法
  2. XPath 表达式中的命名空间
  3. 请参阅

XML 文档对象模型 (DOM) 包含的方法使您可以使用 XML 路径语言 (XPath) 浏览功能查询 DOM 中的信息。 可以使用 XPath 查找单个特定节点,或查找与某个条件匹配的所有节点。

XPath 选择方法

DOM 类提供两种 XPath 选择方法:SelectSingleNode 方法和 SelectNodes 方法。 SelectSingleNode 方法返回符合选择条件的第一个节点。 SelectNodes 方法返回包含匹配节点的 XmlNodeList

下面的示例使用 SelectSingleNode 方法来选择其作者姓氏符合指定条件的第一个 book 节点。 bookstore.xml 文件(在本主题末尾提供)用作输入文件。

C#
// Load the document and set the root element.  
XmlDocument doc = new XmlDocument();  
doc.Load("bookstore.xml");  
XmlNode root = doc.DocumentElement;  
  
// Add the namespace.  
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);  
nsmgr.AddNamespace("bk", "urn:newbooks-schema");  
  
// Select and display the first node in which the author's
// last name is Kingsolver.  
XmlNode node = root.SelectSingleNode(  
    "descendant::bk:book[bk:author/bk:last-name='Kingsolver']", nsmgr);  
Console.WriteLine(node.InnerXml);  

下一个示例使用 SelectNodes 方法来选择其价格大于指定金额的所有书节点。 然后,以编程方式将选定列表中的每本书的价格减去 10%。 最后,将更新的文件写入控制台。 bookstore.xml 文件(在本主题末尾提供)用作输入文件。

C#
// Load the document and set the root element.  
XmlDocument doc = new XmlDocument();  
doc.Load("bookstore.xml");  
XmlNode root = doc.DocumentElement;  
  
// Add the namespace.  
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);  
nsmgr.AddNamespace("bk", "urn:newbooks-schema");  
  
// Select all nodes where the book price is greater than 10.00.  
XmlNodeList nodeList = root.SelectNodes(  
     "descendant::bk:book[bk:price>10.00]", nsmgr);  
foreach (XmlNode book in nodeList)  
{  
     // Discount prices by 10%.  
     double price;  
     price = Math.Round(Convert.ToSingle(  
          book.LastChild.InnerText) * 0.9, 2);  
     book.LastChild.InnerText = price.ToString();  
}  
  
// Display the updated document.  
doc.Save(Console.Out);  

上面的示例从文档元素开始执行 XPath 查询。 设置 XPath 查询的起始点即设置了上下文节点,该节点是 XPath 查询的起始点。 如果不希望在文档元素处开始,而是希望从文档元素的第一个子级开始,可以编写 Select 语句的代码,如下所示:

C#
this doc.DocumentElement.FirstChild.SelectNodes(. . .);  

所有 XmlNodeList 对象都与基础文档同步。 因此,如果循环访问节点列表并修改某个节点的值,则该节点在包含它的文档中也被更新。 请注意,在上一个示例中,在选定的 XmlNodeList 中修改节点时,也会修改基础文档。

 备注

修改基础文档时,最好重新运行此 Select 语句。 如果修改的节点可能导致该节点被添加到节点列表(当先前没有添加它时),或者现在会导致它从节点列表中被移除,则无法保证节点列表现在是精确的。

XPath 表达式中的命名空间

XPath 表达式可以包含命名空间。 使用 XmlNamespaceManager 支持命名空间解析。 如果 XPath 表达式包含前缀,前缀和命名空间 URI 对必须添加到 XmlNamespaceManager,并且 XmlNamespaceManager 传递给 SelectNodes(String, XmlNamespaceManager) 或 SelectSingleNode(String, XmlNamespaceManager) 方法。 请注意,上面的代码示例使用 XmlNamespaceManager 来解析 bookstore.xml 文档的命名空间。

 备注

如果 XPath 表达式不包含前缀,则假定命名空间统一资源标识符 (URI) 是空的命名空间。 如果 XML 包含默认命名空间,仍必须将前缀和命名空间 URI 添加到 XmlNamespaceManager;否则,不会选择任何节点。

输入文件

下面的 bookstore.xml 文件在本主题的示例中用作输入文件。

XML
<?xml version='1.0'?>  
<bookstore xmlns="urn:newbooks-schema">  
  <book genre="novel" style="hardcover">  
    <title>The Handmaid's Tale</title>  
    <author>  
      <first-name>Margaret</first-name>  
      <last-name>Atwood</last-name>  
    </author>  
    <price>19.95</price>  
  </book>  
  <book genre="novel" style="other">  
    <title>The Poisonwood Bible</title>  
    <author>  
      <first-name>Barbara</first-name>  
      <last-name>Kingsolver</last-name>  
    </author>  
    <price>11.99</price>  
  </book>  
  <book genre="novel" style="paperback">  
    <title>The Bean Trees</title>  
    <author>  
      <first-name>Barbara</first-name>  
      <last-name>Kingsolver</last-name>  
    </author>  
    <price>5.99</price>  
  </book>  
</bookstore>  

请参阅


 

XPath 查询和命名空间

 

本文内容

  1. XmlNamespaceManager
  2. 请参阅

XPath 查询支持 XML 文档中的命名空间,可以使用命名空间前缀来限定元素和属性的名称。 使用命名空间前缀来限定元素和属性的名称可以限制 XPath 查询只返回属于特定命名空间的节点。

例如,如果前缀 books 映射到命名空间 http://www.contoso.com/books,以下 XPath 查询 /books:books/books:book 将只选择命名空间 book 中的 http://www.contoso.com/books 元素。

XmlNamespaceManager

要在 XPath 查询中使用命名空间,构造一个从 IXmlNamespaceResolver 接口派生的对象(例如 XmlNamespaceManager 类),包含要加入 XPath 查询的命名空间 URI 和前缀。

XmlNamespaceManager 对象可以通过下列任意方式在查询中使用。

以下是 XPathNavigator 类中接受从 IXmlNamespaceResolver 接口派生的对象作为参数的方法。

默认命名空间

在下面的 XML 文档中,具有空前缀的默认命名空间用于声明 http://www.contoso.com/books 命名空间。

XML
<books xmlns="http://www.contoso.com/books">  
    <book>  
        <title>Title</title>  
        <author>Author Name</author>  
        <price>5.50</price>  
    </book>  
</books>  

XPath 将空前缀作为 null 命名空间对待。 也就是说,XPath 查询中只能使用映射到命名空间上的前缀。 这意味着如果要针对 XML 文档中的某个命名空间进行查询,即使是默认的命名空间,也需要为其定义前缀。

例如,在没有为上面的 XML 文档定义前缀的情况下,XPath 查询 /books/book 不会返回任何结果。

必须绑定前缀,这样,如果查询的文档中有些节点在某个命名空间,有些节点在默认命名空间,可以避免混淆情况。

以下代码为默认命名空间定义前缀,并选择 book 命名空间中的所有 http://www.contoso.com/books 元素。

C#
XPathDocument document = new XPathDocument("books.xml");  
XPathNavigator navigator = document.CreateNavigator();  
XPathExpression query = navigator.Compile("/books:books/books:book");  
XmlNamespaceManager manager = new XmlNamespaceManager(navigator.NameTable);  
manager.AddNamespace("books", "http://www.contoso.com/books");  
query.SetContext(manager);  
XPathNodeIterator nodes = navigator.Select(query);  

请参阅


XPath 命名空间浏览

 

本文内容

  1. 命名空间声明
  2. 通过命名空间前缀进行浏览
  3. 请参阅

要对 XML 文档使用 XPath 查询,必须正确定位 XML 命名空间以及命名空间中包含的元素。 命名空间可防止在多个上下文中使用名称时可能产生的混淆情况;例如,名称 ID 可能引用与 XML 文档的不同元素相关联的多个标识符。 命名空间语法指定了 URI、名称和前缀,可区分 XML 文档的各个元素。

本主题中的示例演示了通过 XPathNavigator 在浏览 XML 文档时使用前缀。 有关命名空间和语法的详细信息,请参阅 XML 文件:了解 XML 命名空间

命名空间声明

命名空间声明使得在使用 XPathNavigator 的实例时,很容易区分和定位 XML 文档的各个元素。 命名空间前缀提供了一种简化的语法,用来定位命名空间。

前缀由以下形式定义:<e:Envelope xmlns:e=http://schemas.xmlsoap.org/soap/envelope/>. 在此语法中,前缀“e”是命名空间的正式 URI 的缩写。 使用此语法可以将 Body 元素标识为 Envelope 命名空间的成员:e:Body

在下一节的浏览示例中,下面的 XML 文档将用作 response.xml

XML
<?xml version="1.0" encoding="utf-8" ?>  
<e:Envelope xmlns:e="http://schemas.xmlsoap.org/soap/envelope/">  
  <e:Body>  
    <s:Search xmlns:s="http://schemas.microsoft.com/v1/Search">  
      <r:request xmlns:r="http://schemas.microsoft.com/v1/Search/metadata"
                 xmlns:i="http://www.w3.org/2001/XMLSchema-instance">  
      </r:request>  
    </s:Search>  
  </e:Body>  
</e:Envelope>  

本节中的代码使用 XPathNavigator 和 XmlNamespaceManager 对象,从前一节的 XML 文档中选择 Search 元素。 查询 xpath 对路径中的每个元素都包含了命名空间前缀。 指定包含每个元素的命名空间的精确标识,可确保通过 Search 方法正确浏览至 SelectSingleNode 元素。

C#
using (XmlReader reader = XmlReader.Create("response.xml"))  
{  
    XPathDocument doc = new XPathDocument(reader);  
    XPathNavigator nav = doc.CreateNavigator();
  
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(nav.NameTable);  
    nsmgr.AddNamespace("e", @"http://schemas.xmlsoap.org/soap/envelope/");  
    nsmgr.AddNamespace("s", @"http://schemas.microsoft.com/v1/Search");  
    nsmgr.AddNamespace("r", @"http://schemas.microsoft.com/v1/Search/metadata");  
    nsmgr.AddNamespace("i", @"http://www.w3.org/2001/XMLSchema-instance");  
  
    string xpath = "/e:Envelope/e:Body/s:Search";  
  
    XPathNavigator element = nav.SelectSingleNode(xpath, nsmgr);  
  
    Console.WriteLine("Element Prefix:" + element.Prefix +
    " Local name:" + element.LocalName);  
    Console.WriteLine("Namespace URI: " + element.NamespaceURI);  
}  

完全限定的命名空间和名称的精确度不仅仅是一种方便。 对前面的示例中的文档定义和代码进行一项小实验,可以验证如果不使用完全限定的元素名称进行浏览,就会引发异常。 例如,元素定义为 <Search xmlns="http://schemas.microsoft.com/v1/Search">,而查询字符串 xpath = "/s:Envelope/s:Body/Search"; 没有对 Search 元素使用命名空间前缀,则此查询将返回 null,而不是 Search 元素。

请参阅