Java 中文官方教程 2022 版(四十)(2)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Java 中文官方教程 2022 版(四十)

Java 中文官方教程 2022 版(四十)(1)https://developer.aliyun.com/article/1488164

资源、命名空间和错误

StAX 规范处理资源解析、属性和命名空间,以及错误和异常,如下所述。

资源解析

XMLResolver接口提供了在 XML 处理期间解析资源的方法。应用程序在XMLInputFactory上设置接口,然后该工厂实例创建的所有处理器都设置该接口。

属性和命名空间

属性由 StAX 处理器使用游标接口中的查找方法和字符串以及迭代器接口中的AttributeNamespace事件报告。请注意,命名空间被视为属性,尽管在游标和迭代器 API 中,命名空间与属性分开报告。还要注意,命名空间处理对于 StAX 处理器是可选的。有关命名空间绑定和可选命名空间处理的完整信息,请参阅 StAX 规范。

错误报告和异常处理

所有致命错误都通过javax.xml.stream.XMLStreamException接口报告。所有非致命错误和警告都使用javax.xml.stream.XMLReporter接口报告。

读取 XML 流

正如在本课程前面所描述的,使用 StAX 处理器读取 XML 流的方式——更重要的是,您得到的内容——取决于您是使用 StAX 游标 API 还是事件迭代器 API,这两个部分描述了如何使用这两个 API 读取 XML 流。

使用 XMLStreamReader

StAX 游标 API 中的XMLStreamReader接口只允许您以向前方向读取 XML 流或文档,每次只能读取信息集中的一个项目。以下方法可用于从流中提取数据或跳过不需要的事件:

  • 获取属性的值
  • 读取 XML 内容
  • 确定一个元素是否有内容或为空
  • 获取对属性集合的索引访问
  • 获取对命名空间集合的索引访问
  • 获取当前事件的名称(如果适用)
  • 获取当前事件的内容(如果适用)

XMLStreamReader的实例在任何时候都有一个当前事件,其方法在其上操作。当您在流上创建一个XMLStreamReader实例时,初始当前事件是START_DOCUMENT状态。然后可以使用XMLStreamReader.next方法来跳到流中的下一个事件。

读取属性、属性和命名空间

XMLStreamReader.next方法加载流中下一个事件的属性。然后,您可以通过调用XMLStreamReader.getLocalNameXMLStreamReader.getText方法来访问这些属性。

XMLStreamReader游标位于StartElement事件上时,它读取事件的名称和任何属性,包括命名空间。可以使用索引值访问事件的所有属性,并且还可以通过命名空间 URI 和本地名称查找。但请注意,只有当前StartEvent上声明的命名空间可用;之前声明的命名空间不会被保留,重新声明的命名空间也不会被移除。

XMLStreamReader 方法

XMLStreamReader提供以下方法来检索有关命名空间和属性的信息:

int getAttributeCount();
String getAttributeNamespace(int index);
String getAttributeLocalName(int index);
String getAttributePrefix(int index);
String getAttributeType(int index);
String getAttributeValue(int index);
String getAttributeValue(String namespaceUri, String localName);
boolean isAttributeSpecified(int index);

也可以使用三种额外的方法访问命名空间:

int getNamespaceCount();
String getNamespacePrefix(int index);
String getNamespaceURI(int index);

实例化一个 XMLStreamReader

这个示例取自 StAX 规范,展示了如何实例化一个输入工厂,创建一个读取器,并遍历 XML 流的元素:

XMLInputFactory f = XMLInputFactory.newInstance();
XMLStreamReader r = f.createXMLStreamReader( ... );
while(r.hasNext()) {
    r.next();
}

使用 XMLEventReader

StAX 事件迭代器 API 中的XMLEventReader API 提供了将 XML 流中的事件映射到可以自由重用的分配的事件对象的方法,并且 API 本身可以扩展以处理自定义事件。

XMLEventReader提供了四种方法来迭代解析 XML 流:

  • next:返回流中的下一个事件
  • nextEvent:返回下一个类型化的 XMLEvent
  • hasNext:如果流中有更多事件要处理,则返回 true
  • peek:返回事件但不迭代到下一个事件

例如,以下代码片段说明了XMLEventReader方法声明:

package javax.xml.stream;
import java.util.Iterator;
public interface XMLEventReader extends Iterator {
    public Object next();
    public XMLEvent nextEvent() throws XMLStreamException;
    public boolean hasNext();
    public XMLEvent peek() throws XMLStreamException;
    // ...
}

