原文: 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 流。 区别在于:

  1. StAX 是“pull” API。 SAX 是“push” API。
  2. StAX 可以进行 XML 读取和写入。 SAX 只能读取 XML。

StAX 是拉取风格 API 。 这意味着您必须自己将 StAX 解析器从 XML 文件中的一个项目移动到另一个项目,就像使用标准Iterator或 JDBC ResultSet一样。 然后,您可以通过 StAX 解析器访问 XML 文件中遇到的每个此类“项目”的 XML 信息。

游标与迭代器

  1. 在读取 XML 文档时,迭代器读取器从其nextEvent()调用中返回 XML 事件对象。 此事件提供有关您遇到的 XML 标签类型(元素,文本,注释等)的信息。 收到的事件是不可变的,因此您可以传递应用以安全地对其进行处理。 ```java XMLEventReader reader = …;

while(reader.hasNext()){ XMLEvent event = reader.nextEvent();

  1. if(event.getEventType() == XMLEvent.START_ELEMENT){
  2. //process data
  3. }
  4. //... more event types handled here...

}

  1. 2.
  2. 与迭代器不同,游标的工作方式类似于 JDBC 中的`Resultset` 如果将游标移动到 XML 文档中的下一个元素。 然后,您可以直接在游标上调用方法以获得有关当前事件的更多信息。
  3. ```java
  4. XMLStreamReader streamReader = ...;
  5. while(streamReader.hasNext()){
  6. int eventType = streamReader.next();
  7. if(eventType == XMLStreamReader.START_ELEMENT){
  8. System.out.println(streamReader.getLocalName());
  9. }
  10. //... more event types handled here...
  11. }

2)StAX 迭代器 API 示例

下面给出的 XML 文档演示如何使用基于 StAX 迭代器的 API 读取对象

XML 文件

  1. <employees>
  2. <employee id="101">
  3. <name>Lokesh Gupta</name>
  4. <title>Author</title>
  5. </employee>
  6. <employee id="102">
  7. <name>Brian Lara</name>
  8. <title>Cricketer</title>
  9. </employee>
  10. </employees>

使用 StAX 迭代器读取 XML

要读取文件,我已按照以下步骤编写了程序:

  1. 创建迭代器并开始接收事件。
  2. 一旦获得打开的'employee'标签,请创建一个新的Employee对象。
  3. 从员工标签读取id属性,并将其设置为当前的Employee对象。
  4. 循环到下一个开始标签事件。 这些是employee标记内的 XML 元素。 读取这些标签内的数据。 将读取的数据设置为当前的Employee对象。
  5. 继续迭代事件。 当找到'employee'标签的结束元素事件时,可以说您已经读取了当前employee的数据,因此将当前employee对象添加到employeeList集合中。
  6. 最后,通过打印employeeList验证读取的数据。
  1. package com.howtodoinjava.demo.stax;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.FileReader;
  5. import java.util.ArrayList;
  6. import java.util.Iterator;
  7. import java.util.List;
  8. import javax.xml.namespace.QName;
  9. import javax.xml.stream.XMLEventReader;
  10. import javax.xml.stream.XMLInputFactory;
  11. import javax.xml.stream.XMLStreamException;
  12. import javax.xml.stream.events.Attribute;
  13. import javax.xml.stream.events.Characters;
  14. import javax.xml.stream.events.EndElement;
  15. import javax.xml.stream.events.StartElement;
  16. import javax.xml.stream.events.XMLEvent;
  17. public class ReadXMLExample
  18. {
  19. public static void main(String[] args) throws FileNotFoundException, XMLStreamException
  20. {
  21. File file = new File("employees.xml");
  22. // Instance of the class which helps on reading tags
  23. XMLInputFactory factory = XMLInputFactory.newInstance();
  24. // Initializing the handler to access the tags in the XML file
  25. XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(file));
  26. //All read employees objects will be added to this list
  27. List<Employee> employeeList = new ArrayList<>();
  28. //Create Employee object. It will get all the data using setter methods.
  29. //And at last, it will stored in above 'employeeList'
  30. Employee employee = null;
  31. // Checking the availability of the next tag
  32. while (eventReader.hasNext())
  33. {
  34. XMLEvent xmlEvent = eventReader.nextEvent();
  35. if (xmlEvent.isStartElement())
  36. {
  37. StartElement startElement = xmlEvent.asStartElement();
  38. //As soo as employee tag is opened, create new Employee object
  39. if("employee".equalsIgnoreCase(startElement.getName().getLocalPart())) {
  40. employee = new Employee();
  41. }
  42. //Read all attributes when start tag is being read
  43. @SuppressWarnings("unchecked")
  44. Iterator<Attribute> iterator = startElement.getAttributes();
  45. while (iterator.hasNext())
  46. {
  47. Attribute attribute = iterator.next();
  48. QName name = attribute.getName();
  49. if("id".equalsIgnoreCase(name.getLocalPart())) {
  50. employee.setId(Integer.valueOf(attribute.getValue()));
  51. }
  52. }
  53. //Now everytime content tags are found;
  54. //Move the iterator and read data
  55. switch (startElement.getName().getLocalPart())
  56. {
  57. case "name":
  58. Characters nameDataEvent = (Characters) eventReader.nextEvent();
  59. employee.setName(nameDataEvent.getData());
  60. break;
  61. case "title":
  62. Characters titleDataEvent = (Characters) eventReader.nextEvent();
  63. employee.setTitle(titleDataEvent.getData());
  64. break;
  65. }
  66. }
  67. if (xmlEvent.isEndElement())
  68. {
  69. EndElement endElement = xmlEvent.asEndElement();
  70. //If employee tag is closed then add the employee object to list;
  71. //and be ready to read next employee data
  72. if("employee".equalsIgnoreCase(endElement.getName().getLocalPart())) {
  73. employeeList.add(employee);
  74. }
  75. }
  76. }
  77. System.out.println(employeeList); //Verify read data
  78. }
  79. }
  80. //Output:
  81. [Employee [id=101, name=Lokesh Gupta, title=Author],
  82. Employee [id=102, name=Brian Lara, title=Cricketer]]

