<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Heck's  Blog]]></title> 
<link>https://www.heckjj.com/index.php</link> 
<description><![CDATA[一瞬间的决定，往往可以改变很多，事实上，让自己成功的往往不是知识，是精神！ 如果你总是为自己找借口，那只好让成功推迟。执行力，今天！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Heck's  Blog]]></copyright>
<item>
<link>https://www.heckjj.com/java-calc-xpath-xml/</link>
<title><![CDATA[从Java 平台计算XPath]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[编程杂谈]]></category>
<pubDate>Tue, 21 Sep 2010 06:04:30 +0000</pubDate> 
<guid>https://www.heckjj.com/java-calc-xpath-xml/</guid> 
<description>
<![CDATA[ 
	<span style="font-family: 微软雅黑;">分组 XML 技术<br/><br/>很多年前，当 XML 成为最热门的技术之一时，很难想象得到 XML 会在十年内变得如此重要，而且您可以找到大量与 XML 相关的有趣技术。实际上，可以通过多种途径了解 XML 技术。<br/><br/><span style="font-size: 12px;"><strong>传统的 XML 分组</strong></span><br/><br/>可以将与 XML 相关的技术划分为一些基本的分组或主要区域：<br/><br/>&nbsp;&nbsp; <strong>1. 文档创作：</strong>此分组面向将主要的时间用于创作 XML 的人。无论他们是创建原始 XML 数据，还是用 XML 格式表示现有数据，这里主要关注的都是纯 XML，很少关注可能使用这些文档的编程任务。这就是 XML 的核心思想所在，这个分组还包括特定的 XML 词汇表（比如 MathML）或一些科学 XML 词汇表。<br/>&nbsp;&nbsp; <strong>2. 处理 XML：</strong>这些技术（比如 XSL）允许对 XML 进行转换、修改或由一种格式迁移到另一种格式。这些技术主要关注的仍然是 XML 文档及其内部数据，但有时候也使用编程语言来完成这些转换。<br/>&nbsp;&nbsp; <strong>3. 读取/编写 XML（以及持久化数据）：</strong>这些技术与编程联系更加紧密，包括从低级的 API（比如 SAX 和 DOM）到数据处理技术（比如 JAXB 和 Castor）。这些技术将 XML 看作一种数据存储机制，而且在许多情形下看作一种达到目的的手段。<br/><br/>到目前为止，这些分组是主要的技术类别，每个分组中都在不断出现最新的技术和规范。<br/><br/><strong>将 XML 转变为一类数据居民</strong><br/><br/>XML 的一个主要问题就是缺乏良好的搜索支持，尽管这个问题仅限于上面的三个分组。如果想要对 XML 格式的数据进行搜索，则这会是一个问题。实际上，通常的解决方案是将上面的一些分组结合起来。文档创作者可能使用命令行工具（比如 grep，这是一种笨拙的搜索方式。编程人员可能读入 XML（另一个分组），然后使用他们的编程语言（比如 Java 或 C#）对非 XML 格式的数据进行搜索。这种方法是可行的，但暴露了 XML 的一些局限性。<br/><br/>幸运的是，XPath（和 XQuery，本文稍后将会谈到）的引入和流行带来了一个新分组：<br/><br/>&nbsp;&nbsp; <strong>4. 搜索 XML：</strong>XPath 和 XQuery 就属于这个分组。这些规范/技术允许以 XML 的方式对 XML 文档进行搜索。换句话说，可以使用 XML 语义进行搜索，并且不但能够搜索 XML 文档中的数据，还能够搜索这些文档的结构。<br/><br/>借助 XPath 和 XQuery，不再需要将数据由 XML 转换为一种编程语言，然后使用这种语言的工具来搜索数据。使用这种方法不仅会受到编程语言的约束，通常还会丢失大多数 XML 语义和结构（比如元素之间的父子关系等等）。使用 XPath 和 XQuery，无需编程语言 就可以对 XML 进行搜索。</span><span style="font-family: 微软雅黑;"><br/><br/>尽管如此，仍然需要使用 Java（和其他）语言进行编程并与 XPath 和 XQuery 交互。尽管 XPath 和 XQuery 具有强大的 XML 搜索功能，编程人员仍然需要一种方式来使用这些技术。使用系统命令（比如 exec()）来启动命令行进程是个很痛苦的过程，而且会引起您无法处理的错误。更糟的是，几乎不能对搜索结果进行处理。因此 XPath 必须与 Java（或 C# 或 Perl）语言结合起来。本文使用的是 Java 语言。（如果您想看看关于其他语言的文章，请在本文反馈部分中告诉我们！）<br/><br/>要阅读本文，至少应该熟悉 XPath。如果从未使用过此技术，请参阅 参考资料 中的链接，学习一个包含两部分的介绍性 XPath 教程，然后再阅读本文。<br/><br/>在这一点上（XPath 和 Java 技术的结合），Sun 为 Java 编程人员提供了很大帮助。Java 编程人员将 XPath 支持集成到了 Java 5 环境中。更好的是，您无需下载企业版本或者补充的程序包（比如 Sun 用来处理 JDBC 的某些部分的程序包）。如果计算机上已经安装了 Java 5 软件，那么您已经通过专注于 Java 的方式获得了对 XPath 的支持。实际上，您可能已经熟悉了 JAXP（Java API for XML Processing）的某些部分。<br/><br/><strong><span style="font-size: 14px;">确保已经获得了 Java 5 发行版</span></strong><br/><br/>如果您不能确定拥有的是哪个版本的 Java 技术，或者计算机（可能是远程服务器）上运行的是哪个版本的 Java 技术，那么您可以轻松地找出来。只需使用 -version 标志运行 java。清单 1 显示了应该看到的结果。<br/><br/><br/><span style="font-size: 14px;"><strong>清单 1. 确保已经获得了 Java 5 或更高版本</strong></span><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>[bdm0509:~/Documents/developerworks/java_xpath] java -version<br/>java version "1.5.0_13"<br/>Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05-237)<br/>Java HotSpot(TM) Client VM (build 1.5.0_13-119, mixed mode, sharing)<br/><br/>只要版本是 1.5 或更高版本，您就能够顺利完成本文。注意，1.5 相当于 5.0，（我和大多数 Java 开发人员）都不太明白为什么所有公开著作上都称之为 “Java 5”，但是上面的 java 命令仍然会返回 1.5。如果您拥有 1.5.x 或者甚至是 1.6.x，那就再好不过了 。否则，请访问 参考资料 中的链接，下载 Java 5 技术。<br/><br/><span style="font-size: 14px;"><strong>确保获得了 XPath 支持</strong></span><br/><br/>接下来，需要确保拥有 XPath 支持。这听起来有点多余；不就是检查一下是否获得了 Java 5 或更高版本的软件吗？尽管如此，仍然有很多开发人员在其系统上使用的 Java 版本与其开发环境所使用的版本不一样。或者 Eclipse（您的 IDE）运行的不是 Web 应用服务器等等……避免此类问题的最好方法是构建一个小程序来对软件进行测试。清单 2 展示了一个程序，该程序仅仅创建 XPath 工厂的一个新实例 XPathFactory。这也可以确保解析器和一个实现已经设置并能够运行。<br/><br/><br/><span style="font-size: 14px;"><strong>清单 2. 一个非常简单的 XPath 测试类</strong></span></span><br/><br/><textarea name="code" class="java" rows="15" cols="100">import javax.xml.xpath.XPathFactory;

public class XPathTester &#123;

&nbsp;&nbsp;public static void main(String args[]) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathFactory factory = XPathFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("Uh oh...looks like you don't have the version " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"of JAXP with XPath support. Better upgrade to Java 5 or greater.");
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Successfully loaded XPath factory. Things look good.");
&nbsp;&nbsp;&#125;
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">编译这个类并运行它。您应该会获得如清单 3 所示的非常基本的输出。<br/><br/><br/><span style="font-size: 14px;"><strong>清单 3. 清单 2 中的测试类的成功输出</strong></span><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>[bdm0509:~/Documents/developerworks/java_xpath] java XPathTester<br/>Successfully loaded XPath factory. Things look good.<br/><br/>这非常繁琐，但是您可以尝试在 Web 服务器、应用服务器、镜像生产服务器等想要运行 XPath 代码的地方使用它。如果这个类能够在这些机器上运行，那么您就能够安全地开发更加复杂的 XPath 应用程序。如果测试类不能运行，那么请在编写代码之前花点时间获得 XPath 支持，否则编写的代码可能不会正常运行。<br/><br/> <br/><br/>XPath API 概述<br/><br/>理解 JAXP API 的 XPath 部分完全在于理解 JAXP 如何处理所有 的 XML 解析、处理和转换。<br/><br/><span style="font-size: 14px;"><strong>基础的 JAXP 工作流</strong></span><br/><br/>以下是处理 XML 的基本步骤：<br/><br/>&nbsp;&nbsp; 1. 获得一个工厂类，以提供特定于供应商的 JAXP 实现的一个实例。<br/>&nbsp;&nbsp; 2. 从工厂获得一个解析器或转换器。<br/>&nbsp;&nbsp; 3. 设置关于这个解析器或转换器的配置选项（验证、名称空间感知、要使用的样式表等等）。<br/>&nbsp;&nbsp; 4. 创建一个对象来持有、存储或引用要操作的 XML（通常通过一些类型的 InputSource 来实现）。<br/>&nbsp;&nbsp; 5. 解析或转换 XML。<br/><br/>这些代码通常与清单 4 类似，其中展示了一个简单的 XML 解析，使用命令行参数作为要解析的 XML 文档的文件名。<br/><br/><br/><span style="font-size: 14px;"><strong>清单 4. 使用 SAXParserFactory</strong></span></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="java" rows="15" cols="100">import java.io.OutputStreamWriter;
import java.io.Writer;

// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

// SAX
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class TestSAXParsing &#123;
&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.length != 1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println ("Usage: java TestSAXParsing [filename]");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit (1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Get SAX Parser Factory
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAXParserFactory factory = SAXParserFactory.newInstance();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Turn on validation, and turn off namespaces
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;factory.setValidating(true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;factory.setNamespaceAware(false);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAXParser parser = factory.newSAXParser();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parser.parse(new File(args[0]), new MyHandler());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (ParserConfigurationException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("The underlying parser does not support " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " the requested features.");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (FactoryConfigurationError e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Error occurred obtaining SAX Parser Factory.");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;

class MyHandler extends DefaultHandler &#123;

&nbsp;&nbsp;&nbsp;&nbsp;// SAX callback implementations from ContentHandler, ErrorHandler, etc.
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">如果构建一个 DOM 树，构建过程仍然遵循相同的模型。清单 5 展示了创建 XML 文档的 DOM 树的代码，步骤与清单 4 非常相似，但其中的类和方法名称发生了变化。<br/><br/><span style="font-size: 14px;"><strong>清单 5. 使用文档构建器工厂</strong></span></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="java" rows="15" cols="100">import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;

// DOM
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestDOMParsing &#123;

&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.length != 1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println ("Usage: java TestDOMParsing " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"[filename]");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit (1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Get Document Builder Factory
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory factory = 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory.newInstance();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Turn on validation, and turn off namespaces
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;factory.setValidating(true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;factory.setNamespaceAware(false);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilder builder = factory.newDocumentBuilder();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Document doc = builder.parse(new File(args[0]));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Print the document from the DOM tree and
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp; feed it an initial indentation of nothing
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printNode(doc, "");

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (ParserConfigurationException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("The underlying parser does not " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "support the requested features.");

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (FactoryConfigurationError e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Error occurred obtaining Document " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Builder Factory.");

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;private static void printNode(Node node, String indent)&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// print the DOM tree
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">在两种情形中，您都获得一个工厂，并用其创建一个新的解析器/处理器实例，然后在该实例上进行操作。<br/><br/><span style="font-size: 14px;"><strong>XPath 工作流</strong></span><br/><br/>该工作流与您编写 XPath 代码时的流程非常相似：<br/><br/>&nbsp;&nbsp; 1. 获得一个 XPath 工厂，以提供特定于供应商的 XPath 实例的一个实现。<br/>&nbsp;&nbsp; 2. 从工厂获得一个 XPath 计算器实例。<br/>&nbsp;&nbsp; 3. 创建一个新的 XPath 表达式。（虽然这一步仍然与 XML 转换模型中的样式表分配保持一致，但它与解析模型不同）。<br/>&nbsp;&nbsp; 4. 构建 XML 文档的一个 DOM 树，用于计算 XPath 表达式。<br/>&nbsp;&nbsp; 5. 计算 XPath 表达式。<br/><br/>让我们逐步研究一下这个过程，构建一个基本的程序来解析 XPath 表达式，然后可以计算您自己的任何 XPath 或在学习 XPath 教程（参见 参考资料 获得其链接）过程中编写的任何 XPath。<br/><br/>为 XPath 提供一个 DOM 树<br/><br/>您需要记住用于本文将要构建的程序的一些假设：<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;* <span style="font-size: 14px;"><strong>您有一个 XML 文档，而且可以轻松将其转换为 DOM 树。</strong></span>本文的示例从命令行读入一个 XML 文档，并将其转换为一个 DOM 树，但是您可以从网络 URL、一组 SAX 事件或任何其他来源轻松构建一个 DOM 树。如果您对如何使用 JAXP 从各种来源构建 DOM 树有些陌生，那么请访问 参考资料 中的一些有帮助的链接。<br/>&nbsp;&nbsp;&nbsp;&nbsp;* <span style="font-size: 14px;"><strong>需要计算 XPath。</strong></span> 本文假设您已经有一个 XPath，或者至少知道如何构建一个 XPath。本文不会详细讨论如何构建 XPath，而主要讨论如何计算它们。<br/><br/>满足这些假设之后，您就可以编写代码了。<br/><br/><span style="font-size: 14px;"><strong>获得一个要针对其计算 XPath 的 XML 文档</strong></span><br/><br/>首先从一个简单的程序开始，该程序从命令行读入一个文件名。您将使用该名称从它引用的 XML 文档构建一个 DOM 树。此处的内容并不是特定于 XPath 或者甚至 JAXP 的；只是一些简单的 I/O 和程序片段。清单 6 是最初的程序；将其保存为 XPathEvaluator.java。<br/><br/><span style="font-size: 14px;"><strong>清单 6. 计算 XPath 的程序的最初版本</strong></span></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="java" rows="15" cols="100">package ibm.dw.xpath;

public class XPathEvaluator &#123;

&nbsp;&nbsp;public XPathEvaluator(String xmlFilename) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;// Convert filename into a DOM tree
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public void evaluateXPath(String xpathString) &#123;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public static void main(String[] args) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.length != 1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("Usage: java ibm.dw.xpath.XPathEvaluator " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"[XML filename]");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathEvaluator evaluator = new XPathEvaluator(args[0]);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;"><span style="font-size: 14px;"><strong>将 XML 转换为 DOM 树</strong></span><br/><br/>XPath API（至少其当前的 JAXP 形式）需要由 DOM 树来操作。所有 XPath 都需要由某种类型的内存中模型来操作，因为 XPath 基本上与 XML 文档的层次结构相关。DOM 提供了一个这样的模型，一个可导航的元素、属性和文本节点树。<br/><br/>因为您已经使用 JAXP 来提供 XPath 支持，所以您也免费获得了 DOM 支持。使用 DocumentBuilder 类（及其相关联的工厂 DocumentBuilderFactory），以将字符串引用转换为一个内存中 DOM 树。清单 7 展示了用于实现此目的的 XPathEvaluator 类的附加部分。<br/><br/><span style="font-size: 14px;"><strong>清单 7. 从输入 XML 文档创建 DOM 树</strong></span></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="java" rows="15" cols="100">package ibm.dw.xpath;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class XPathEvaluator &#123;

&nbsp;&nbsp;private Document domTree = null;

&nbsp;&nbsp;public XPathEvaluator(String xmlFilename) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Convert filename into a DOM tree
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory domFactory =
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilder builder = domFactory.newDocumentBuilder();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.domTree = builder.parse(xmlFilename);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (SAXException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error in document parsing: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (ParserConfigurationException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error in configuring parser: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public void evaluateXPath(String xpathString) &#123;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public static void main(String[] args) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.length != 1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("Usage: java ibm.dw.xpath.XPathEvaluator " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"[XML filename]");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathEvaluator evaluator = new XPathEvaluator(args[0]);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">大多数代码仅仅是基于 DOM 的 JAXP 解析；如果您还不太明白此处发生了什么，请参见 参考资料 获取关于一般的 JAXP 解析和转换的文章的链接。<br/><br/><span style="font-size: 14px;"><strong>关于名称空间感知的注意事项</strong></span><br/><br/>正如大多数现代的和目前的 XML 规范所描述的，XPath 是名称空间感知的。这意味着元素的名称空间前缀（比如 iTunes:artist）可以作为 XPath 的一部分。即使您未 使用具有名称空间的文档，您也应该确保今后会拥有这种功能。<br/><br/>为此，您必须确保 DOM 树是名称空间感知的。换句话讲，您应该确保 XPath 计算的输入 是名称空间感知的，从而使您的计算也具有名称空间感知特性。要确保这一点，应该在构建 DOM 树时始终打开名称空间感知。清单 8 展示了为了实现此目的而新增的一行代码。<br/><br/><span style="font-size: 14px;"><strong>清单 8. 将名称空间感知添加到 DOM 树的构建过程中</strong></span></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="java" rows="15" cols="100">package ibm.dw.xpath;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class XPathEvaluator &#123;

&nbsp;&nbsp;private Document domTree = null;

&nbsp;&nbsp;public XPathEvaluator(String xmlFilename) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Convert filename into a DOM tree
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory domFactory =
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;domFactory.setNamespaceAware(true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilder builder = domFactory.newDocumentBuilder();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.domTree = builder.parse(xmlFilename);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (SAXException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error in document parsing: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (ParserConfigurationException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error in configuring parser: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public void evaluateXPath(String xpathString) &#123;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public static void main(String[] args) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.length != 1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("Usage: java ibm.dw.xpath.XPathEvaluator " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"[XML filename]");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathEvaluator evaluator = new XPathEvaluator(args[0]);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;"><span style="font-size: 14px;"><strong>在 Java 环境中表示 XPath</strong></span><br/><br/>一旦拥有了要计算的 DOM 树，就需要获得 XPath（一个文本字符串）并为其创建一个 Java 表示。当然，这不仅仅意味着创建一个 String 变量并将 XPath 填充到其中。您需要一个实际的 Java 对象，它必须能够针对 DOM 树计算其本身，要么能够被其他某个 XPath 感知的组件计算。JAXP 的新 API 附加功能正好能在这里派上用场。<br/><br/><span style="font-size: 14px;"><strong>开始使用 XPath 工厂</strong></span><br/><br/>前面提到的事件序列将在这里登上舞台。从一个新类 javax.xml.xpath.XPathFactory 开始所有的 XPath 工作。但获取 DOM 除外，从技术上讲，这可以在实际的 XPath 计算之前的任何时刻完成。<br/><br/>具体来讲，XPathFactory 是一个接口，您需要该接口的一个实现。这个实现将特定于供应商；Sun 提供了一个默认实现，Apache 可能有一个实现，Oracle 可能也有一个实现……但所有这些代码都与供应商密切相关。但是，您可以使用 XPathFactory 及其 newInstance() 方法（该方法为您获取一个 XPathFactory 实现）对供应商细节进行抽象。<br/><br/>清单 9 主要实现这个目的。注意，这个清单仅仅 展示了 evaluateXPath() 方法。您将需要将一些 import 语句添加到代码中来使其生效，需要添加的所有代码都位于 javax.xml.xpath 包中。<br/><br/><br/><span style="font-size: 14px;"><strong>清单 9. 获取一个 XPathFactory 实例</strong></span></span><br/><textarea name="code" class="java" rows="15" cols="100">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;public void evaluateXPath(String xpathString) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;XPathFactory factory = XPathFactory.newInstance();
&nbsp;&nbsp;&#125;
</textarea><br/><span style="font-family: 微软雅黑;">获取一个 XPath 对象<br/><br/>接下来，您需要一个 XPath 对象。这个对象能够计算 XPath，并且是 XPath 感知的 Java 程序的基础。就像从 DocumentBuilderFactory 中获得一个 DocumentBuilder 一样，您从 XPathFactory 获得一个 XPath。清单 10 展示了这段代码。<br/><br/><br/><span style="font-size: 14px;"><strong>清单 10. 获取一个 XPath 对象</strong></span></span><br/><textarea name="code" class="java" rows="15" cols="100">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;public void evaluateXPath(String xpathString) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;XPathFactory factory = XPathFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;XPath xpath = factory.newXPath();
&nbsp;&nbsp;&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">有了这个类，您就可以计算 XPath 并处理结果了。<br/><br/><span style="font-size: 14px;"><strong>计算 XPath 表达式</strong></span><br/><br/>一旦有了一个 XPath 实例，您就可以计算 XPath，获取一个结果节点集并对结果进行一些处理。<br/><br/><span style="font-size: 14px;"><strong>计算 XPath</strong></span><br/><br/>在 XPath Java 对象上使用 evaluate 方法计算 XPath（不是 Java 对象，而是引用 XML 文档的一个字符串路径）。这有点容易混淆：您使用 XPath 计算 XPath。因此，从实际的角度上讲，XPath 对象是一个 XPath 计算器。<br/><br/>evaluate() 方法拥有两个参数：一个字符串 XPath，一个 DOM 树（用来针对其计算该 XPath），还有一个 XPath 常量表示返回类型。事实证明返回类型很不灵活；返回类型的规范化只是为了未来的兼容性；现在，始终使用 XPathConstants.NODESET，以将结果作为一个 DOM NodeList 结构返回。<br/><br/>查看清单 11 中用于计算 XPath 的代码，将其添加到 evaluateXPath 方法中。<br/><br/><span style="font-size: 14px;"><strong>清单 11. 计算 XPath</strong></span></span><br/><textarea name="code" class="java" rows="15" cols="100">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;public NodeList evaluateXPath(String xpathString) throws IOException &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathFactory factory = XPathFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPath xpath = factory.newXPath();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (NodeList)xpath.evaluate(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xpathString, domTree, XPathConstants.NODESET);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (XPathExpressionException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error evaluating XPath: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">清单 11 包含一些新特性，这些特性都非常重要：<br/><br/>&nbsp;&nbsp; 1. 该方法现在返回一个 org.w3c.dom.NodeList。确保将一个 import org.w3c.dom.NodeList; 语句添加到代码中，以使其生效。NodeList 是一个结构，用于从 XPath 计算中返回节点列表。<br/>&nbsp;&nbsp; 2. 整个代码块包装在一个 try/catch 块中，并且由 XPath 计算导致的异常（javax.xml.xpath.XPathExpressionException）被捕获并作为一个 IOException 再次抛出。您立刻就会明白这背后的原因。<br/>&nbsp;&nbsp; 3. 使用传递给该方法的 XPath 字符串调用 evaluate()，在类的构造函数中构建的 DOM 树和常量指示将结果作为一组节点返回。<br/>&nbsp;&nbsp; 4. evaluate 的结果（一个 Object）被转换为 DOM NodeList 类型并返回。<br/><br/>尽管发生了很多事情，但它们都非常直观，应该不会出错。<br/><br/><span style="font-size: 14px;"><strong>特定于 XPath、特定于 DOM、特定于 JAXP？</strong></span><br/><br/>一个有趣的事情是决定将来自此方法的任何异常，以及构造函数中出现的任何异常作为 IOException 返回。这是一个设计决策，实际上并非特定于 XPath，但是这个 决策非常重要。有了这个决策，您可以通过命令行或另一个程序使这个类的用户不用了解、导入或直接使用任何 XPath 类或接口。<br/><br/>实际上，您从 DOM 抽象出所有 JAXP 类、DOM 类、SAX 类以及 XPath 类……但 NodeList 类除外。这项功能非常强大，因为其他编程人员无需熟悉 JAXP 或 XPath API 就可以进行 XPath 计算。它将您的程序从有趣的编程体验转变为一个可重用的工具，这是一个非常重要的特性。<br/><br/>如果您采用这个原则并想更进一步，您可以获取返回的 NodeList 并对其进行迭代，将结果转储到一个 Java List 中。这将完全抽象出 DOM 的细节，然后删除当前对 org.w3c.dom.NodeList 的所有依赖关系。<br/><br/>处理计算结果<br/><br/>获得了 XPath 计算的结果之后，就可以对结果进行处理了……无论怎么处理都行。例如，您可以只是在结果中进行迭代并将它们打印出来。当然，您可以进行更加复杂的处理。<br/><br/>结果节点上的一个非常简单的迭代<br/><br/>实际上，NodeList 的每个成员都是一个 DOM Node（org.w3c.dom.Node），并且您可以找到每个节点的名称和类型，甚至关于节点的任何内容。清单 12 展示了 XPathEvaluator 类的一个非常基本的附加功能，它传入一个 XPath 以进行计算，获得结果并将其打印出来。<br/><br/><span style="font-size: 14px;"><strong>清单 12. 完成 XPathEvaluator 程序</strong></span></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="java" rows="15" cols="100">package ibm.dw.xpath;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XPathEvaluator &#123;

&nbsp;&nbsp;private Document domTree = null;

&nbsp;&nbsp;public XPathEvaluator(String xmlFilename) throws IOException &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Convert filename into a DOM tree
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory domFactory =
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilderFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;domFactory.setNamespaceAware(true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DocumentBuilder builder = domFactory.newDocumentBuilder();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.domTree = builder.parse(xmlFilename);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (SAXException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error in document parsing: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (ParserConfigurationException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error in configuring parser: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public NodeList evaluateXPath(String xpathString) throws IOException &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathFactory factory = XPathFactory.newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPath xpath = factory.newXPath();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (NodeList)xpath.evaluate(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xpathString, domTree, XPathConstants.NODESET);
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (XPathExpressionException e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new IOException("Error evaluating XPath: " + e.getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;

&nbsp;&nbsp;public static void main(String[] args) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;try &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.length != 1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("Usage: java ibm.dw.xpath.XPathEvaluator " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"[XML filename]");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XPathEvaluator evaluator = new XPathEvaluator(args[0]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String xpathString = "//target[@name='init']/property[" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "starts-with(@name, 'parser')]";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NodeList results = evaluator.evaluateXPath(xpathString);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i=0; i<results.getLength(); i++) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node node = results.item(i);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print("Result: ");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch (node.getNodeType()) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case Node.ELEMENT_NODE: System.out.println("Element node named " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.getNodeName());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case Node.ATTRIBUTE_NODE: System.out.println(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Attribute node named " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.getNodeName() + " with value '" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.getNodeValue() + "'");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case Node.TEXT_NODE:&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Text: '" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.getNodeValue() + "'");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: System.out.println(node);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (Exception e) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;
&#125;</textarea><br/><br/><span style="font-family: 微软雅黑;">如果您阅读了关于 XPath 的两部分教程，那么您将会在选择一些属性时感受到 XPath 的强大功能。如果还没有示例文件 xerces-build.xml，那么您应该下载（参见 参考资料）并运行此示例，如清单 13 所示。<br/><br/><span style="font-size: 14px;"><strong>清单 13. 运行 XPathEvaluator 程序</strong></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>[bdm0509:~/java_xpath] java ibm.dw.xpath.XPathEvaluator xerces-build.xml <br/>Result: Element node named property<br/>Result: Element node named property<br/>Result: Element node named property<br/>Result: Element node named property<br/>Result: Element node named property<br/>Result: Element node named property<br/><br/>这些结果非常单调，与图 1 比较时更是如此，图 1 是来自一个教程的屏幕截图，该教程使用计算 XPath 的工具对这个表达式进行图形化计算。<br/><br/><span style="font-size: 14px;"><strong>图 1. 用图形化工具计算 XPath 表达式</strong></span><br/>您可以在谓词中使用 starts-with() 并指定比较中涉及到的任何相关节点<br/><a href="https://www.heckjj.com/attachment.php?fid=69" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=69" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>但是，打印出的元素视图非常 简单。<br/><br/><span style="font-size: 14px;"><strong>一个拥有多个名称的节点</strong></span><br/><br/>请记住，尽管示例程序的所有工作只是打印节点名称、类型，以及可能的值（依赖于节点类型），您仍然会获得一个完整的 Node 对象。而且，这个节点并不是孤立的；它是对内存中的 DOM 树的一个引用（您可能未从使用透视图中看到这个 DOM 树，它隐藏在 XPathEvalutor 节点内部）。<br/><br/>这意味着，对于每个 Node，您实际上获得了传递给 XPathEvaluator 的完整 XML 文档中的一个位置指针。这意味着您可以导航到节点的子节点，查看每个元素节点的属性，找到文本节点的父元素的名称，以及在 Node 上执行任何其他允许的 DOM 操作。您不仅仅 是拥有一个节点，您拥有该节点在完整的 DOM 上下文中的引用。您可以决定对该节点和它所处的上下文进行何种操作。<br/><br/><span style="font-size: 14px;"><strong>关于早期的 JAXP、DOM 和 XPath 抽象……</strong></span><br/><br/>您可能已经注意到，上面讨论的用于避免特定于 DOM 的引用的所有工作现在都显得不重要了。实际上，这就是 XPathEvaluator 从类的用户那里抽象出 XPath 细节，但仍然返回一个 DOM NodeList 的原因。您可以使用户安全地脱离 JAXP 和 XPath，将主要精力放在 XPath 计算的结果上，您将需要对 DOM 进行处理。<br/><br/>出于此原因，最好返回 DOM 结构，但是要避免对特定于 XPath 的输入的需求，或者避免提供特定于 XPath 的输出。让您的用户仅仅处理 DOM，至少在类函数需求方面不需要任何其他内容。<br/><br/><br/>XQuery<br/><br/>开发人员的性格都比较急躁。当您开始获得从 Java 环境使用 XPath 的感觉和命令时，您可能已经在想 Xpath 还不能 进行哪些操作。数据之间非常复杂的关系不易处理（使用类似于 SQL 的连接已经达到 XPath 的功能上限了），您必须在 Java 环境中对节点进行排序和过滤，而且如果还不熟悉规范的话，将很难读懂 XPath。<br/><br/>幸运的是，您可以很自然地从 XPath 转向另一种能够解决所有这些局限性的语言，通过一种能够记住已经完成的操作的方式来完成。XQuery 添加了一个更加 XML 化的 SQL 版本，允许构建查询、对结果进行排序，并在查询中使用实际的 WHERE 语句。XQuery 也构建在 XPath 之上，这意味着您所知道的关于节点、谓词匹配，以及元素和属性如何彼此关联等所有内容都适用于 XQuery。<br/><br/>而且，就像 XPath 一样，XQuery 拥有一个面向 Java 编程人员的 API：XQuery for Java (XQJ) API。要了解关于 XQuery 的更多信息，请参见 参考资料，其中包含关于 XQuery 和 XQJ 的文章和教程的链接。如果觉得已经对 XPath 融汇贯通了，那么可以考虑使用 XQuery 来向 XML 相关的应用程序代码添加更强大的功能。<br/><br/><br/>结束语<br/><br/>从 Java 技术的角度使用 XPath 主要包括学习新语法、配置一个 API 和一些工具，然后应用所掌握的 XPath 技术。但是您不应该认为在 Java 环境中使用 XPath 是件微不足道的事情。除了复杂性之外，在通过 Java 编程来处理 XML 时，XPath 还提供了的巨大的灵活性。它能够实现的功能远远超出了大多数基本的 SAX、DOM、JAXP、JDOM 或其他实现所提供的功能（尽管一些供应商和项目为这些规范和 API 所具有的基本功能提供了支持 XPath 的扩展）。<br/><br/>而且，XPath 还能够使用更加复杂的 XQuery 语言，（通过 XQJ API）结合使用 Java 和 XQuery。无需立即转向 XQuery，您将会对 XPath 技能更加融汇贯通，学习从 Java 应用程序内部选择复杂的节点集，并根据需要对其进行操作。您将会发现很多情况下只需要 XPath 就能够处理。另外，XQuery 构建在 XPath 之上（从语法的观点和 XQJ API 方面来讲，二者都能够实际地计算并执行 XQuery），所以您不知不觉中就提高了 XQuery 技能。最重要的是，能够体会到 XPath 所提供的强大灵活性所带来的乐趣，从 Java 环境进行计算时更是如此。</span><br/>Tags - <a href="https://www.heckjj.com/tags/xpath/" rel="tag">xpath</a> , <a href="https://www.heckjj.com/tags/java/" rel="tag">java</a> , <a href="https://www.heckjj.com/tags/xml/" rel="tag">xml</a>
]]>
</description>
</item><item>
<link>https://www.heckjj.com/java-calc-xpath-xml/#blogcomment</link>
<title><![CDATA[[评论] 从Java 平台计算XPath]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://www.heckjj.com/java-calc-xpath-xml/#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>