要读取流上的所有事件然后打印它们,您可以使用以下方法:

while(stream.hasNext()) {
    XMLEvent event = stream.nextEvent();
    System.out.print(event);
}

读取属性

您可以从其关联的javax.xml.stream.StartElement中访问属性,如下所示:

public interface StartElement extends XMLEvent {
    public Attribute getAttributeByName(QName name);
    public Iterator getAttributes();
}

您可以使用StartElement接口上的getAttributes方法来使用在该StartElement上声明的所有属性的Iterator

读取命名空间

与读取属性类似,命名空间是通过调用StartElement接口上的getNamespaces方法创建的Iterator来读取的。仅返回当前StartElement的命名空间,并且应用程序可以通过使用StartElement.getNamespaceContext来获取当前命名空间上下文。

写入 XML 流

StAX 是一个双向 API,游标和事件迭代器 API 都有自己的一套接口用于写入 XML 流。与读取流的接口一样,写入器 API 对于游标和事件迭代器之间存在显著差异。以下部分描述了如何使用这些 API 之一来写入 XML 流。

使用 XMLStreamWriter

StAX 游标 API 中的XMLStreamWriter接口允许应用程序写回到 XML 流或创建全新的流。XMLStreamWriter 具有让您执行以下操作的方法:

  • 写入格式良好的 XML
  • 刷新或关闭输出
  • 写入限定名称

请注意,XMLStreamWriter实现不需要对输入执行格式良好性或有效性检查。虽然一些实现可能执行严格的错误检查,但其他可能不会。您实现的规则适用于XMLOutputFactory类中定义的属性。

使用writeCharacters方法转义字符,如&<>"。绑定前缀可以通过传递前缀的实际值,使用setPrefix方法,或设置默认命名空间声明的属性来处理。

以下示例取自 StAX 规范,展示了如何实例化输出工厂,创建写入器并写入 XML 输出:

XMLOutputFactory output = XMLOutputFactory.newInstance();
XMLStreamWriter writer = output.createXMLStreamWriter( ... );
writer.writeStartDocument();
writer.setPrefix("c","http://c");
writer.setDefaultNamespace("http://c");
writer.writeStartElement("http://c","a");
writer.writeAttribute("b","blah");
writer.writeNamespace("c","http://c");
writer.writeDefaultNamespace("http://c");
writer.setPrefix("d","http://c");
writer.writeEmptyElement("http://c","d");
writer.writeAttribute("http://c", "chris","fry");
writer.writeNamespace("d","http://c");
writer.writeCharacters("Jean Arp");
writer.writeEndElement();
writer.flush();

此代码生成以下 XML(新行不是规范性的):

<?xml version=’1.0’ encoding=’utf-8’?>
<a b="blah"  >
<d:d d:chris="fry" />Jean Arp</a>

使用 XMLEventWriter

StAX 事件迭代器 API 中的XMLEventWriter接口允许应用程序写回到 XML 流或创建全新的流。此 API 可以扩展,但主要 API 如下:

public interface XMLEventWriter {
    public void flush() throws XMLStreamException;
    public void close() throws XMLStreamException;
    public void add(XMLEvent e) throws XMLStreamException;
    // ... other methods not shown.
}

XMLEventWriter的实例是由XMLOutputFactory的实例创建的。流事件被迭代地添加,一旦添加到事件写入器实例后,事件就不能被修改。

属性、转义字符、绑定前缀

StAX 实现需要缓冲最后一个StartElement,直到在流中添加或遇到除AttributeNamespace之外的事件。这意味着当您向流中添加AttributeNamespace时,它会附加到当前的StartElement事件。

您可以使用Characters方法转义字符如&<>"

setPrefix(...) 方法可用于显式绑定输出时使用的前缀,而 getPrefix(...) 方法可用于获取当前前缀。请注意,默认情况下,XMLEventWriter 会将命名空间绑定添加到其内部命名空间映射中。前缀在绑定它们的事件对应的 EndElement 后会失效。

Oracle 的流式 XML 解析器实现

原文:docs.oracle.com/javase/tutorial/jaxp/stax/parser.html

应用服务器 9.1 包含 Sun 微系统的 JSR 173(StAX)实现,称为 Sun Java 流式 XML 解析器(简称为流式 XML 解析器)。流式 XML 解析器是一个高速、非验证的、符合 W3C XML 1.0 和 Namespace 1.0 标准的流式 XML 拉取解析器,构建在 Xerces2 代码库之上。

