首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > XML SOAP >

Xpath施用,从 Java 程序中查询 XML

2012-07-25 
Xpath使用,从 Java 程序中查询 XML?XPath在众多查询语言之中,结构化查询语言(SQL)是一种针对查询特定类型

Xpath使用,从 Java 程序中查询 XML

?

XPath

在众多查询语言之中,结构化查询语言(SQL)是一种针对查询特定类型的关系库而设计和优化的语言。其他不那么常见的查询语言还有对象查询语言(OQL)和 XQuery。但本文的主题是 XPath,一种为查询 XML 文档而设计的查询语言。比如,下面这个简单的 XPath 查询可以在文档中找到作者为 Neal Stephenson 的所有图书的标题:


一个简单的例子

我将举例说明如何使用它。然后再讨论一些细节问题。假设要查询一个图书列表,寻找 Neal Stephenson 的著作。具体来说,这个图书列表的形式如?清单 2?所示:


清单 2. 包含图书信息的 XML 文档

抽象工厂

XPathFactory?是一个抽象工厂。抽象工厂设计模式使得这一种 API 能够支持不同的对象模型,如 DOM、JDOM 和 XOM。为了选择不同的模型,需要向XPathFactory.newInstance()?方法传递标识对象模型的统一资源标识符(URI)。比如 http://xom.nu/ 可以选择 XOM。但实际上,到目前为止 DOM 是该 API 支持的惟一对象模型。

查找所有图书的 XPath 查询非常简单://book[author="Neal Stephenson"]。为了找出这些图书的标题,只要增加一步,表达式就变成了?//book[author="Neal Stephenson"]/title。最后,真正需要的是?title?元素的文本节点孩子。这就要求再增加一步,完整的表达式就是?//book[author="Neal Stephenson"]/title/text()

现在我提供一个简单的程序,它从 Java 语言中执行这个查询,然后把找到的所有图书的标题打印出来。首先,需要将文档加载到一个 DOMDocument?对象中。为了简化起见,假设该文档在当前工作目录的 books.xml 文件中。下面的简单代码片段解析文档并建立对应的Document?对象:


清单 3. 用 JAXP 解析文档

直接求值

如果 XPath 表达式只使用一次,可以跳过编译步骤直接对XPath?对象调用?evaluate()?方法。但是,如果同一个表达式要重复使用多次,编译可能更快一些。

最后,计算 XPath 表达式得到结果。表达式是针对特定的上下文节点计算的,在这个例子中是整个文档。还必须指定返回类型。这里要求返回一个节点集:

XPath 数据模型

每当混合使用诸如 XPath 和 Java 这样两种不同的语言时,必定会有某些将两者粘合在一起的明显接缝。并非一切都很合拍。XPath 和 Java 语言没有同样的类型系统。XPath 1.0 只有四种基本数据类型:

  • node-set
  • number
  • boolean
  • string

    当然,Java 语言有更多的数据类型,包括用户定义的对象类型。

    多数 XPath 表达式,特别是位置路径,都返回节点集。但是还有其他可能。比如,XPath 表达式?count(//book)?返回文档中的图书数量。XPath 表达式?count(//book[@author="Neal Stephenson"]) > 10?返回一个布尔值:如果文档中 Neal Stephenson 的著作超过 10 本则返回 true,否则返回 false。

    evaluate()?方法被声明为返回?Object。实际返回什么依赖于 XPath 表达式的结果以及要求的类型。一般来说,XPath 的

    • number 映射为?java.lang.Double
    • string 映射为?java.lang.String
    • boolean 映射为?java.lang.Boolean
    • node-set 映射为?org.w3c.dom.NodeList

      XPath 2

      前面一直假设您使用的是 XPath 1.0。XPath 2 大大扩展和修改了类型系统。Java XPath API 支持 XPath 2 所需的主要修改是为返回 XPath 2 新数据类型增加常量。

      在 Java 中计算 XPath 表达式时,第二个参数指定需要的返回类型。有五种可能,都在?javax.xml.xpath.XPathConstants?类中命名了常量:

      • XPathConstants.NODESET
      • XPathConstants.BOOLEAN
      • XPathConstants.NUMBER
      • XPathConstants.STRING
      • XPathConstants.NODE

        最后一个?XPathConstants.NODE?实际上没有匹配的 XPath 类型。只有知道 XPath 表达式只返回一个节点或者只需要一个节点时才使用它。如果 XPath 表达式返回了多个节点并且指定了?XPathConstants.NODE,则?evaluate()?按照文档顺序返回第一个节点。如果 XPath 表达式选择了一个空集并指定了?XPathConstants.NODE,则?evaluate()?返回 null。

        如果不能完成要求的转换,evaluate()?将抛出?XPathException


        名称空间上下文

        若 XML 文档中的元素在名称空间中,查询该文档的 XPath 表达式必须使用相同的名称空间。XPath 表达式不一定要使用相同的前缀,只需要名称空间 URI 相同即可。事实上,如果 XML 文档使用默认名称空间,那么尽管目标文档没有使用前缀,XPath 表达式也必须使用前缀。

        但是,Java 程序不是 XML 文档,因此不能用一般的名称空间解析。必须提供一个对象将前缀映射到名称空间 URI。该对象是javax.xml.namespace.NamespaceContext?接口的实例。比如,假设图书文档放在 http://www.example.com/books 名称空间中,如?清单 5?所示:


        清单 5. 使用默认名称空间的 XML 文档


        函数求解器

        有时候,在 Java 语言中定义用于 XPath 表达式的扩展函数很有用。这些函数可以执行用纯 XPath 很难或者无法执行的任务。不过必须是真正的函数,而不是随意的方法。就是说不能有副作用。(XPath 函数可以按照任意的顺序求值任意多次。)

        通过 Java XPath API 访问的扩展函数必须实现?javax.xml.xpath.XPathFunction?接口。这个接口只声明了一个方法 evaluate:

        ?

        结束语

        用 SQL 和 XPath 这样的声明性语言编写查询,要比使用 Java 和 C 这样的命令式语言容易得多。但是,用 Java 和 C 这样的图灵完整语言编写复杂的逻辑,又比 SQL 和 XPath 这样的声明性语言容易得多。所幸的是,通过使用 Java Database Connectivity (JDBC) 和javax.xml.xpath?之类的 API 可以将两者结合起来。随着世界上越来越多的数据转向 XML,javax.xml.xpath?将与?java.sql?一样变得越来越重要。

热点排行