`

XPath and Default Namespace handling

    博客分类:
  • XML
阅读更多

转自 http://wakan.blog.51cto.com/blog/59583/7220

原文 http://www.edankert.com/defaultnamespaces.html

 

 

诸如“为什么用 XPath 的表达式进行查询,却没有返回所期望的结果?” 的问题通常都与命名空间(NameSpace)有关,而且绝大多数是与缺省命名空间(Default Namespace)有关。本文试图解释这个问题并针对三种流行的 XPath 实现给出解决方法:Jaxen、JAXP XPPathFactory 以及 XSLT。

内容列表

  • 问题描述
  • “前缀-命名空间”映射
  • Jaxen 和 Dom4J
  • Jaxen 和 XOM
  • Jaxen 和 JDOM
  • JAXP XPathFactory
  • XSLT
  • 结束语
  • 资源

问题描述

看下述 XML:
<catalog>
  <cd>
    <artist>Sufjan Stevens</artist>
    <title>Illinois</title>
  </cd>
  <cd>
    <artist>Stoat</artist>
    <title>Future come and get me</title>
  </cd>
  <cd>
    <artist>The White Stripes</artist>
    <title>Get behind me satan</title>
  </cd>
</catalog>
    你可以使用“//cd”来得到没有在任何命名空间中定义的“cd”节点。 
    现在让我们来改造这个 XML,让它的所有元素都属于 'http://www.edankert.com/examples/' 命名空间中。
 
    为了避免在每个不同的元素前都要加个前缀,我们在根元素上定义通常所说的缺省命名空间。改造后的 XML 如下:
 
<catalog xmlns="http://www.edankert.com/examples/">
  <cd>
    <artist>Sufjan Stevens</artist>
    <title>Illinois</title>
  </cd>
  <cd>
    <artist>Stoat</artist>
    <title>Future come and get me</title>
  </cd>
  <cd>
    <artist>The White Stripes</artist>
    <title>Get behind me satan</title>
  </cd>
</catalog>
    当我们使用与上文相同的 XPath “//cd”,将得不到任何元素。这是因为指定的 XPath 返回的是所有不属于任何命名空间的“cd”节点,而本例中,所有的“cd”元素都属于缺省的命名空间“[url]http://www.edankert.com/examples/[/url]”。

“前缀-命名空间”映射

    为了取出命名空间“[url]http://www.edankert.com/examples/[/url]”中的所有“cd”元素,我们需要对 XPath 表达式做一些额外的工作。
 
    为了解决这个问题,XPath 规范允许我们使用 QName 来指定元素或者属性。QName 可以是元素的直接名称(形如“element”),或者包含一个前缀(形如“pre:element”)。这个前缀需要映射到一个命名空间的 URI 上。例如,如果把“pre”前缀映射到“[url]http://www.edankert.com/test[/url]”上,则通过“pre:element”可以查找出属于命名空间“[url]http://www.edankert.com/test[/url]”的所有 “element”元素。
 
    在本例中,我们把“edx”映射到“'http://www.edankert.com/examples/”命名空间上。通过 XPath“//edx:cd”就可以查找出属于“'http://www.edankert.com/examples/”命名空间的所有“cd”元素。 
 
    XPath 处理器允许设置“前缀-命名空间”的映射,但是,如何去映射,却要依赖于具体的实现。下文举例说明 Jaxen (JDOM/dom4j/XOM)、JAXP 以及 XSLT 中是如何进行“前缀-命名空间”的映射的。

Jaxen 和 Dom4J

    下述代码从文件系统读入一个 XML 文件到 org.dom4j.Document 对象中,并且在 Document 中查找属于“[url]http://www.edankert.com/examples/[/url]”命名空间的所有“cd”元素。
 
try {
 
SAXReader reader = new SAXReader();
  Document document = reader.read( "file:catalog.xml");
 
 
HashMap map = new HashMap();
  map.put( "edx", "http://www.edankert.com/examples/");
 
  XPath xpath = new Dom4jXPath( "//edx:cd");
  xpath.setNamespaceContext( new
SimpleNamespaceContext( map));
 
 
List nodes = xpath.selectNodes( document);
 
  ...
 
} catch (
JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( DocumentException e) {
  // the document is not well-formed.
  ...
}
    第一步,创建一个 SAXReader,用来从文件系统中读取“catalog.xml”并创建一个特定于 Dom4j 的 Document 对象。
    第二步,对于所有 Jaxen 实现都一样,就是创建一个 HashMap 对象,用于保存“前缀-命名空间的 URI”的映射。
 
    为了能通过 Dom4j 使用 Jaxen 的 XPath 功能,需要创建一个与 Dom4j 相关的 XPath 对象:Dom4jXPath。创建方法是把 XPath 的表达式(即“//edx:cd”)传给 Dom4jXPath 的构造方法。
 
    现在,我们已经创建了 XPath 对象,接下来可以把“前缀-命名空间”的映射表传递给 XPath 引擎:把这个 HashMap 映射表用 SimpleNamespaceContext 包装起来。SimpleNamespaceContext 是 Jaxen 的 NamespaceContext 接口的默认实现类。
 
    最后一步就是调用 XPath 对象的 selectNodes() 方法进行查找。并把完整的 Dom4j  Document 对象作为参数传递进去。实际上,Document 中的任何结点都可以作为参数。

Jaxen 和 XOM

    XOM 是基于简单的 Java DOM APIs 之上的最新工具,它的设计初衷是提供简单和易学易用的接口。
 
try {
 
Builder builder = new Builder();
  Document document = builder.build( "file:catalog.xml");
 
 
HashMap map = new HashMap();
  map.put( "edx", "http://www.edankert.com/examples/");
 
  XPath xpath = new XOMXPath( "//edx:cd");
  xpath.setNamespaceContext( new
SimpleNamespaceContext( map));
 
 
List nodes = xpath.selectNodes( document);
 
  ...
 
} catch (
JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( IOException e) {
  // An error occurred opening the document
  ...
} catch ( ParsingException e) {
  // An error occurred parsing the document
  ...
}
 
    我们需要创建一个 Builder 对象,从文件系统中读取“catalog.xml”文件,并创建出与 XOM 相关的 Document 对象。
 
    下一步创建出包含了“前缀-命名空间”映射关系的 HashMap 对象。
 
    我们需要创建一个特定于 XOM 的 XPath 对象:XOMXPath。创建方法是把 XPath 表达式传递给构造方法,然后就可以通过 XOM 使用 Jaxen 的 XPath 功能了。
 
    创建完 XPath 对象后,同样,我们把“前缀-命名空间”的映射表用 SimpleNamespaceContext 对象封装后,传递给 XPath 引擎。
 
    最后调用 XPath 对象的“selectNodes()”方法进行查找,把 XOM Document 对象作为本方法的参数。

Jaxen 和 JDOM

    JDOM 是第一个提供简单的 XML 访问 API 的工具。 
 
try {
 
SAXBuilder builder = new SAXBuilder();
  Document document = builder.build( "file:catalog.xml");
 
 
HashMap map = new HashMap();
  map.put( "edx", "http://www.edankert.com/examples/");
 
  XPath xpath = new JDOMXPath( "//edx:cd");
  xpath.setNamespaceContext( new
SimpleNamespaceContext( map));
 
 
List nodes = xpath.selectNodes( document);
 
  ...
 
} catch (
JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( IOException e) {
  // An error occurred opening the document
  ...
} catch ( JDOMException e) {
  // An error occurred parsing the document
  ...
}
 
    首先,通过 SAXBuilder 创建了一个特定于 JDom 的 Document 对象。
 
    接着创建一个特定于 JDOM 的 XPath 对象:JDOMXPath
 
    然后,把“前缀-命名空间”的映射表(HashMap)用 SimpleNamespaceContext 对象封装起来,传递给 XPath 引擎。
 
    最后调用 XPath 对象的“selectNodes()”方法来进行查找,并把 JDOM 的 Document 对象作为本方法的输入参数。

JAXP XPathFactory

    从 1.3 版起, JAXP 还提供了一种在 XML Object Models 上进行查询的通用机制。 
 
try {
 
DocumentBuilderFactory domFactory =DocumentBuilderFactory.newInstance();
  domFactory.setNamespaceAware( true);
 
 
DocumentBuilder builder = domFactory.newDocumentBuilder();Document document = builder.parse( new InputSource( "file:catalog.xml"));
 
 
XPathFactory factory =XPathFactory.newInstance();
 
XPath xpath = factory.newXPath();
  xpath.setNamespaceContext( new
NamespaceContext() {
    public
String getNamespaceURI(String prefix) {
      if ( prefix.equals( "edx")) {
        return "http://www.edankert.com/examples/";
      } else if ...
        ...
      }
     
      return
XPathConstants.NULL_NS_URI;
    }
 
    public
String getPrefix(String namespaceURI) {
      if ( namespaceURI.equals( "http://www.edankert.com/examples/")) {
        return "edx";
      } else if ...
        ...
      } 
   
      return null;
    }
 
    public
Iterator getPrefixes(String namespaceURI) {
     
ArrayList list = new ArrayList();
   
      if ( namespaceURI.equals( "http://www.edankert.com/examples/")) {
        list.add( "edx");
      } else if ...
        ...
      }
   
      return list.iterator();
    }
  });
 
 
Object nodes = xpath.evaluate( "//edx:cd", document.getDocumentElement(),
                                
XPathConstants.NODESET);
 
  ...
 
} catch (
ParserConfigurationException e) {
  ...
} catch (
XPathExpressionException e) {
  ...
} catch (
SAXException e) {
  ...
} catch (
IOException e) {
  ...
}
    首先用 JAXP 的 DocumentBuilderFactory 创建一个org.w3c.dom.Document 对象,确保启用了 namespace 处理功能。
 
    现在可以通过 XPathFactory 来创建 XPath 对象,并通过 XPath 对象对文档进行查询。
 
    为了创建“前缀-命名空间”映射并传递给 XPath 引擎,我们需要实现 NamespaceContext 接口,该接口目前还没有默认实现类。这就意味着要实现 getNamespaceURI、getPrefix 和getPrefixes 方法,并确保这些方法能返回正确的值,包括“xmlns”和“xml”前缀所对应的命名空间的 URI 值。
 
    把我们自己实现的 NamespaceContext 对象传递给 XPath 引擎后,就可以通过 evaluate 方法来查询 XPath 表达式所对应的元素:使用上文中提到的 XPath 表达式,并使用 Document 的根节点作为输入入参数,并接收一个 NodeList 对象作为返回结果。

XSLT

    XPath 设计的初衷是用于 XSLT。这也许能解释“为什么在 XSLT 中定义命名空间的前缀是一件很平常的事”(也许因为 XSLT 也是一个 XML 名词的缘故吧)。 
 
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="//edx:cd" xmlns:edx="http://www.edankert.com/examples/">
    <xsl:apply-templates/>
  </xsl:template>
</xsl:stylesheet>
 
    只需要使用 XML 本身的机制,简单地为 edx 前缀赋予一个命名空间的 URI 值。
 
    通过与我们的 XPath 表达式“//edx:cd”相匹配的 xsl:template,能得到与上文其他例子相同的输出结果。

结束语

    为了在(缺省)命名空间上使用 XPath 表达式,我们需要指定一个“前缀-命名空间”映射。正如我们所看到的,具体使用什么样的前缀名称,是无关紧要的。
 
    同样的方法,也可以用于查询那些用其他前缀修饰的元素。这意味着上面的例子对下述 XML 也有效。下述 XML 没有使用缺省命名空间,而是使用了 examples 作命名空间的前缀: 
 
<examples:catalog xmlns:examples="http://www.edankert.com/examples/">
  <examples:cd>
    <examples:artist>Sufjan Stevens</examples:artist>
    <examples:title>Illinois</examples:title>
    <examples:src>
[url]http://www.sufjan.com/</[/url]examples:src>
  </examples:cd>
  <examples:cd>
    <examples:artist>Stoat</examples:artist>
    <examples:title>Future come and get me</examples:title>
    <examples:src>
[url]http://www.stoatmusic.com/</[/url]examples:src>
  </examples:cd>
  <examples:cd>
    <examples:artist>The White Stripes</examples:artist>
    <examples:title>Get behind me satan</examples:title>
    <examples:src>
[url]http://www.whitestripes.com/</[/url]examples:src>
  </examples:cd>
</examples:catalog>
 
    使用“//edx:cd”作为 XPath 表达式,使用与前文例子相同的“前缀-命名空间”映射,在这个 XML 上同样能查询出属于“[url]http://www.edankert.com/examples/[/url]”命名空间的所有“cd”元素。

资源

分享到:
评论

相关推荐

    XPath and XSLT

    在学习XPath和XSLT时,"Beginning XSLT and XPath"这样的资源是非常有价值的。这本书可能会涵盖以下内容: 1. XPath基础:路径表达式、节点类型、轴、函数库等。 2. XSLT结构:模板规则、模式匹配、变量和参数、...

    Beginning XSLT and XPath: Transforming XML Documents and Data

    Ian Williams presents a clear, concise resource on XSLT concepts and methods and explains how and why XSLT relies on the XML Path language (XPath).As you gain a solid foundation in XSLT processing,...

    Xpath指南XPATH实例

    - **节点类型**:XPath处理的节点包括元素(Element)、属性(Attribute)、文本(Text)、命名空间(Namespace)、处理指令(Processing Instruction)、注释(Comment)和文档(Document)节点。 - **路径表达式...

    Xpath生成器,自动生成XPATH,C#版

    XPath(XML Path Language)是一种在XML文档中查找信息的语言,它是W3C组织制定的一种标准查询语言,用于选取XML文档中的节点,包括元素、属性、文本等。在本项目“Xpath生成器,自动生成XPATH,C#版”中,开发者...

    从XML文件抽出XPath - C and C++

    总结起来,"从XML文件抽出XPath - C and C++"涉及的知识点主要包括: 1. XML的基本概念:元素、属性、文本等。 2. XPath的用途和基本语法:选取XML文档中的特定节点。 3. C++中的TinyXML库:解析XML,遍历DOM,实现...

    XPath依赖Jar包

    1. 节点类型:XPath识别元素(element)、属性(attribute)、文本(text)、命名空间(namespace)、处理指令(processing-instruction)和注释(comment)等六种基本节点类型。 2. 路径表达式:路径表达式是XPath...

    XPath教程

    =、&lt;、&gt;、、&gt;=)、逻辑运算符(and、or)、算术运算符(+、-、*、/、div、mod)等。函数则涵盖字符串、数字、节点集和布尔值的处理,如concat()用于连接字符串,number()用于转换节点为数字,contains()检测字符串...

    Xpath

    1. **节点类型**:XPath支持元素(element)、属性(attribute)、文本(text)、命名空间(namespace)、处理指令(processing-instruction)和注释(comment)六种基本节点类型。 2. **轴(Axis)**:轴定义了...

    IE下获取XPATH小工具源码_xpath_

    XPath,全称XML Path Language,是一种在XML文档中查找信息的语言。它被设计用来选取XML文档中的节点,如元素、属性、文本等。在IE浏览器下,为了方便开发者获取XML或HTML文档中的XPath路径,存在一种小工具,本文将...

    XPathHelper_2.0.2_xpath_

    3. **动态选取**:XPath支持逻辑运算符(and、or、not)以及比较运算符(=、!=、&lt;、&gt;等),使得我们可以根据元素的值或属性进行复杂的选择,如 `//a[./@href='http://example.com']` 选取链接地址为'...

    谷歌浏览器XPath2.0插件

    XPath(XML Path Language)是一种在XML文档中查找信息的语言,它允许我们通过路径表达式来选取节点,比如元素、属性和文本等。XPath 2.0是XPath的第二个主要版本,增加了更多的功能和优化。 在没有XPath Helper的...

    英文原版-XPath XLink XPointer and XML 1st Edition

    However, the introduction of XML, along with a sequence of related technologies such as XPath, XLink, and XPointer, has heralded a substantial change in the way in which content can be managed....

    xpath-helper.zip

    本压缩包文件"xpath-helper.crx"很可能是一个Chrome浏览器的扩展程序,旨在提供实时的XPath查询支持。 XPath(XML Path Language)是一种在XML文档中查找信息的语言,它允许我们通过路径表达式来选取节点,如元素、...

    dom4j和xpath必备jar包

    5. **短路逻辑**:XPath中的“and”和“or”操作符支持短路逻辑,可以避免不必要的计算。 DOM4J和XPath结合使用,可以实现高效的XML处理。例如,通过DOM4J解析XML文档,然后使用XPath表达式来快速定位到特定的元素...

    XPathHelper_2.0.2.zip

    XPathHelper_2.0.2.zip 是一个包含XPath Helper Chrome扩展程序的压缩文件,版本为2.0.2。XPath Helper是一款非常实用的工具,它专为Chrome浏览器设计,帮助开发者和网页爬虫工程师高效地测试和调试XPath表达式。...

    xpath-helper 插件及使用方法

    XPath Helper是一款强大的Chrome浏览器插件,专为网页元素定位和数据提取而设计。它使得开发者和数据抓取者能够方便地生成和测试XPath表达式,从而高效地在HTML文档中定位所需信息。XPath(XML Path Language)是一...

    xPath(简单教程)

    XPath还支持数值比较、字符串操作和逻辑运算,例如 `price&gt;10 and price是一个逻辑表达式,选取价格在10到20之间的节点。此外,XPath内置了多个函数,如 `count()` 计算节点个数,`string()` 获取节点的字符串值,`...

    xpath定位,xpath定位,xpath定位

    Selenium xpath,

    火狐老版本+xpath插件(适合python+xpath爬虫使用)

    火狐老版本与XPath插件的组合在Python网络爬虫领域具有重要的应用价值。XPath是一种在XML文档中查找信息的语言,对于数据提取和解析尤其有效。在这个压缩包中,我们找到了火狐的老版本浏览器和一个专门针对XPath的...

    XPath Helper 2.0.2网页插件

    9. **逻辑运算符**:`and` 和 `or` 用于组合多个条件,例如 `//input[@type='text' and @name='username']` 选取所有type为'text'且name为'username'的输入元素。 XPath Helper 2.0.2 插件将这些功能直观地集成到...

Global site tag (gtag.js) - Google Analytics