在 Sun 的流式 XML 解析器实现中,Xerces2 的底层,特别是 Scanner 和相关类,已经重新设计为拉取方式。除了底层的更改外,流式 XML 解析器还包括额外的与 StAX 相关的功能和许多性能增强改进。流式 XML 解析器实现在 appserv-ws.jarjavaee.jar 文件中,这两个文件位于 install_dir/lib/ 目录中。

JAXP 参考实现中包含了 StAX 代码示例,位于 INSTALL_DIR/jaxp-version/samples/stax 目录中,展示了 Sun 的流式 XML 解析器实现的工作原理。这些示例在 示例代码 中有描述。

在继续使用示例代码之前,有两个关于流式 XML 解析器的方面需要注意:

  • 报告 CDATA 事件
  • 流式 XML 解析器工厂实现

下面将讨论这些主题。

报告 CDATA 事件

流式 XML 解析器中实现的 javax.xml.stream.XMLStreamReader 不报告 CDATA 事件。如果您有一个需要接收此类事件的应用程序,请配置 XMLInputFactory 来设置以下特定于实现的 report-cdata-event 属性:

XMLInputFactory factory = XMLInptuFactory.newInstance();
factory.setProperty("report-cdata-event", Boolean.TRUE);

流式 XML 解析器工厂实现

大多数应用程序不需要知道工厂实现类名。对于大多数应用程序,只需将 javaee.jarappserv-ws.jar 文件添加到类路径即可,因为这两个 jar 文件在 META-INF/services 目录下提供了各种流式 XML 解析器属性的工厂实现类名,例如 javax.xml.stream.XMLInputFactoryjavax.xml.stream.XMLOutputFactoryjavax.xml.stream.XMLEventFactory,这是应用程序请求工厂实例时查找操作的第三步。有关查找机制的更多信息,请参阅 XMLInputFactory.newInstance 方法的 Javadoc。

但是,在某些情况下,应用程序可能希望了解工厂实现类名并显式设置属性。这些情况可能包括类路径中存在多个 JSR 173 实现,应用程序希望选择其中一个,也许是性能更好的一个,包含了关键的错误修复,或类似情况。

如果一个应用程序设置了SystemProperty,那么这是查找操作的第一步,因此获取工厂实例相对于其他选项来说会更快;例如:

javax.xml.stream.XMLInputFactory -->
  com.sun.xml.stream.ZephyrParserFactory
javax.xml.stream.XMLOutputFactory -->
  com.sun.xml.stream.ZephyrWriterFactor
javax.xml.stream.XMLEventFactory -->
  com.sun.xml.stream.events.ZephyrEventFactory

示例代码

原文:docs.oracle.com/javase/tutorial/jaxp/stax/example.html

本节逐步介绍了 JAXP 参考实现包中包含的示例 StAX 代码。本节中使用的所有示例目录均位于INSTALL_DIR/jaxp-version/samples/stax目录中。

本节涵盖的主题如下:

  • 示例代码组织
  • 示例 XML 文档
  • 游标示例
  • 游标到事件示例
  • 事件示例
  • 过滤器示例
  • 读写示例
  • 写入示例

示例代码组织

INSTALL_DIR/jaxp-version/samples/stax目录包含六个 StAX 示例目录:

  • 游标示例cursor目录包含CursorParse.java,演示如何使用XMLStreamReader(游标)API 读取 XML 文件。
  • 游标到事件示例cursor2event目录包含CursorApproachEventObject.java,演示应用程序如何在使用游标 API 时将信息作为XMLEvent对象获取。
  • 事件示例event目录包含EventParse.java,演示如何使用XMLEventReader(事件迭代器)API 读取 XML 文件。
  • 过滤器示例filter目录包含MyStreamFilter.java,演示如何使用 StAX 流过滤器 API。在此示例中,过滤器仅接受StartElementEndElement事件,并过滤掉其余事件。
  • 读写示例readnwrite目录包含EventProducerConsumer.java,演示了如何使用 StAX 生产者/消费者机制同时读取和写入 XML 流。
  • 写入示例writer目录包含CursorWriter.java,演示如何使用XMLStreamWriter以编程方式编写 XML 文件。

除了写入示例外,本节中的所有 StAX 示例均使用示例 XML 文档BookCatalog.xml

示例 XML 文档

