8. 使用 Java 语言对 XML 数据进行解析 Java 语言和 XML 数据格式都被认为是过去数十年中最为重要的 IT 技术之一。 Java 和 XML 之间存在有许多相似的特性,比如平台无关性、可扩展性、可重用性和国际化支持。XML 和 Java 常常被认为是完美的组合,使用 XML 的半结构化模型描述各种各样的业务数据、表达复杂的业务信息,后台则使用 Java 语言来实现独立于平台的、易于处理的面向对象的应用软件解决方案。
用于 XML 数据处理的 Java API IBM、Apache 以及其他许多公司,开发了很多用于 XML 数据处理的 Java API。 从 JDK 1.4 开始,Sun 公司将一些非常重要的代码库集成到了 Java2 平台之中,并不断升级更新,直到 JDK 1.6。 在尚未发布的 Java 7 中,Sun 公司努力实现对 XML 的语言级支持。 对于其它的语言也同样如此(比如 C++、Perl、.NET),作为一名程序开发人员,需要在首先了解 XML 相关技术的基础上,熟练掌握有关 XML 数据处理的程序开发技巧,才能顺利完成开发任务。
JDK 1.6 中面向 XML 的 JAVA API 用于 XML 数据处理的 JAVA API(Java API for XML Processing,JAXP)。JAXP 对应于 JDK 中的 javax.xml 包及其部分子包、org.w3c.dom 包及其子包、org.xml.sax 包及其子包; 用于 XML 数据绑定的 Java API(Java API for XML Binding,JAXB),对应于 JDK 中的 javax.xml.bind 包及其子包; 用于基于 XML 的 RPC 的 Java API(Java API for XML-based RPC,JAX-RPC),对应于 JDK 中的 javax.jws 包及其子包; 用于带附件的 SOAP 消息的 JAVA API(SOAP with Attachments API for Java,SAAJ),对应于 JDK 中的 javax.xml.soap 包及其子包; 用于基于 XML 的 Web 服务的 Java API(Java API for XML-based Web services,JAX-WS),对应于 JDK 中的 javax.xml.ws 包及其子包; 用于 XML 加密签名的 Java API,对应于 JDK 中的 javax.xml.crypto 包及其子包;
8.1 XML 数据解析的概念及 JAXP 简介 XML 解析器实际上就是能够识别 XML 基本语法形式的特殊应用程序,并将纯文本的 XML 文档转换成其他某种内存中表现形式(比如 XML 文档树、或者一系列的解析事件),以便客户端应用程序能够方便地对 XML 文档中的数据进行访问、提取、检索。 Xerces 来自 IBM 在 1999 年捐赠给 Apache 的 XML4J 项目,随后成为了 Apache XML Project 的子项目。但由于 XML 技术的迅速发展,在 2004 年,Xerces 解析器成为了 Apache Software Foundation 的顶级项目(独立项目)。
DOM 和 SAX 解析模型简介 DOM (Document Object Model)是 W3C 的规范(http://www.w3.org/DOM/),是一种与浏览器、平台、语言无关的接口,可用于表示各种半结构化的、层次模型的数据(比如 HTML、XML 等)。 SAX ( Simple API for XML )是顺序读取 XML 的解析器 API,是一个为基于事件 XML 解析器定义的、免费的、并且与平台、语言无关的 API。由 XML-Dev 邮件列表组织(由许多 XML 方面的专家和开发人员组成)开发而来,并且已经成为了一种 XML 数据处理的事实上的标准。
DOM 解析模型 DOM 是以层次结构组织的节点或信息片断的集合,是 XML 数据的一种树型表示,通过树中的各种节点、以及节点之间的父子关系来表示 XML 文档中的元素、属性、文本内容,以及元素之间的嵌套关系。这个层次结构允许开发人员在树中寻找特定信息,并对其中的数据进行修改和创建。
SAX 解析模型 SAX 解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件(如图 8-2 中所示),当发生相应事件时,将调用一个回调方法,回调方法的编写是数据解析的关键。 <?xml version="1.0"?> <config> <server>UNIX</server> </config> Start document Start element (config) Characters (whitespace) Start element (server) Characters (UNIX) End element (server) End element (config) End document
JAXP 简介 JAXP 是 Java API for XML Processing 的首字母缩写(读作 jaks-p),是 SUN Java JDK 中的 XML 编程 API,它为解析、处理、验证 XML 文档数据的基本功能提供了相应的编程接口。 作为处理 XML 数据的 Java 抽象层,JAXP 规范本身也在不断地发展,目前 JDK 1.6 中的 JAXP 的版本为 JAXP 1.4。
JAXP 的本质 XML 解析器种类繁多,开发人员希望不修改源代码就能够更换底层所使用的 XML 解析器呢,这就必须“对抽象进行编程”,以实现底层解析器的可插入性。
8.2 在 JAXP 中使用 DOM 解析器处理 XML 文档 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = dbf.newDocumentBuilder(); Document domDoc = builder.parse(fileName);} catch (ParserConfigurationException e) { e.printStackTrace()); };
8.2.1 使用 JAXP 在 JAXP 中,newInstance 在确定具体解析器工厂实现类时,将按照下面的顺序进行搜索: 使用 javax.xml.parsers.DocumentBuilderFactory 系统属性。 使用 JRE 文件夹中的属性文件 "lib/jaxp.properties"。此配置文件格式为标准的 java.util.Properties 且包含实现类的完全限定名,其中实现类的键是上述定义的系统属性。 JAXP 实现只读取一次 jaxp.properties 文件,然后缓存其值供以后使用。如果首次尝试读取文件时,文件不存在,则不会再次尝试检查该文件是否存在。首次读取 jaxp.properties 后,其中的属性值不能再更改。 使用 Services API(在 JAR 规范中进行了详细描述)来确定类名称。Services API 将查找在运行时可用的 jar 中 META-INF/services/javax.xml.parsers. DocumentBuilderFactory 文件中的类名。 平台默认的 DocumentBuilderFactory 实例。
8.2.2 DOM 解析器编程接口
org.w3c.xml.Node 接口 Node 接口是整个文档对象模型的主要数据类型。它表示该文档树中的单个节点。Node 接口中包含如下主要内容: 表示节点类型的常量、及获得节点类型信息的方法; 获得节点基本信息(名称、值)的方法; 获得节点层次信息的方法; for (int i = 0; i < attrs.getLength(); i++) { Attr attrNode = attrs.item(i); // item() 方法表示可以按某种顺序访问属性集合,而属性本身是没有顺序的。 ...... } NodeList xNodeList = xNode.getChildNodes(); for (int i = 0; i < xNodeList.getLength();) { childNode = xNodeList.item(i); ...... } short nodeType = node.getNodeType(); switch (nodeType) { case Node.DOCUMENT_NODE: {... break; } case Node.ELEMENT_NODE: {... break; } case Node.ATTRIBUTE_NODE: {... break; } case Node.TEXT_NODE: {... break; } ......} 获得节点的名称 getNodeName()、节点的值getNodeValue()
org.w3c.xml.Document 接口 Document 接口表示整个 HTML 或 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的基本访问。请注意,文档的根元素节点并不是文档节点,文档节点在根元素节点之上,是一个无形的节点。 Document 接口还包含所需的、创建这些对象的工厂方法。文档节点 Document 接口中提供了一系列的 create 方法(所有的创建工作都必须使用文档节点),比如: createElement(String tagName) 创建指定类型的元素节点。 createAttribute(String name) 创建给定名称的 Attr 节点。 createTextNode(String data)创建指定字符串的 Text 节点。 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.newDocument(); Node xNode1 = doc.createElement("family"); doc.appendChild(xNode1); Node xNode2 = doc.createElement("parent"); xNode1.appendChild(xNode2); Node xNode3 = doc.createElement("child"); xNode1.appendChild(xNode3); ......
org.w3c.xml.Element 接口 Element 接口表示 XML 文档中的一个元素。 可使用getAttributes()来获得元素所有属性的集合attributes(Node 接口的方法);可使用 Node 接口提供的 getChildNodes() 方法获得子元素列表 。 定义了 getElementsByTagName(String name),它将以文档顺序返回具有给定标记名称的所有后代元素的 NodeList。
org.w3c.xml.Attr 接口 Attr 接口表示 Element 对象中的属性。通常该属性所允许的值定义在与文档相关的模式中。 Attr 对象继承 Node 接口,但由于它们实际上并不是相关元素的子节点,DOM 不会将它们看作文档树的一部分。 Node 的属性 parentNode、previousSibling 和 nextSibling 都将返回 null。 如果要获得属性所属的元素,不能使用 Node 接口中定义的 getParentNode() 方法,而应该使用 Attr 接口中定义的 getOwnerElement() 方法。
org.w3c.xml.CharacterData 接口及其子接口 CharacterData 接口用于表示 XML 文档中以文本内容为主的节点,其子接口包括:CDATASection、Comment、Text。CharacterData 接口中提供了各种操作文本数据的方法: appendData(String arg) ——将字符串追加到节点的字符数据的结尾。 deleteData(int offset, int count) ——从该节点移除某个范围的字符。 getData() ——获取文本内容。 setData(String data) ——设置文本内容。
org.w3c.xml 中的其他接口 DOM 文档树中还包括一些其他类型的节点,比如 ProcessingInstruction、Notation、Entity 等等。 此外,org.w3c.xml 中还定义了一些在解析 XML 数据时使用到的其他接口,比如前面提到的 NodeList 节点列表接口、NamedNodeMap 命名节点映射接口等等。 熟练地掌握针对上述接口的操作,是解析 XML 文档数据的关键。
8.2.3 使用 DOM 模型解析 XML 文档的示例程序 DomEcho.java
8.3 在 JAXP 中使用 SAX 解析器处理 XML 数据 SAX 是通过 callback 回调函数来处理 XML 元素的,这样,SAX 处理 XML 时,是从头开始,对 XML 元素是一个一个地处理。所以可以有效地抑制内存的消耗,适合处理大内容的 XML 文档。SAX 对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的标记。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现。
8.3.1 JAXP 中 SAX 模型的使用 在 JAXP 1.4 中使用 SAX 模型进行数据处理时,将使用到 javax.xml.parsers 包、org.xml.sax 包及其子包(org.xml.sax.ext 包和 org.xml.sax.helpers 包)。 将简要介绍这些包中常用的一些基本类和接口、以及它们之间的关系(有关所有的类、接口、异常的内容,请参见 JDK 开发文档),然后说明使用 SAX 解析器的一般步骤。
SAX 相关类库的介绍(1) javax.xml.parsers包中有关SAX模型的Java 类: SAXParserFactory(抽象类) SAXParser(抽象类) 创建 SAX 解析器对象之后,可以使用 SAXParser 类的 parse( ) 方法对 XML 文档进行解析。 SAXParserFactory spf = SAXParserFactory.newInstance( ) 缺省情况下,JAXP 将使用 JDK 1.6 中自带的 Xerces 提供的 SAX 解析器实现的工厂类: class com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl SAXParser sp = spf.newSAXParser(); 在缺省情况下,使用的 SAX 解析器实现为: class com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl
SAX 相关类库的介绍(2) 解析事件处理程序(接口) XMLReader(接口) XML 解析器 SAX2 驱动程序必须实现的接口 ContentHandler DTDHandler EntityResolver ErrorHandler XMLReader(接口) XML 解析器 SAX2 驱动程序必须实现的接口 void setContentHandler(ContentHandler handler) / ContentHandler getContentHandler() 允许应用程序注册内容事件处理程序。 void setDTDHandler(DTDHandler handler) / DTDHandler getDTDHandler() 允许应用程序注册 DTD 事件处理程序。 void setEntityResolver(EntityResolver resolver) / EntityResolver getEntityResolver() 允许应用程序注册实体解析器。 void setErrorHandler(ErrorHandler handler) / getErrorHandler()
SAX 相关类库的介绍(3) org.xml.sax.ext 包中有关 SAX 模型的 Java 类: LexicalHandler(接口):SAX2 的可选扩展处理程序,以提供关于 XML 文档的词汇信息,例如,对注释和 CDATA 段的处理。通常不需要为 XMLReader 注册此处理程序,它不是核心 SAX2 的内容。
SAX 相关类库的介绍(4) org.xml.sax.helpers 包中有关 SAX 模型的 Java 类: JDK 的 org.xml.sax.helpers 包中提供了一个 DefaultHandler 类,该类实现了 ContentHandler、DTDHandler、EntityResolver、ErrorHandler 四个接口,并为其中所有的方法提供了空的实现。这样一来,我们只需要继承这个类,并重写其中感兴趣的回调函数即可。实际上,这正是设计模式中常用的“缺省适配器模式”。
使用 SAX 解析器的几种方法 (1) 直接用 SAXParser 解析器对象的 parse(...) 方法解析输入 XML 文档 SAXParserFactory spf = SAXParserFactory.newInstance( ) SAXParser sp = spf.newSAXParser(); // MyDefaultHandler 是用户编写的 DefaultHandler 的子类,重写了所需的回调函数 sp.parse(new File("bib.xml"), new MyDefaultHandler( ));
使用 SAX 解析器的几种方法 (2) 使用 SAXParser 解析器对象中包含的 XMLReader 对象来解析 XML 文档。 SAXParserFactory spf = SAXParserFactory.newInstance( ) SAXParser sp = spf.newSAXParser(); XMLReader reader = sp.getXMLReader(); // MyContentHandler 是用户编写的 ContentHandler 的实现类,重写了所需的回调函数 reader.setContentHandler(new MyContentHandler( )); // MyDTDHandler 是用户编写的 DTDHandler 的实现类,重写了所需的回调函数 reader.setDTDHandler(new MyDTDHandler( )) // MyEntityResolver 是用户编写的 EntityResolver 的实现类,重写了所需的回调函数 reader.setEntityResolver(new MyEntityResolver( )) // MyErrorHandler是用户编写的 ErrorHandler 的实现类,重写了所需的回调函数 reader.setErrorHandler(new MyErrorHandler( )) reader.parse(new InputSource(new FileInputStream(new File("bib.xml")));
额外功能的使用 在使用 SAX 解析器时,可以在程序中启用某些额外的功能,比如支持验证、支持命名空间等等。SAXParserFactory 中为此提供了一些设置方法 : setValidating(boolean validating) 是否在解析的同时进行验证 setNamespaceAware(boolean awareness) 是否支持命名空间 具体的程序代码可能如下所示: SAXParserFactory spf = SAXParserFactory.newInstance( ) spf.setValidating(true); spf.setNamespaceAware(true); SAXParser sp = spf.newSAXParser(); 这样一来,工厂类对象 spf 创建的所有 SAXParser 解析器都支持验证和命名空间。 也可以使用 SAXParserFactory 的 setFeature(String name, boolean value) 来完成同样的操作。 SAXParserFactory spf = SAXParserFactory.newInstance( ) spf.setFeature("http://xml.org/sax/features/validation", true); spf.setFeature("http://xml.org/sax/features/namespaces", true); SAXParser sp = spf.newSAXParser(); http://apache.org/xml/features/validation/schema/augment-psvi 是否启用扩展的 PSVI http://xml.org/sax/features/external-parameter-entities 是否支持外部参数实体
8.3.2 SAX 模型中回调函数的重写 使用 SAX 模型解析 XML 数据的关键在于编写适当的回调函数,并在其中实现所需的数据处理逻辑。下面将详细地介绍每种回调函数的作用和使用,当然还需要确定一个假想的数据处理逻辑,这里假设在对某个 XML 文档进行处理时,仅仅只是将其中的内容复制一遍(这个处理逻辑非常简单,后面将其称为 SAXEcho 任务),那么应该如何编写相应的回调函数呢?
void setDocumentLocator(Locator locator) 接收文档事件的 Locator 对象。默认情况下,不执行任何操作。如果应用程序编写者希望存储定位器以用于其他的文档事件,则可以在子类中重写此方法。该定位器仅在调用 SAX 事件回调期间,在 startDocument 返回之后,调用 endDocument 之前,返回正确的信息。 用例:对于 SAXEcho 任务,如果需要在某个事件发生时,获得该事件对应于 XML 文档中的位置,则可以编写如下代码。 private Locator locator; void setDocumentLocator(Locator locator) { this.locator = locator; }
void startDocument( ) 接收文档开始的通知。默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在文档的开始采取特定的措施(如分配树的根节点或创建输出文件)。通常,发生在其他任何事件回调(不包括 setDocumentLocator)之前,SAX 解析器仅调用此方法一次。 用例:对于 SAXEcho 任务,在碰到 startDocument 事件时表示开始处理输入 XML 文档内容,这时只需要输出 XML 声明即可。 void startDocument() { System.out.print("<?xml version=\"1.0\"?>\n"); }
void endDocument( ) 接收文档结束的通知。默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在文档的结束处采取特定的操作(如,结束树或关闭输出文件)。SAX 解析器仅调用此方法一次,并且它将是解析期间最后调用的方法。直到解析器放弃解析(由于不可恢复的错误)或到达输入的结尾时,它才可以调用此方法。 用例:对于 SAXEcho 任务,在碰到 endDocument 事件时表示即将结束对输入 XML 文档内容的处理,不需要进行任何操作。 void endDocument() { // Do not need to do anything. }
void startElement(String uri, String localName, String qName, Attributes attributes) 用例:对于 SAXEcho 任务,在碰到 startElement 事件时表示处理到某个 XML 元素的开始标记,这时需要手动输出该元素开始标记的所有内容(包括属性、命名空间声明)。 void startElement(String namespaceURI, String localName, String qName, Attributes attrs) { System.out.print("<"); System.out.print(qName); if (attrs != null) int len = attrs.getLength(); for (int i = 0; i < len; i++) System.out.print(" "); System.out.print(attrs.getQName(i)); System.out.print("=\""); System.out.print(attrs.getValue(i)); System.out.print("\""); } System.out.print(">"); 接收元素开始的通知。默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在每个元素的开始处采取特定的操作(如分配新的树节点或将输出写入文件)。
void endElement(String uri, String localName, String qName) 接收元素结束的通知。默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在每个元素的结束处采取特定的操作(如,结束树节点或将输出写入文件)。SAX 解析器会在 XML 文档中每个元素的末尾调用此方法;对于每个 endElement 事件都将有相应的 startElement 事件(即使该元素为空时)。 用例:对于 SAXEcho 任务,在碰到 endElement 事件时只需输出元素的结束标记即可。 void endElement(String namespaceURI, String localName, String qName) { System.out.print("</"); System.out.print(qName); System.out.print(">"); }
void characters(char[ ] ch, int start, int length) 接收元素中字符数据的通知。默认情况下,不执行任何操作。应用程序编写者可以重写此方法,以便对每块字符数据采取特定的措施(如将该数据添加到节点或缓冲区,或者将该数据打印到文件)。 用例:对于 SAXEcho 任务,在碰到文本内容时,需要进行复制输出。 public void characters(char ch[], int start, int length) { System.out.print(new String(ch, start, length)); } 比如 XML 数据 <author><last>Stevens</last><first>W.</first></author>,将两次进入 characters 回调函数,每次在该回调函数中,使用 new String(ch, start, length) 可以获得当前处理的文本内容。
void ignorableWhitespace(char[ ] ch, int start, int length) 接收元素内容中可忽略空白的通知。默认情况下,不执行任何操作。应用程序编写者可以重写此方法,以便对每块可忽略的空白采取特定的措施(如将数据添加到节点或缓冲区,或者将数据打印到文件)。 如果按照前面的方法重写 characters,而不重写 ignorableWhitespace 回调函数,完全能够得到正确地结果(即输出与输入完全相同)。 对于下面的输入 XML 文档: <author> <last>Stevens</last> <first>W.</first> </author>
可忽略的空白字符(ignorableWhitespace) <!DOCTYPE author [ <!ELEMENT author (last,first)> <!ELEMENT last (#PCDATA)> <!ELEMENT first (#PCDATA)> ]> <author> <last>Stevens</last> <first>W.</first> </author> 如果仅仅按照上面的方法重写 characters,而不重写 ignorableWhitespace 回调函数,那么输出结果:<author><last>Stevens</last><first>W.</first></author> void ignorableWhitespace(char ch[], int start, int length) { characters(ch, start, length); } SAX 解析器并不会主动地忽略输入文档中的空白字符(所以使用 characters 回调函数就能够对空白字符进行处理),除非指定 SAX 解析器使用验证功能,并且根据所提供的模式,能够判断出其中包含了多余的空白字符。
void processingInstruction(String target, String data) 接收处理指令的通知。默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便对每个处理指令采取特定的措施,如设置状态变量或调用其他的方法。 用例:对于 SAXEcho 任务,在碰到处理指令时,需要进行复制输出。 void processingInstruction(String target, String data) { System.out.print("<?"); System.out.print(target); if (data != null && data.length() > 0) System.out.print(' '); System.out.print(data); } System.out.print("?>");
有关命名空间的回调函数 void startPrefixMapping(String prefix, String uri) 接收名称空间映射开始的通知。默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在每个名称空间前缀范围的开始处采取特定的操作。 void endPrefixMapping(String prefix) 接收名称空间映射结束的通知。默认情况不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在每个前缀映射的结束处采取特定操作。
错误处理回调函数 void warning(SAXParseException e) 接收解析器警告的通知。默认实现不执行任何操作。应用程序编写者可以在子类中重写此方法,以便对每个警告采取特定措施,如在日志文件中插入消息,或将其打印到控制台。 void error(SAXParseException e) 接收可恢复的解析器错误的通知。默认实现不执行任何操作。应用程序编写者可以在子类中重写此方法,以便对每个错误采取特定的措施,如在日志文件中插入消息,或者将它打印到控制台。 void fatalError(SAXParseException e) 报告严重的 XML 解析错误。默认的实现抛出 SAXParseException。
8.3.3 使用 SAX 模型解析 XML 文档的示例程序 SAXSample.java (从 XML 文档构造 Employee 类的对象集合 )。
8.4 DOM 和 SAX 之间的性能分析和比较 saxVSdom 应用程序。 DOM 和 SAX 的性能比较。
8.5 JAXP 中的其它 XML 数据处理 API 执行 XPath 查询 使用 Trax API 执行数据转换操作 执行 XQuery 查询
执行 XPath 查询 (1) 1. 实例化一个 XPathFactory 2. 使用 XPathFactory 创建一个 XPath 对象 javax.xml.xpath.XPathFactory factory = javax.xml.xpath.XPathFactory.newInstance(); 缺省情况下,JDK 1.6 中将使用: class com.sun.org.apache.xpath.internal.jaxp.XPathImpl javax.xml.xpath.XPath xpath = factory.newXPath();
执行 XPath 查询 (2) 3. (可选步骤)将 XPath 表达式字符串编译为 XPathExpression 对象: javax.xml.xpath.XPathExpression expression = xpath.compile("/doc/name"); 通常可以使用 XPath.compile(String expression) 将 XPath 表达式字符串编译为一个 XPathExpression 对象,以便稍后使用;当然,执行之前的编译操作并不是必须的,这是一个可选的步骤,您也可以直接计算 XPath 对象。XPathExpression 对象和 XPath 对象的区别在于,如果需要反复针对多个上下文执行同一个 XPath 查询计划,那么应该首先对其进行编译,以便重用。
执行 XPath 查询 (3) 4. 针对一个输入文档,计算 XPath 表达式(使用经过编译的 XPathExpression 对象,或者未经过编译的 XPath 对象) XPathJaxp.java expression.evaluate(new org.xml.sax.InputSource("foo.xml")); xpath.evaluate("/doc/name", new org.xml.sax.InputSource("foo.xml")); XPathExpression 类的 evaluate 方法: String evaluate(Object item) Object evaluate(Object item, QName returnType) String evaluate(InputSource source) Object evaluate(InputSource source, QName returnType) 参数 QName returnType 的值可能为: XPathConstants.BOOLEAN XPathConstants.NUMBER XPathConstants.STRING XPathConstants.NODESET XPathConstants.NODE
使用 Trax API 执行数据转换操作(1) 转换任务的输入可能是 URL、XML 流、DOM 树、SAX 事件、或者专用格式和数据结构,输出类型大致与输入类型相同,如果有 n 种输入、n 种输出,那么一共就有 n2 种组合。因此,对于转换 API 来说,最重要地就是如何处理输入和输出的各种可能的组合。 从 JDK 1.5 中的 JAXP 1.3 起,就开始将 TrAX(Transformation API for XML)集成到了核心的 Java 开发环境中。TrAX 主要由下列软件包组成: javax.xml.transform:定义用于处理转换指令、以及执行从源到结果的转换的 API。 javax.xml.transform.sax:实现特定于 SAX2 的转换 API。 javax.xml.transform.dom:此包实现特定于 DOM 的转换 API。 javax.xml.transform.stream:实现特定于流和 URI 的转换 API。
使用 Trax API 执行数据转换操作(2) TransformerFactory 是处理转换指令的一种对象,可以由它产生 Templates,一个 Templates 可以产生一个 Transformer,后者可以将一个或多个 Source 转换为一个或多个 Result。 要使用 TrAX API,必须首先创建一个 TransformerFactory,它可以直接提供 Transformer、或者从不同的 Source 提供 Templates。 Templates 对象是经过处理的转换指令的运行时表示形式,是经过编译的 Transformer,对于多线程同时运行的给定实例是线程安全的,且在给定会话中可多次使用。
使用 Trax API 保存 XML 文档 private void saveXMLtoFile(Document xDoc, String fileName) { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(xDoc), new StreamResult( new FileOutputStream(outputfileName))); } class com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl Xalan 是 Apache 开发的一种 TrAX API,JDK 1.6 中使用的则是 Xalan 的内部修改版本,您也可以到 http://xalan.apache.org 下载完整的 Xalan API。
使用 Trax API 执行简单的 XSLT 转换 对某个 XML 文档执行 XSLT 转换,只需在使用转换器工厂对象的 newTransformer 构造 transformer 对象时使其关联到 XSLT 文档即可(传递一个 XSLT 文件作为参数),比如要使用 test.xsl 对 test.xml 进行转换: TraxDemo1.java 执行复杂的 XSLT 转换 (TraxDemo2.java) void XSLTTransformation() { TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(new StreamSource("test.xsl")); transformer.transform(new StreamSource("test.xml"), new StreamResult(System.out)); }
执行 XQuery 查询(1) XQJ 的目标在于为 XQuery 的 Java 实现提供标准的便捷的访问接口。XQJ 是一个通用的 XQuery 数据访问框架,它在许多不同的 XQuery 实现之上提供了一个统一的接口。 与 JAXP 一样,其中定义了一些相关的接口和类、以及相应的编程规范,以便 Java 应用程序能够灵活地选择底层的 XQuery 实现提供者,并且能够通过 XQuery 引擎对一个或者多个 XML 数据源提交 XQuery 查询和使用查询结果。
执行 XQuery 查询(2) 大部分 Java 程序员熟悉 JDBC,它提供了标准的 Java API 以便与各种关系数据库的 SQL 引擎进行交互。XQJ 具有相同的目的:它向 Java 程序员提供了标准的 Java API 用于和各种 XML 数据源的 XQuery 引擎进行交互。因此在使用上,XQJ 采取了与 JDBC 相同的几种模式。 比如,创建并执行 XQuery 查询的典型方法为: 1. 建立与数据源的连接; 2. 准备 XQuery 查询计划; 3. 对预编译的 XQuery 查询计划进行变量绑定,以便复用查询计划; 4. 执行 XQuery 查询,并处理结果; 5. 清理资源,断开与数据源的连接。
执行 XQuery 查询(3) 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: import java.util.*; import net.sf.saxon.javax.xml.xquery.*; import net.sf.saxon.xqj.SaxonXQDataSource; public class XQJ_Simple { public static void main(String[] args) throws Exception { XQDataSource xqds=new SaxonXQDataSource(); XQConnection xqjc = xqds.getConnection(); XQExpression xqje = xqjc.createExpression(); XQSequence xqjs = xqje.executeQuery("for $i in 1 to 10 return $i"); xqjs.writeSequence(System.out, new Properties()); xqjc.close(); } 程序 XQJ_Simple.java