3)StAX 游标 API 示例

我将使用基于游标的 API 读取相同的employees.xml文件。

  1. package com.howtodoinjava.demo.stax;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.FileReader;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import javax.xml.stream.XMLInputFactory;
  8. import javax.xml.stream.XMLStreamException;
  9. import javax.xml.stream.XMLStreamReader;
  10. public class ReadXMLExample
  11. {
  12. public static void main(String[] args) throws FileNotFoundException, XMLStreamException
  13. {
  14. //All read employees objects will be added to this list
  15. List<Employee> employeeList = new ArrayList<>();
  16. //Create Employee object. It will get all the data using setter methods.
  17. //And at last, it will stored in above 'employeeList'
  18. Employee employee = null;
  19. File file = new File("employees.xml");
  20. XMLInputFactory factory = XMLInputFactory.newInstance();
  21. XMLStreamReader streamReader = factory.createXMLStreamReader(new FileReader(file));
  22. while(streamReader.hasNext())
  23. {
  24. //Move to next event
  25. streamReader.next();
  26. //Check if its 'START_ELEMENT'
  27. if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT)
  28. {
  29. //employee tag - opened
  30. if(streamReader.getLocalName().equalsIgnoreCase("employee")) {
  31. //Create new employee object asap tag is open
  32. employee = new Employee();
  33. //Read attributes within employee tag
  34. if(streamReader.getAttributeCount() > 0) {
  35. String id = streamReader.getAttributeValue(null,"id");
  36. employee.setId(Integer.valueOf(id));
  37. }
  38. }
  39. //Read name data
  40. if(streamReader.getLocalName().equalsIgnoreCase("name")) {
  41. employee.setName(streamReader.getElementText());
  42. }
  43. //Read title data
  44. if(streamReader.getLocalName().equalsIgnoreCase("title")) {
  45. employee.setTitle(streamReader.getElementText());
  46. }
  47. }
  48. //If employee tag is closed then add the employee object to list
  49. if(streamReader.getEventType() == XMLStreamReader.END_ELEMENT)
  50. {
  51. if(streamReader.getLocalName().equalsIgnoreCase("employee")) {
  52. employeeList.add(employee);
  53. }
  54. }
  55. }
  56. //Verify read data
  57. System.out.println(employeeList);
  58. }
  59. }
  60. //Output:
  61. [Employee [id=101, name=Lokesh Gupta, title=Author],
  62. 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。

将我的问题放在评论部分。

学习愉快!