大多数 StAX 示例类使用的示例 XML 文档BookCatalog.xml是一个基于常见BookCatalogue命名空间的简单图书目录。BookCatalog.xml的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<BookCatalogue >
<Book>
    <Title>Yogasana Vijnana: the Science of Yoga</Title>
    <author>Dhirendra Brahmachari</Author>
    <Date>1966</Date>
    <ISBN>81-40-34319-4</ISBN>
    <Publisher>Dhirendra Yoga Publications</Publisher>
    <Cost currency="INR">11.50</Cost>
</Book>
<Book>
    <Title>The First and Last Freedom</Title>
    <Author>J. Krishnamurti</Author>
    <Date>1954</Date>
    <ISBN>0-06-064831-7</ISBN>
    <Publisher>Harper &amp; Row</Publisher>
    <Cost currency="USD">2.95</Cost>
</Book>
</BookCatalogue>

游标示例

位于INSTALL_DIR/jaxp-version/samples/stax/cursor/目录中,CursorParse.java演示了如何使用 StAX 游标 API 读取 XML 文档。在游标示例中,应用程序通过调用next()指示解析器读取 XML 输入流中的下一个事件。

请注意,next()只返回与解析器所处位置对应的整数常量。应用程序需要调用相关函数以获取与底层事件相关的更多信息。

您可以将这种方法想象成虚拟游标在 XML 输入流中移动。当虚拟游标位于特定事件时,可以调用各种访问器方法。

逐个事件地进行步进

在这个示例中,客户端应用程序通过在解析器上调用next方法来拉取 XML 流中的下一个事件;例如:

try {
    for (int i = 0 ; i < count ; i++) {
        // pass the file name.. all relative entity
        // references will be resolved against this 
        // as base URI.
        XMLStreamReader xmlr = xmlif.createXMLStreamReader(filename,
                                   new FileInputStream(filename));
        // when XMLStreamReader is created, 
        // it is positioned at START_DOCUMENT event.
        int eventType = xmlr.getEventType();
        printEventType(eventType);
        printStartDocument(xmlr);
        // check if there are more events 
        // in the input stream
        while(xmlr.hasNext()) {
            eventType = xmlr.next();
            printEventType(eventType);
            // these functions print the information 
            // about the particular event by calling 
            // the relevant function
            printStartElement(xmlr);
            printEndElement(xmlr);
            printText(xmlr);
            printPIData(xmlr);
            printComment(xmlr);
        }
    }
}

请注意,next只是返回与当前游标位置下的事件对应的整数常量。应用程序调用相关函数以获取与底层事件相关的更多信息。当游标位于特定事件时,可以调用各种访问器方法。

返回字符串表示形式

因为next方法只返回与底层事件类型对应的整数,通常需要将这些整数映射到事件的字符串表示形式;例如:

public final static String getEventTypeString(int eventType) {
    switch (eventType) {
        case XMLEvent.START_ELEMENT:
            return "START_ELEMENT";
        case XMLEvent.END_ELEMENT:
            return "END_ELEMENT";
        case XMLEvent.PROCESSING_INSTRUCTION:
            return "PROCESSING_INSTRUCTION";
        case XMLEvent.CHARACTERS:
            return "CHARACTERS";
        case XMLEvent.COMMENT:
            return "COMMENT";
        case XMLEvent.START_DOCUMENT:
            return "START_DOCUMENT";
        case XMLEvent.END_DOCUMENT:
            return "END_DOCUMENT";
        case XMLEvent.ENTITY_REFERENCE:
            return "ENTITY_REFERENCE";
        case XMLEvent.ATTRIBUTE:
            return "ATTRIBUTE";
        case XMLEvent.DTD:
            return "DTD";
        case XMLEvent.CDATA:
            return "CDATA";
        case XMLEvent.SPACE:
            return "SPACE";
    }
    return "UNKNOWN_EVENT_TYPE , " + eventType;
}

运行游标示例

  1. 要编译和运行游标示例,在终端窗口中,转到INSTALL_DIR/jaxp-version/samples/目录,并输入以下内容:
