处理器与Java API for XML 处理 (JAXP) 的关系
在大部分情况下,将需要迁移使用 Java™ API for XML 处理 (JAXP) 的任一应用程序以使用当前 API。
使用 XSLT 1.0 和 XPath 1.0 的引用定义 JAXP 的 XSLT 和 XPath 处理部分。JAXP 不具有进行 XSLT 2.0 和 XPath 2.0 处理的供应。尤其是,存在以下情况:如果具有相同输入和相同样式表或表达式,XSLT 2.0 或 XPath 2.0 处理器必须生成结果,且与 XSLT 1.0 或 XPath 1.0 处理器生成的结果不同。 因此,无法使用 JAXP 实例化当前处理器。
JAXP 还不具有对序列、XQuery 1.0 或 XSLT 2.0、XPath 2.0 和 XQuery 1.0 中可用的多个当前数据类型的支持。JAXP 还会限制为输入和输出可采用的格式。所有这些项不利于处理 XSLT 2.0 样式表以及 XPath 2.0 和 XQuery 1.0 表达式。
以下示例说明常见迁移场景以及如何使用当前 API 来编写代码,此代码与可使用 JAXP 编写的代码等价。
使用 API 处理 XSLT 样式表
XFactory factory = XFactory.newInstance();
XSLTExecutable style = factory.prepareXSLT(new StreamSource("style.xsl"));
style.execute(new StreamSource("input.xml"), new StreamResult(System.out));
使用 API 处理 XPath 表达式
XFactory factory = XFactory.newInstance();
XPathExecutable pathExpr = factory.prepareXPath("/doc/child[@id='N1378']");
// Process input from a StreamSource
XSequenceCursor result1 = pathExpr.execute(new StreamSource("input.xml"));
// Process input from a DOM node
XSequenceCursor result2 = pathExpr.execute(new DOMSource(node));
解析 URI 引用
如果使用了 JAXP URIResolver 接口的实例来解析 XSLT document() 函数的引用,那么现在可使用 XSourceResolver 接口来完成相同事情。要解析 document() 函数或 fn:doc() 函数的引用,可以在 XDynamicContext 接口的实例上设置 XSourceResolver 接口的实例;要解析通过 xsl:import 和 xsl:include 声明导入的样式表的引用,可以在 XStaticContext 接口的实例上设置 XSourceResolver 接口的实例。
final XFactory factory = XFactory.newInstance();
XSLTExecutable style = factory.prepareXSLT(new StreamSource("style.xsl"));
XDynamicContext dContext = factory.newDynamicContext();
// Create and set an instance of an anonymous inner class as the
// XSourceResolver
dContext.setSourceResolver(new XSourceResolver() {
// Create an item to use as the initial context node for
// transformations in the getSource method
private XItemView fDummyNode =
factory.getItemFactory()
.item(new StreamSource(
new StringReader("<doc/>")));
// Resolve URIs by loading the resource as an XSLT stylesheet
// and evaluating it - return the result as the Source to use
public Source getSource(String href, String base) {
java.net.URI baseURI;
try {
// Get base URI object
baseURI = new java.net.URI(base);
} catch (java.net.URISyntaxException use) {
throw new RuntimeException(use);
}
// Resolved relative reference against base URI
String resolvedURI = baseURI.resolve(href).toString();
// Prepare and execute the stylesheet
XItemView transformResult =
factory.prepareXSLT(new StreamSource(resolvedURI))
.execute(fDummyNode);
return new XItemSource(transformResult);
}
});
XSequenceCursor result = style.execute(new StreamSource("input.xml"), dContext);
定义扩展函数和外部函数
使用 JAXP for XPath 表达式求值,可以注册 XPathFunctionResolver 接口的实例,以提供 XPath 表达式可以调用的扩展函数的实现。JAXP 的 XSLT 部分不具有等价机制。
使用当前 API,可以在 XStaticContext 接口的实例上声明扩展函数,同时指定自变量的预期类型和调用函数的结果的预期类型,并可在 XDynamicContext 接口的实例上注册扩展函数的实现。您的 XSLT 样式表以及 XPath 和 XQuery 表达式可调用您注册的任何扩展函数。
设置样式表参数和外部变量的值
使用 JAXP,可以通过调用 Transformer.setParameter 方法提供样式表参数的初始值,并可通过提供 XPathVariableResolver 接口的实例为 XPath 表达式提供变量值。使用 API,可以使用 XStaticContext 接口的 declareVariable() 方法声明变量,同时指定变量名称和变量的预期类型。可以通过 XDynamicContext 接口的其中一个 bind() 方法提供样式表参数、XPath 变量和 XQuery 外部变量的值。
XFactory factory = XFactory.newInstance();
XStaticContext sContext = factory.newStaticContext();
// Declare the XPath variable "query-id" in the static context
QName queryIdVar = new QName("query-id");
sContext.declareVariable(queryIdVar, XTypeConstants.STRING_QNAME);
// Prepare the XPath expression
XItemFactory itemFactory = factory.getItemFactory();
XPathExecutable expr =
factory.prepareXPath("/catalog/product[id eq $query-id]", sContext);
XItemView catalog = itemFactory.item(new StreamSource("catalog.xml"));
XDynamicContext dContext = factory.newDynamicContext();
// Set the value of the "query-id" variable, and evaluate the
// expression with that variable value
dContext.bind(queryIdVar, "ID43785");
XSequenceCursor product1 = expr.execute(catalog, dContext);
// Set the value of the "query-id" variable, and evaluate the
// expression with the new variable value
dContext.bind(queryIdVar, "ID18574");
XSequenceCursor product2 = expr.execute(catalog, dContext);
标识变换
JAXP 中常用的其他操作为标识变换。此方法便于将数据从一种格式变换为另一种格式,例如,序列化 DOM 树或从 SAX 事件生成 DOM 树。不可使用 API 实现标识变换。请参阅执行基本 XSLT 操作,以获取示例。
Prepare-time 和 execution-time 配置
在 JAXP 中,直接针对用于执行变换的对象为 Transformer 接口和 TransformerHandler 接口的实例提供 XSLT 样式表的大量运行时配置信息(样式表参数的值、URIResolvers 等)。类似地,提供直接针对 JAXP 中的 TransformerFactory 和 XPathFactory 类的实例准备样式表和 XPath 表达式的配置信息。
使用 API,可以使用 XStaticContext 接口的实例提供准备样式表或表达式时需要的配置信息(称空间绑定、外部函数或变量的类型等)。类似地,可以提供在 XDynamicContext 接口的实例上对样式表或表达式进行求值所需的任何配置信息(变量的值、输出参数的设置等,您可以将此接口作为自变量传递到 XExecutable 接口及其子接口的执行方法。
将配置信息划分为单独对象的操作使 API 对于线程更安全。应用程序可以在不同线程上使用 XExecutable 接口的相同实例,而无需进行任何同步。这与 JAXP 相反,Transformer、TransformerHandler 和 XPathExpression 接口的实例对于线程不安全;且使用这些接口的每个线程必须同步对这些对象的共享实例的访问权,或必须创建特定于每个线程的不同副本。
处理错误
在 JAXP 中,可以提供 ErrorHandler 接口的实例以控制处理器应如何响应错误。在 API 中,可以通过在 XStaticContext 接口的实例上提供 XMessageHandler 接口的实例来响应 preparation-time 错误,或在 XDynamicContext 接口上提供该实例响应 execution-time 错误以达到此目的。