原文: https://howtodoinjava.com/xml/read-xml-stax-parser-cursor-iterator/
学习使用 Java StAX 解析器解析和读取 XML 文件。 StAX(用于 XML 的流 API)提供了两种解析 XML 的方法,即基于游标的 API 和基于迭代器的 API 。
1)StAX 解析器
就像 SAX 解析器一样, StAX API 设计用于解析 XML 流。 区别在于:
- StAX 是“
pull” API。 SAX 是“push” API。 - StAX 可以进行 XML 读取和写入。 SAX 只能读取 XML。
StAX 是拉取风格 API 。 这意味着您必须自己将 StAX 解析器从 XML 文件中的一个项目移动到另一个项目,就像使用标准Iterator或 JDBC ResultSet一样。 然后,您可以通过 StAX 解析器访问 XML 文件中遇到的每个此类“项目”的 XML 信息。
游标与迭代器
- 在读取 XML 文档时,迭代器读取器从其
nextEvent()调用中返回 XML 事件对象。 此事件提供有关您遇到的 XML 标签类型(元素,文本,注释等)的信息。 收到的事件是不可变的,因此您可以传递应用以安全地对其进行处理。 ```java XMLEventReader reader = …;
while(reader.hasNext()){ XMLEvent event = reader.nextEvent();
if(event.getEventType() == XMLEvent.START_ELEMENT){//process data}//... more event types handled here...
}
2.与迭代器不同,游标的工作方式类似于 JDBC 中的`Resultset`。 如果将游标移动到 XML 文档中的下一个元素。 然后,您可以直接在游标上调用方法以获得有关当前事件的更多信息。```javaXMLStreamReader streamReader = ...;while(streamReader.hasNext()){int eventType = streamReader.next();if(eventType == XMLStreamReader.START_ELEMENT){System.out.println(streamReader.getLocalName());}//... more event types handled here...}
2)StAX 迭代器 API 示例
下面给出的 XML 文档演示如何使用基于 StAX 迭代器的 API 读取对象。
XML 文件
<employees><employee id="101"><name>Lokesh Gupta</name><title>Author</title></employee><employee id="102"><name>Brian Lara</name><title>Cricketer</title></employee></employees>
使用 StAX 迭代器读取 XML
要读取文件,我已按照以下步骤编写了程序:
- 创建迭代器并开始接收事件。
- 一旦获得打开的
'employee'标签,请创建一个新的Employee对象。 - 从员工标签读取
id属性,并将其设置为当前的Employee对象。 - 循环到下一个开始标签事件。 这些是
employee标记内的 XML 元素。 读取这些标签内的数据。 将读取的数据设置为当前的Employee对象。 - 继续迭代事件。 当找到
'employee'标签的结束元素事件时,可以说您已经读取了当前employee的数据,因此将当前employee对象添加到employeeList集合中。 - 最后,通过打印
employeeList验证读取的数据。
package com.howtodoinjava.demo.stax;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import javax.xml.namespace.QName;import javax.xml.stream.XMLEventReader;import javax.xml.stream.XMLInputFactory;import javax.xml.stream.XMLStreamException;import javax.xml.stream.events.Attribute;import javax.xml.stream.events.Characters;import javax.xml.stream.events.EndElement;import javax.xml.stream.events.StartElement;import javax.xml.stream.events.XMLEvent;public class ReadXMLExample{public static void main(String[] args) throws FileNotFoundException, XMLStreamException{File file = new File("employees.xml");// Instance of the class which helps on reading tagsXMLInputFactory factory = XMLInputFactory.newInstance();// Initializing the handler to access the tags in the XML fileXMLEventReader eventReader = factory.createXMLEventReader(new FileReader(file));//All read employees objects will be added to this listList<Employee> employeeList = new ArrayList<>();//Create Employee object. It will get all the data using setter methods.//And at last, it will stored in above 'employeeList'Employee employee = null;// Checking the availability of the next tagwhile (eventReader.hasNext()){XMLEvent xmlEvent = eventReader.nextEvent();if (xmlEvent.isStartElement()){StartElement startElement = xmlEvent.asStartElement();//As soo as employee tag is opened, create new Employee objectif("employee".equalsIgnoreCase(startElement.getName().getLocalPart())) {employee = new Employee();}//Read all attributes when start tag is being read@SuppressWarnings("unchecked")Iterator<Attribute> iterator = startElement.getAttributes();while (iterator.hasNext()){Attribute attribute = iterator.next();QName name = attribute.getName();if("id".equalsIgnoreCase(name.getLocalPart())) {employee.setId(Integer.valueOf(attribute.getValue()));}}//Now everytime content tags are found;//Move the iterator and read dataswitch (startElement.getName().getLocalPart()){case "name":Characters nameDataEvent = (Characters) eventReader.nextEvent();employee.setName(nameDataEvent.getData());break;case "title":Characters titleDataEvent = (Characters) eventReader.nextEvent();employee.setTitle(titleDataEvent.getData());break;}}if (xmlEvent.isEndElement()){EndElement endElement = xmlEvent.asEndElement();//If employee tag is closed then add the employee object to list;//and be ready to read next employee dataif("employee".equalsIgnoreCase(endElement.getName().getLocalPart())) {employeeList.add(employee);}}}System.out.println(employeeList); //Verify read data}}//Output:[Employee [id=101, name=Lokesh Gupta, title=Author],Employee [id=102, name=Brian Lara, title=Cricketer]]
3)StAX 游标 API 示例
我将使用基于游标的 API 读取相同的employees.xml文件。
package com.howtodoinjava.demo.stax;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.util.ArrayList;import java.util.List;import javax.xml.stream.XMLInputFactory;import javax.xml.stream.XMLStreamException;import javax.xml.stream.XMLStreamReader;public class ReadXMLExample{public static void main(String[] args) throws FileNotFoundException, XMLStreamException{//All read employees objects will be added to this listList<Employee> employeeList = new ArrayList<>();//Create Employee object. It will get all the data using setter methods.//And at last, it will stored in above 'employeeList'Employee employee = null;File file = new File("employees.xml");XMLInputFactory factory = XMLInputFactory.newInstance();XMLStreamReader streamReader = factory.createXMLStreamReader(new FileReader(file));while(streamReader.hasNext()){//Move to next eventstreamReader.next();//Check if its 'START_ELEMENT'if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT){//employee tag - openedif(streamReader.getLocalName().equalsIgnoreCase("employee")) {//Create new employee object asap tag is openemployee = new Employee();//Read attributes within employee tagif(streamReader.getAttributeCount() > 0) {String id = streamReader.getAttributeValue(null,"id");employee.setId(Integer.valueOf(id));}}//Read name dataif(streamReader.getLocalName().equalsIgnoreCase("name")) {employee.setName(streamReader.getElementText());}//Read title dataif(streamReader.getLocalName().equalsIgnoreCase("title")) {employee.setTitle(streamReader.getElementText());}}//If employee tag is closed then add the employee object to listif(streamReader.getEventType() == XMLStreamReader.END_ELEMENT){if(streamReader.getLocalName().equalsIgnoreCase("employee")) {employeeList.add(employee);}}}//Verify read dataSystem.out.println(employeeList);}}//Output:[Employee [id=101, name=Lokesh Gupta, title=Author],Employee [id=102, name=Brian Lara, title=Cricketer]]
4)总结
因此,在此 StAX 解析器教程中,我们学习了以下内容:
- 什么是基于 XML 流 API 的 StAX 解析器。
- StAX 与 SAX 解析器之间的差异。
- 如何通过示例使用 StAX 迭代器 API 来读取 XML。
- 如何通过示例使用 StAX 游标 API 来读取 XML。
两种 API 都能够解析任何类型的 XML 文档,但是游标 API 比迭代器 API 具有更高的内存效率。 因此,如果您的应用需要更好的性能,请考虑使用基于游标的 API。
将我的问题放在评论部分。
学习愉快!