javac stax/cursor/*.java
  1. BookCatalogue.xml文件上运行CursorParse示例,使用以下命令。
    CursorParse将打印出BookCatalogue.xml文件的每个元素。
java stax/event/CursorParse stax/data/BookCatalogue.xml

游标到事件示例

位于tut-install/javaeetutorial5/examples/stax/cursor2event/目录中,CursorApproachEventObject.java演示了如何在使用游标 API 时获取XMLEvent对象返回的信息。

这里的想法是,游标 API 的XMLStreamReader返回与特定事件对应的整数常量,而事件迭代器 API 的XMLEventReader返回不可变且持久的事件对象。 XMLStreamReader更有效率,但XMLEventReader更易于使用,因为与特定事件相关的所有信息都封装在返回的XMLEvent对象中。然而,事件方法的缺点是为每个事件创建对象的额外开销,这既消耗时间又消耗内存。

有了这个想法,即使使用游标 API,也可以使用XMLEventAllocator来获取事件信息作为XMLEvent对象。

实例化一个 XMLEventAllocator

第一步是创建一个新的XMLInputFactory并实例化一个XMLEventAllocator

XMLInputFactory xmlif = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + xmlif);
xmlif.setEventAllocator(new XMLEventAllocatorImpl());
allocator = xmlif.getEventAllocator();
XMLStreamReader xmlr = xmlif.createXMLStreamReader(filename,
                           new FileInputStream(filename));

创建一个事件迭代器

下一步是创建一个事件迭代器:

int eventType = xmlr.getEventType();
while (xmlr.hasNext()) {
    eventType = xmlr.next();
    // Get all "Book" elements as XMLEvent object
    if (eventType == XMLStreamConstants.START_ELEMENT 
        && xmlr.getLocalName().equals("Book")) {
        // get immutable XMLEvent
        StartElement event = getXMLEvent(xmlr).asStartElement();
        System.out.println ("EVENT: " + event.toString());
    }
}

创建分配器方法

最后一步是创建XMLEventAllocator方法:

private static XMLEvent getXMLEvent(XMLStreamReader reader)
    throws XMLStreamException {
    return allocator.allocate(reader);
}

运行游标到事件示例

  1. 要编译和运行游标到事件示例,在终端窗口中,转到INSTALL_DIR/jaxp-version/samples/目录,并输入以下内容:
javac -classpath ../lib/jaxp-ri.jar stax/cursor2event/*.java
  1. BookCatalogue.xml文件上运行CursorApproachEventObject示例,使用以下命令。
java stax/cursor2event/CursorApproachEventObject stax/data/BookCatalogue.xml
  1. CursorApproachEventObject将打印出BookCatalogue.xml文件中定义的事件列表。

事件示例

位于INSTALL_DIR/jaxp-version/samples/stax/event/目录中,EventParse.java演示了如何使用 StAX 事件 API 读取 XML 文档。

创建一个输入工厂

第一步是创建一个新的XMLInputFactory实例:

XMLInputFactory factory = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + factory);

创建一个事件读取器

下一步是创建一个 XMLEventReader 实例:

XMLEventReader r = factory.createXMLEventReader
                       (filename, new FileInputStream(filename));

Java 中文官方教程 2022 版(四十)(3)https://developer.aliyun.com/article/1488168

相关文章
|
11天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
2月前
|
Java 开发者 UED
【实战宝典】Java异常处理大师级教程:throws关键字,让异常声明成为你的专属标签!
【实战宝典】Java异常处理大师级教程:throws关键字,让异常声明成为你的专属标签!
48 3
|
5天前
|
Java 数据库连接 编译器
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
|
8天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
本系列教程笔记详细讲解了Kotlin语法,适合希望深入了解Kotlin的开发者。对于需要快速学习Kotlin的小伙伴,推荐查看“简洁”系列教程。本篇笔记重点介绍了Kotlin与Java混编的技巧,包括代码转换、类调用、ProGuard问题、Android库开发建议以及相互调用时的注意事项。
14 3
|
10天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
18 3
|
11天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
17天前
|
消息中间件 存储 JSON
rabbitmq基础教程(ui,java,springamqp)
本文提供了RabbitMQ的基础教程,包括如何使用UI创建队列和交换机、Java代码操作RabbitMQ、Spring AMQP进行消息发送和接收,以及如何使用不同的交换机类型(fanout、direct、topic)进行消息路由。
13 0
rabbitmq基础教程(ui,java,springamqp)
|
18天前
|
存储 前端开发 Java
Java后端如何进行文件上传和下载 —— 本地版(文末配绝对能用的源码,超详细,超好用,一看就懂,博主在线解答) 文件如何预览和下载?(超简单教程)
本文详细介绍了在Java后端进行文件上传和下载的实现方法,包括文件上传保存到本地的完整流程、文件下载的代码实现,以及如何处理文件预览、下载大小限制和运行失败的问题,并提供了完整的代码示例。
117 1
|
9天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(2)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(2)
|
9天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(1)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(1)