企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 使用 Java StAX 解析器读取 XML – 游标和迭代器 API > 原文: [https://howtodoinjava.com/xml/read-xml-stax-parser-cursor-iterator/](https://howtodoinjava.com/xml/read-xml-stax-parser-cursor-iterator/) 学习使用 Java StAX 解析器解析和**读取 XML 文件**。 StAX(用于 XML 的流 API)提供了两种解析 XML 的方法,即**基于游标的 API** 和**基于迭代器的 API** 。 ## 1)StAX 解析器 就像 [SAX 解析器](https://howtodoinjava.com/xml/how-to-parse-an-xml-using-sax-parser-and-defaulthandler/)一样, [StAX API](https://docs.oracle.com/javase/tutorial/jaxp/stax/api.html) 设计用于解析 XML 流。 区别在于: 1. StAX 是“`pull`” API。 SAX 是“`push`” API。 2. StAX 可以进行 XML 读取和写入。 SAX 只能读取 XML。 **StAX 是拉取风格 API** 。 这意味着您必须自己将 StAX 解析器从 XML 文件中的一个项目移动到另一个项目,就像使用标准[`Iterator`](https://howtodoinjava.com/java/collections/how-iterator-works-in-java/)或 JDBC [`ResultSet`](https://howtodoinjava.com/java/jdbc/jdbc-select-query-example/)一样。 然后,您可以通过 StAX 解析器访问 XML 文件中遇到的每个此类“项目”的 XML 信息。 #### 游标与迭代器 1. 在读取 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 文档中的下一个元素。 然后,您可以直接在游标上调用方法以获得有关当前事件的更多信息。 ```java XMLStreamReader 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 文件 ```java <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 要读取文件,我已按照以下步骤编写了程序: 1. 创建迭代器并开始接收事件。 2. 一旦获得打开的`'employee'`标签,请创建一个新的`Employee`对象。 3. 从员工标签读取`id`属性,并将其设置为当前的`Employee`对象。 4. 循环到下一个开始标签事件。 这些是`employee`标记内的 XML 元素。 读取这些标签内的数据。 将读取的数据设置为当前的`Employee`对象。 5. 继续迭代事件。 当找到`'employee'`标签的结束元素事件时,可以说您已经读取了当前`employee`的数据,因此将当前`employee`对象添加到`employeeList`集合中。 6. 最后,通过打印`employeeList`验证读取的数据。 ```java 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 tags XMLInputFactory factory = XMLInputFactory.newInstance(); // Initializing the handler to access the tags in the XML file XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(file)); //All read employees objects will be added to this list List<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 tag while (eventReader.hasNext()) { XMLEvent xmlEvent = eventReader.nextEvent(); if (xmlEvent.isStartElement()) { StartElement startElement = xmlEvent.asStartElement(); //As soo as employee tag is opened, create new Employee object if("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 data switch (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 data if("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`文件。 ```java 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 list List<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 event streamReader.next(); //Check if its 'START_ELEMENT' if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT) { //employee tag - opened if(streamReader.getLocalName().equalsIgnoreCase("employee")) { //Create new employee object asap tag is open employee = new Employee(); //Read attributes within employee tag if(streamReader.getAttributeCount() > 0) { String id = streamReader.getAttributeValue(null,"id"); employee.setId(Integer.valueOf(id)); } } //Read name data if(streamReader.getLocalName().equalsIgnoreCase("name")) { employee.setName(streamReader.getElementText()); } //Read title data if(streamReader.getLocalName().equalsIgnoreCase("title")) { employee.setTitle(streamReader.getElementText()); } } //If employee tag is closed then add the employee object to list if(streamReader.getEventType() == XMLStreamReader.END_ELEMENT) { if(streamReader.getLocalName().equalsIgnoreCase("employee")) { employeeList.add(employee); } } } //Verify read data System.out.println(employeeList); } } //Output: [Employee [id=101, name=Lokesh Gupta, title=Author], Employee [id=102, name=Brian Lara, title=Cricketer]] ``` ## 4)总结 因此,在此 **StAX 解析器教程**中,我们学习了以下内容: 1. **什么是基于 XML 流 API 的 StAX 解析器**。 2. **StAX 与 SAX** 解析器之间的差异。 3. 如何通过示例使用 StAX 迭代器 API 来**读取 XML**。 4. 如何通过示例使用 StAX 游标 API 来**读取 XML**。 两种 API 都能够解析任何类型的 XML 文档,但是**游标 API 比迭代器 API** 具有更高的内存效率。 因此,如果您的应用需要更好的性能,请考虑使用基于游标的 API。 将我的问题放在评论部分。 学习愉快!