下列部分描述了如何使用“XML 的流 API”解析和生成 XML 文档:
<!--[if !supportLists]-->§ <!--[endif]-->XML 的流 API 概述
<!--[if !supportLists]-->§ <!--[endif]-->使用 XMLStreamReader 接口解析 XML:典型步骤
<!--[if !supportLists]-->§ <!--[endif]-->用 XMLStreamWriter 接口生成 XML:典型步骤
<!--[if !supportLists]-->§ <!--[endif]-->为 XMLInputFactory 接口定义的属性
<!--[if !supportLists]-->§ <!--[endif]-->为 XMLOutputFactory 接口定义的属性
Java Community Processs 的 JSR-173 指定的 XML的流 API (StAX) 提供了简单直观的解析和生成 XML 文档的方式。它与 SAX API 类似,但启用对 XML 文档的基于流的过程处理,而不要求您编写 SAX 事件处理程序;在使用复杂 XML 文档时,编写 SAX 事件处理程序将变得会非常复杂。换句话说,与 SAX 相比,StAX 提供了更多对解析的控制。
在程序使用 SAX 解析 XML 文档时,此程序必须创建在要解析的事件发生时对其进行监听的事件监听器,此程序必须响应事件,而不是请求特定事件。相比而言,如果使用 StAX,则可以有系统地逐步解析 XML 文档,请求某些事件类型(如元素的开始)、迭代元素的特性、跳到文档开头、随时停止处理、获取特定元素的子元素并根据需要筛选掉元素。由于是在请求事件而非响应事件,因此常将使用 StAX 称为“pull parsing”。
StAX 包含两个 API:“游标 API”和“事件迭代器 API”,它们中的任一个都可以用于读取和写入 XML。下列部分描述了各个 API 及它们的强项。
通过游标 API 的基本功能,编程人员能够以最轻松且有效方式来解析和生成 XML。对于 StAX 的 两个 API 而言,大多数编程人员乐意使用此 API。
游标 API 可在一组事件(例如开始元素、注释和特性)中迭代,即使可能并未实现这些事件。游标 API 具有两个主要接口:用于解析 XML 的 XMLStreamReader,以及用于生成 XML 的 XMLStreamWriter。
游标 API 使用 XMLStreamReader 接口在 XML 文档上移动虚拟游标,并允许通过调用 hasNext()、next()、getEventType() 和 getText() 之类的方法调用访问数据和底层状态。XMLStreamReader 接口只允许以向前和只读方式访问 XML。
可使用 XMLInputFactory 类新建 XMLStreamReader 的实例。在获取新读取器时,您可以设置各种属性;有关详情信息,请参阅为 XMLInputFactory 接口定义的属性。
在使用 XMLStreamReader 接口的 next() 方法解析 XML 时,读取器可获取下一个解析事件,并返回一个整数(此整数可标识刚读取的事件的类型)。解析与 XML 文档的部分相对应的事件,如 XML 声明、开始和结束元素标记、字符数据、空格、注释和处理指令。XMLStreamConstant 接口可指定 next() 方法返回的整数所对应的事件。还可以使用 XMLStreamReader 的getEventType() 方法来确定事件类型。
XMLStreamReader 接口具有很多获取 XML 文档中特定数据的方法。其中的某些方法包括:
<!--[if !supportLists]-->§ <!--[endif]-->getLocalName() - 返回当前事件的本地名称。
<!--[if !supportLists]-->§ <!--[endif]-->getPrefix() - 返回当前事件的前缀。
<!--[if !supportLists]-->§ <!--[endif]-->getAttributeXXX() - 返回有关当前特性事件的信息的一组方法。
<!--[if !supportLists]-->§ <!--[endif]-->getNamespaceXXX() - 返回有关当前名称空间事件的信息的一组方法。
<!--[if !supportLists]-->§ <!--[endif]-->getTextXXX() - 返回有关当前文本事件的信息的一组方法。
<!--[if !supportLists]-->§ <!--[endif]-->getPIData() - 返回当前处理的指令事件的数据部分。
对于每种事件类型而言,只有某些方法是有效的;如果您尝试对无效事件类型调用方法,StAX 处理器将引发 java.lang.IllegalStateException。例如,尝试对名称空间事件调用 getAttributeXXX() 方法是错误的。有关完整事件列表及其有效 XMLStreamReader 方法的信息,请参阅 StAX specification。
游标 API 使用 XMLStreamWriter 接口指定如何生成 XML。
可使用 XMLOutputFactory 类新建 XMLStreamWriter 的实例。在获取新编写器时,可以设置用于修复名称空间和前缀的属性;有关详情信息,请参阅为 XMLOutputFactory 接口定义的属性。
XMLStreamWriter 接口定义了一组 writeXXX() 方法来写入 XML 文档的标准部分,例如:
<!--[if !supportLists]-->§ <!--[endif]-->writeStartElement()
<!--[if !supportLists]-->§ <!--[endif]-->writeEndDocument()
<!--[if !supportLists]-->§ <!--[endif]-->writeAttribute()
<!--[if !supportLists]-->§ <!--[endif]-->writeNamespace()
<!--[if !supportLists]-->§ <!--[endif]-->writeCData()
必须使用这些方法,显式写入 XML 文档的每个部分(包括特性和命名空间)。
可使用 flush() 方法将任何缓存数据写入输出,使用 close() 方法关闭编写器,并释放所有资源。
在生成 XML 时,XMLStreamWriter 不检查生成文档的格式是否标准;创建标准格式的 XML 文档是编程人员的职责。要打印特殊字符 &、< 和 >,请使用 writeCharacters() 方法。
事件迭代器 API 是位于游标 API 顶端的层。它易于扩展并简化了管道操作。管道操作指多个 XML 到 XML 的转换。通过使用事件迭代器 API,编程人员无需在管道的每个阶段除序列化和序列化 XML;而是只需在管道的每个末尾处执行操作,并使用 API 方法(如 nextEvent())在中间阶段进行通信。事件迭代器 API 具有两个主要接口:用于解析 XML 的XMLEventReader,以及用于生成 XML 的 XMLEventWriter。
由于游标 API 是 StAX 中最常用的 API,故本部分不再详细描述事件迭代器 API 的用法,只显示一个示例。有关使用此 API 的详细信息,请参阅 StAX specification。
以下示例显示了一个简单程序,此程序使用 StAX 的 XMLEventReader 接口解析 XML 文档。此程序采用单个参数,即一个 XML 文件,并使用此参数创建 XMLEventReader 对象。程序然后使用此读取器迭代事件流,并进行打印。
import java.io.FileReader;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.stream.util.*;
import javax.xml.namespace.QName;
/**
* 迭代事件的简单示例
*
* @作者版权所有 (c) 2002 BEA System。保留所有权利。
*/
public class Parse {
private static String filename = null;
private static void printUsage() {
System.out.println("usage: java examples.event.Parse <xmlfile>");
}
public static void main(String[] args) throws Exception {
try {
filename = args[0];
} catch (ArrayIndexOutOfBoundsException aioobe){
printUsage();
System.exit(0);
}
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader r =
factory.createXMLEventReader(new FileReader(filename));
while(r.hasNext()) {
XMLEvent e = r.nextEvent();
System.out.println("ID:"+e.hashCode()+"["+e+"]");
}
}
}
用于生成 XML 文档的接口。它提供了一组 writeXXX() 方法,用于生成 XML 文档的特定部分,如开始元素和特性等。 | ||
用于处理事件的基本接口。从 XMLEvent 扩展的所有特定 XML 事件,如 StartElement 和 Attribute 等。 | ||
使用 XMLStreamReader 接口解析 XML:典型步骤
以下过程描述了使用 StAX 游标 API 的 XMLStreamReader 接口解析 XML 文档的典型步骤。此过程在其描述中使用了使用 StAX 解析 XML 的示例中的示例。
<!--[if !supportLists]-->1. <!--[endif]-->导入 javax.xml.stream.* 类。
<!--[if !supportLists]-->2. <!--[endif]-->可使用 XMLInputFactory.newInstance() 方法实例化 XMLInputFactory,如以下代码摘录所示:
XMLInputFactory xmlif = XMLInputFactory.newInstance();
有关可以设置的属性列表的信息,请参阅为 XMLInputFactory 接口定义的属性。
<!--[if !supportLists]-->3. <!--[endif]-->可使用 XMLInputFactory.createXMLStreamReader() 方法实例化基于 XML 文档的 XMLStreamReader 对象。
有关详细信息,请参阅获取 XMLStreamReader 对象。
<!--[if !supportLists]-->4. <!--[endif]-->可使用 hasNext() 和 next() 方法逐一查看 XML 事件,以解析 XML 文档,如以下代码摘录所示:
while(xmlr.hasNext()){
printEvent(xmlr);
xmlr.next();
在此示例中,xmlr 为 XMLStreamReader 实例,本地 printEvent() 方法(不属于 StAX API)用于确定特定事件类型,如下一步中所述。
<!--[if !supportLists]-->5. <!--[endif]-->在解析 XML 文档期间,确定当前的特定事件类型并采取相应的操作。事件类型包括 XML 文档的开始和结束、XML 元素的开始和结束、注释和实体引用等。
请参阅确定特定 XML 事件类型。
<!--[if !supportLists]-->6. <!--[endif]-->如果当前事件类型是开始元素或结束元素,则可根据需要获取其特性。
请参阅获取元素的特性。
<!--[if !supportLists]-->7. <!--[endif]-->如果当前事件类型是开始元素或结束元素,则可根据需要获取其名称空间。
请参阅获取元素的名称空间。
<!--[if !supportLists]-->8. <!--[endif]-->如果当前事件类型包含文本数据,如 CDATA 或注释,则可根据需要获取实际数据。
请参阅获取文本数据。
<!--[if !supportLists]-->9. <!--[endif]-->可根据需要获取位置信息,如当前事件的行号或列号。
请参阅获取位置信息。
<!--[if !supportLists]-->10. <!--[endif]-->关闭流。
请参阅关闭输入流。
以下示例显示了一个简单程序,此程序使用 StAX 的 XMLStreamReader 接口解析 XML 文档。
此程序采用单个参数,即一个 XML 文件,并使用此参数创建 XMLStreamReader 对象。此程序然后使用读取器迭代事件流,确定每个事件的类型,如 XML 元素的开始、元素的特性列表和处理指令等。此程序可打印出有关这些事件的信息,在适当时使用内部方法打印出特性列表和名称空间列表。
import java.io.FileReader;
import java.util.Iterator;
import javax.xml.stream.*;
import javax.xml.namespace.QName;
/**
* 这个简单示例
* 演示了 XMLStreamReader 类。
*
* 作者版权所有 (c) 2003 BEA Systems。保留所有权利。
*/
public class Parse {
private static String filename = null;
private static void printUsage() {
System.out.println("usage: java examples.basic.Parse <xmlfile>");
}
public static void main(String[] args) throws Exception {
try {
filename = args[0];
} catch (ArrayIndexOutOfBoundsException aioobe){
printUsage();
System.exit(0);
}
//
// 获取输入工厂
//
XMLInputFactory xmlif = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + xmlif);
//
// 实例化读取器
//
XMLStreamReader xmlr = xmlif.createXMLStreamReader(new FileReader(filename));
System.out.println("READER: " + xmlr + "\n");
//
// 解析 XML
//
while(xmlr.hasNext()){
printEvent(xmlr);
xmlr.next();
}
private static void printEvent(XMLStreamReader xmlr) {
System.out.print("EVENT:["+xmlr.getLocation().getLineNumber()+"]["+
xmlr.getLocation().getColumnNumber()+"] ");
switch (xmlr.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
System.out.print("<");
printName(xmlr);
printNamespaces(xmlr);
printAttributes(xmlr);
System.out.print(">");
break;
case XMLStreamConstants.END_ELEMENT:
System.out.print("</");
printName(xmlr);
System.out.print(">");
break;
case XMLStreamConstants.SPACE:
case XMLStreamConstants.CHARACTERS:
int start = xmlr.getTextStart();
int length = xmlr.getTextLength();
System.out.print(new String(xmlr.getTextCharacters(),
start,
length));
break;
case XMLStreamConstants.PROCESSING_INSTRUCTION:
System.out.print("<?");
if (xmlr.hasText())
System.out.print(xmlr.getText());
System.out.print("?>");
break;
case XMLStreamConstants.CDATA:
System.out.print("<![CDATA[");
start = xmlr.getTextStart();
length = xmlr.getTextLength();
System.out.print(new String(xmlr.getTextCharacters(),
start,
length));
System.out.print("]]>");
break;
case XMLStreamConstants.COMMENT:
System.out.print("<!--");
if (xmlr.hasText())
System.out.print(xmlr.getText());
System.out.print("-->");
break;
case XMLStreamConstants.ENTITY_REFERENCE:
System.out.print(xmlr.getLocalName()+"=");
if (xmlr.hasText())
System.out.print("["+xmlr.getText()+"]");
break;
case XMLStreamConstants.START_DOCUMENT:
System.out.print("<?xml");
System.out.print(" version='"+xmlr.getVersion()+"'");
System.out.print(" encoding='"+xmlr.getCharacterEncodingScheme()+"'");
if (xmlr.isStandalone())
System.out.print(" standalone='yes'");
else
System.out.print(" standalone='no'");
System.out.print("?>");
break;
private static void printName(XMLStreamReader xmlr){
if(xmlr.hasName()){
String prefix = xmlr.getPrefix();
String uri = xmlr.getNamespaceURI();
String localName = xmlr.getLocalName();
printName(prefix,uri,localName);
}
}
private static void printName(String prefix,
String uri,
String localName) {
if (uri != null && !("".equals(uri)) ) System.out.print("['"+uri+"']:");
if (prefix != null) System.out.print(prefix+":");
if (localName != null) System.out.print(localName);
}
private static void printAttributes(XMLStreamReader xmlr){
for (int i=0; i < xmlr.getAttributeCount(); i++) {
printAttribute(xmlr,i);
}
}
private static void printAttribute(XMLStreamReader xmlr, int index) {
String prefix = xmlr.getAttributePrefix(index);
String namespace = xmlr.getAttributeNamespace(index);
String localName = xmlr.getAttributeLocalName(index);
String value = xmlr.getAttributeValue(index);
System.out.print(" ");
printName(prefix,namespace,localName);
System.out.print("='"+value+"'");
}
private static void printNamespaces(XMLStreamReader xmlr){
for (int i=0; i < xmlr.getNamespaceCount(); i++) {
printNamespace(xmlr,i);
}
}
private static void printNamespace(XMLStreamReader xmlr, int index) {
String prefix = xmlr.getNamespacePrefix(index);
String uri = xmlr.getNamespaceURI(index);
System.out.print(" ");
if (prefix == null)
System.out.print("xmlns='"+uri+"'");
else
System.out.print("xmlns:"+prefix+"='"+uri+"'");
}
}
可使用 XMLInputFactory.createXMLStreamReader() 方法实例化基于 XML 文档的 XMLStreamReader 对象,如以下代码摘录所示:
XMLStreamReader xmlr = xmlif.createXMLStreamReader(new FileReader(filename));
在此示例中,xmlif 是 XMLInputFactory 实例。
createXMLStreamReader() 方法的各种签名允许将下列 XML 文档格式作为参数:
<!--[if !supportLists]-->§ <!--[endif]-->java.io.InputStream
<!--[if !supportLists]-->§ <!--[endif]-->java.io.Reader(如示例所示)
<!--[if !supportLists]-->§ <!--[endif]-->javax.xml.transform.Source(在 JAXP API 中指定)
要在解析 XML 文档时确定特定事件类型,请使用 XMLStreamReader.next() 或 XMLStreamReader.getEventType() 方法。next() 方法可读取下一个事件,并返回一个整数(此整数可标识所读取的事件类型);getEventType() 方法只返回标识当前事件类型的整数。XMLStreamReader 的 XMLStreamConstants 超接口可定义事件类型常量,如以下列表所示:
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.ATTRIBUTE
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.CDATA
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.CHARACTERS
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.COMMENT
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.DTD
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.END_DOCUMENT
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.END_ELEMENT
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.ENTITY_DECLARATION
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.ENTITY_REFERENCE
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.NAMESPACE
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.NOTATION_DECLARATION
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.PROCESSING_INSTRUCTION
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.SPACE
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.START_DOCUMENT
<!--[if !supportLists]-->§ <!--[endif]-->XMLStreamConstants.START_ELEMENT
以下示例显示了如何使用 Java case 语句来确定 XMLStreamReader.next() 方法返回的特定事件类型。此示例使用 XMLStreamReader.getEventType() 方法确定由 next() 方法返回的当前事件的整数事件类型。为了简化起见,此示例仅打印已找到的事件,后面的部分显示事件的进一步处理。
switch (xmlr.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
System.out.print("Start Element\n");
break;
case XMLStreamConstants.END_ELEMENT:
System.out.print("End Element\n");
break;
case XMLStreamConstants.SPACE:
System.out.print("Space\n");
break;
case XMLStreamConstants.CHARACTERS:
System.out.print("Characters\n");
break;
case XMLStreamConstants.PROCESSING_INSTRUCTION:
System.out.print("Processing Instrcutions\n");
break;
case XMLStreamConstants.CDATA:
System.out.print("CDATA\n");
break;
case XMLStreamConstants.COMMENT:
System.out.print("Comment\n");
break;
case XMLStreamConstants.DTD:
System.out.print("DTD\n");
break;
case XMLStreamConstants.ENTITY_REFERENCE:
System.out.print("Entity Reference\n");
break;
case XMLStreamConstants.ENTITY_DECLARATION:
System.out.print("Entity Declaration\n");
break;
case XMLStreamConstants.START_DOCUMENT:
System.out.print("Start Document\n");
break;
case XMLStreamConstants.END_DOCUMENT:
System.out.print("End Document\n");
break;
元素的全名包含其前缀、名称空间 URI 和本地名称;一旦确定了当前事件是开始元素还是结束元素,就可以分别使用 XMLStreamReader 接口的 getPrefix()、getNamespaceURI() 和 getLocalName() 方法获取此信息。
例如,假定在此示例程序中开始元素事件的 case 语句如下所示:
case XMLStreamConstants.START_ELEMENT:
System.out.print("<");
printName(xmlr);
printNamespaces(xmlr);
printAttributes(xmlr);
System.out.print(">");
break;
printNamespaces() 和 printAttributes() 方法将在其他部分中讨论。 |
两个本地 printName() 方法可使用 getXXX() 方法,如下:
private static void printName(XMLStreamReader xmlr){
if(xmlr.hasName()){
String prefix = xmlr.getPrefix();
String uri = xmlr.getNamespaceURI();
String localName = xmlr.getLocalName();
printName(prefix,uri,localName);
}
}
private static void printName(String prefix,
String uri,
String localName) {
if (uri != null && !("".equals(uri)) ) System.out.print("['"+uri+"']:");
if (prefix != null) System.out.print(prefix+":");
if (localName != null) System.out.print(localName);
}
一旦确定了当前事件是开始元素、结束元素还是特性,就可以使用 XMLStreamReader 接口的 getAttributeXXX() 方法获取特性的列表及其值。
只能将 getAttributeXXX() 方法用于开始元素、结束元素和特性事件;如果尝试在其他任何事件类型上执行这些方法,将引发 java.lang.IllegalStateException。 |
可使用 getAttributeCount() 方法返回当前元素的特性数目,并在迭代特性列表的循环中使用此计数。此方法的计数中不包含名称空间。其他 getAttributeXXX() 方法可返回特定特性的前缀、名称空间 URI、本地名称和值。
例如,假定此示例程序的开始元素事件的 case 语句如下所示:
case XMLStreamConstants.START_ELEMENT:
System.out.print("<");
printName(xmlr);
printNamespaces(xmlr);
printAttributes(xmlr);
System.out.print(">");
break;
printName() 和 printNamespaces() 方法将在其他部分中讨论。 |
以下本地 printAttributes() 方法显示了一种迭代特性列表的方法;由于特性索引基于零,因此 for 循环将从 0 开始:
private static void printAttributes(XMLStreamReader xmlr){
for (int i=0; i < xmlr.getAttributeCount(); i++) {
printAttribute(xmlr,i);
}
}
以下本地 printAttribute() 方法显示了如何打印出特定特性的所有信息:
private static void printAttribute(XMLStreamReader xmlr, int index) {
String prefix = xmlr.getAttributePrefix(index);
String namespace = xmlr.getAttributeNamespace(index);
String localName = xmlr.getAttributeLocalName(index);
String value = xmlr.getAttributeValue(index);
System.out.print(" ");
printName(prefix,namespace,localName);
System.out.print("='"+value+"'");
}
printName() 方法在获取元素的全名中描述。
一旦确定了当前事件是开始元素、结束元素还是名称空间,就可以使用 XMLStreamReader 接口的 getNamespaceXXX() 方法获取为事件声明的名称空间的列表。
只能将 getNamespaceXXX() 方法用于开始元素、结束元素和名称空间事件;如果尝试在其他任何事件类型上执行这些方法,将引发 java.lang.IllegalStateException。 |
可使用 getNamespaceCount() 方法返回为当前事件声明的名称空间数目,并在迭代列表的循环中使用此计数。如果当前事件是结束元素,此计数则指将要超出范围的名称空间的数目。其他 getNamespaceXXX() 方法可返回特定名称空间的前缀和名称空间 URI。
例如,假定此示例程序的开始元素事件的 case 语句如下所示:
case XMLStreamConstants.START_ELEMENT:
System.out.print("<");
printName(xmlr);
printNamespaces(xmlr);
printAttributes(xmlr);
System.out.print(">");
break;
printName() 和 printAttributes() 方法将在其他部分中讨论。 |
以下本地 printNamespaces() 方法显示一种迭代开始元素名称空间列表的方法;由于名称空间索引基于零,故 for 循环从 0 开始:
private static void printNamespaces(XMLStreamReader xmlr){
for (int i=0; i < xmlr.getNamespaceCount(); i++) {
printNamespace(xmlr,i);
}
}
以下的本地 printNamespace() 方法显示如何打印特定名称空间的所有信息:
private static void printNamespace(XMLStreamReader xmlr, int index) {
String prefix = xmlr.getNamespacePrefix(index);
String uri = xmlr.getNamespaceURI(index);
System.out.print(" ");
if (prefix == null)
System.out.print("xmlns='"+uri+"'");
else
System.out.print("xmlns:"+prefix+"='"+uri+"'");
}
getNamespacePrefix() 方法为默认名称空间声明返回 null。
XMLStreamReader 接口包含各种 getTextXXX() 方法,以便从注释和 CDATA 之类的事件获取文本数据。
使用 getTextStart() 方法获取存储当前文本事件第一个字符的文本字符数组的偏移量。使用 getTextLength() 方法获取文本字符数组中字符序列的长度。最后,使用 getTextCharacters() 方法返回当前事件的字符数组。字符数组仅包含有关当前事件的文本信息,一旦调用 next() 方法读取输入流的下一个事件,字符数组将用新信息来填写。
case XMLStreamConstants.CDATA:
System.out.print("<![CDATA[");
start = xmlr.getTextStart();
length = xmlr.getTextLength();
System.out.print(new String(xmlr.getTextCharacters(),
start,
length));
System.out.print("]]>");
break;
如果首先要检查字符事件实际上具有文本,请使用 hasText() 方法,如以下示例所示:
case XMLStreamConstants.COMMENT:
System.out.print("<!--");
if (xmlr.hasText())
System.out.print(xmlr.getText());
System.out.print("-->");
break;
StAX API 的 Location 接口提供了获取事件位置信息的方法,如行号或列号,以及正在解析的 XML 的公共 ID 和系统 ID。使用 XMLStreamReader 接口的 getLocation() 方法返回当前事件的 Location 对象,如以下示例所示:
System.out.print("EVENT:["+xmlr.getLocation().getLineNumber()+"]["+
xmlr.getLocation().getColumnNumber()+"] ");
在完成使用后,明确关闭 XMLStreamReader 是一个良好的编程实践,这样做可以释放资源。要关闭读取器,请使用 XMLStreamReader.close() 方法,如以下示例所示:
用 XMLStreamWriter 接口生成 XML:典型步骤
下列过程描述使用 StAX 游标 API 的 XMLStreamWriter 接口生成新 XML 文档的典型步骤。
<!--[if !supportLists]-->1. <!--[endif]-->导入 javax.xml.stream.* 类。
<!--[if !supportLists]-->2. <!--[endif]-->使用 XMLOutputFactory.newInstance() 方法来实例化 XMLOutputFactory,如下列代码摘录所示:
XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
有关可以设置的属性列表的信息,请参阅为 XMLOutputFactory 接口定义的属性。
<!--[if !supportLists]-->3. <!--[endif]-->使用 XMLOutputFactory.createXMLStreamWriter() 方法实例化 XMLStreamWriter 对象,为其传送文件名或将包含 XML 的对象。
有关详细信息,请参阅获取 XMLStreamWriter 对象。
<!--[if !supportLists]-->4. <!--[endif]-->将 XML 声明添加到输出。将 XML 声明添加到输出流。
<!--[if !supportLists]-->5. <!--[endif]-->将标准 XML 对象,如开始元素、注释和字符添加到输出。请参阅将标准 XML 事件添加到输出流。
<!--[if !supportLists]-->6. <!--[endif]-->将特性和名称空间声明添加到开始元素。请参阅将特性和名称空间声明添加到开始元素。
<!--[if !supportLists]-->7. <!--[endif]-->关闭输出流。请参阅关闭输出流。
以下示例显示一个简单程序,此程序使用 StAX 的 XMLStreamWriter 接口生成 XML 文档。
程序首先创建 XMLStreamWriter 的实例,指定将输出写入当前目录的 outFile.xml 文件。然后使用各种 writeXXX() 方法生成如下的 XML 文件:
<?xml version='1.0' encoding='utf-8'?>
<!-- 这是注释 -->
<person xmlns:one="http://namespaceOne" gender="f">
<one:name hair="pigtails" freckles="yes">Pippi Longstocking</one:name>
</person>
XMLStreamWriter 接口并不检查 XML 文档的格式是否标准,确保格式的标准(例如每个开始元素都有一个相应的结束元素等)是编程人员的职责。此示例还显示如何使用 writeCharacters("\n") 方法,将新行添加到输出,以便使写入文本文件时 XML 的可读性更好。
import java.io.FileOutputStream;
import java.util.Iterator;
import javax.xml.stream.*;
import javax.xml.namespace.QName;
/**
* 此简单示例说明如何
* 使用 XMLStreamWriter 类生成 XML。
*
* 生成的 XML 文件如下所示:
*
* <?xml version='1.0' encoding='utf-8'?>
*
* <!-- 这是注释 -->
* <person xmlns:one="http://namespaceOne" gender="f">
* <one:name hair="pigtails" freckles="yes">Pippi Longstocking</one:name>
* </person>
*
*
* @作者版权所有 (c) 2003 BEA Systems。保留所有权利。
*/
public static void main(String args[]) throws Exception {
//
// 获取输出工厂
//
XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
System.out.println("FACTORY: " + xmlof);
//
// 实例化编写器
//
XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(new FileOutputStream ("outFile.xml"));
System.out.println("READER: " + xmlw + "\n");
// 编写默认的 XML 声明
xmlw.writeStartDocument();
xmlw.writeCharacters("\n");
xmlw.writeCharacters("\n");
// 编写注释
xmlw.writeComment("this is a comment");
xmlw.writeCharacters("\n");
// 编写有一个“gender”特性的根元素“person”
xmlw.writeStartElement("person");
xmlw.writeNamespace("one", "http://namespaceOne");
xmlw.writeAttribute("gender","f");
xmlw.writeCharacters("\n");
// 编写有某些内容和两个特性的“name”元素
xmlw.writeCharacters(" ");
xmlw.writeStartElement("one", "name", "http://namespaceOne");
xmlw.writeAttribute("hair","pigtails");
xmlw.writeAttribute("freckles","yes");
xmlw.writeCharacters("Pippi Longstocking");
// 结束“name”元素
xmlw.writeEndElement();
xmlw.writeCharacters("\n");
// 结束“person”元素
xmlw.writeEndElement();
// 结束 XML 文档
xmlw.writeEndDocument();
// 关闭 XMLStreamWriter 以释放资源
xmlw.close();
使用 XMLOutputFactory.createXMLStreamWriter() 方法来实例化来实例化基于 XML 文档的 XMLStreamWriter 对象,如下列代码摘录所示:
XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(new FileOutputStream ("outFile.xml"));
在本例中,xmlof 是 XMLOutputFactory 实例。
createXMLStreamWriter() 方法的各种签名允许将下列 XML 文档格式作为参数:
<!--[if !supportLists]-->§ <!--[endif]-->java.io.OutputStream (如示例所示)
<!--[if !supportLists]-->§ <!--[endif]-->java.io.Writer
<!--[if !supportLists]-->§ <!--[endif]-->javax.xml.transform.Result(在 JAXP API 中指定)
可使用 XMLStreamWriter.writeStartDocument() 方法,将 XML 声明作为 XML 文档的第一行进行添加,如以下代码摘录所示:
<?xml version='1.0' encoding='utf-8'?>
如果要指定不同编码或 XML 版本,请使用 writeStartDocument() 方法的下列特性:
<!--[if !supportLists]-->§ <!--[endif]-->writeStartDocument(java.lang.String version)
<!--[if !supportLists]-->§ <!--[endif]-->writeStartDocument(java.lang.String encoding, java.lang.String version)
通过 writeStartDocument() 方法设置编码并不会设置底层输出的实际编码;它仅指定为 XML 声明的 encoding 特性写入的值。要实际设置输出的编码,必须在使用相应的 XMLOutputFactory.createXMLStreamWriter() 方法创建 XMLStreamWriter 实例时指定 encoding 参数。
可使用 XMLStreamWriter.writeXXX() 方法,将标准 XML 事件,如开始元素、结束元素、注释、CDATA 和实体引用等添加到输出流。XXX 指特定的事件,如 writeStartElement()、writeEndElement()、writeComment() 和 writeCData() 等。可通过将名称和文本数据作为一个 String 进行传送来创建大多数元素。
XMLStreamWriter 接口不会验证数据,也不检查文档格式是否标准,确保格式标准(例如每个开始元素都有一个相应的结束元素等)是编程人员的职责。编程人员还需要确保开始和结束元素事件嵌套的正确性。要在写入文本文件时使输出的 XML 更便于人员阅读,请使用 writeCharacters("\n") 方法在适当的位置添加新的行。
<!-- 这是注释 -->
<name>Jane Doe</name>
xmlw.writeComment("This is a comment");
xmlw.writeCharacters("\n");
xmlw.writeStartElement("name");
xmlw.writeCharacters("Jane Doe");
xmlw.writeEndElement();
xmlw.writeCharacters("\n");
可紧随开始元素事件使用 writeAttribute() 方法将特性添加到开始元素。可以为特性指定前缀及其绑定到的 URI,或不指定任何前缀。
xmlw.writeStartElement("person");
xmlw.writeAttribute("gender","f");
xmlw.writeCharacters("\n");
可使用 writeNamespace() 方法将名称空间写入输出流。编程人员负责确保当前事件(例如开始元素)允许名称空间的写入;如果当前事件不允许名称空间的写入,将引发 javax.xml.stream.XMLStreamException。可使用其他 writeXXX() 方法的相应特性指定事件的前缀及其绑定到的 URI。
例如,下列 XML 输出显示了 <person> 元素的名称空间声明,以及为 <one> 子元素指定的 one 前缀:
<person xmlns:one="http://namespaceOne" gender="f">
<one:name hair="pigtails" freckles="yes">Pippi Longstocking</one:name>
</person>
// 编写有一个“gender”特性的根元素“person”
xmlw.writeStartElement("person");
xmlw.writeNamespace("one", "http://namespaceOne");
xmlw.writeAttribute("gender","f");
xmlw.writeCharacters("\n");
// 编写有某些内容和两个特性的“name”元素
xmlw.writeCharacters(" ");
xmlw.writeStartElement("one", "name", "http://namespaceOne");
xmlw.writeAttribute("hair","pigtails");
xmlw.writeAttribute("freckles","yes");
xmlw.writeCharacters("Pippi Longstocking");
// 结束“name”元素
xmlw.writeEndElement();
xmlw.writeCharacters("\n");
// 结束“person”元素
xmlw.writeEndElement();
完成 XMLStreamWriter 的使用后明确将其关闭以释放资源是一个很好的编程实践。要关闭编写器,请使用 XMLStreamReader.close() 方法,如以下示例所示:
// 关闭 XMLStreamWriter 以释放资源
xmlw.close();
下表列出在使用 XMLInputFactory 生成 XMLStreamReader 或 XMLEventReader 对象时,可以设置的标准属性。
下表所有属性的前面均以 javax.xml.stream 开始,如 javax.xml.stream.isValidating。
|
下表列出在使用 XMLOutputFactory 生成 XMLStreamWriter 或 XMLEventWriter 对象时,可以设置的标准属性。
下表所有属性的前面均以 javax.xml.stream 开始,如 javax.xml.stream.isValidating。
|