StAX的两种处理模式

Cursor 和 Iterator API 的区别

在读取 XML 文档时,迭代器读取器从其nextEvent()调用中返回一个 XML 事件对象。此事件提供有关我们遇到的 XML 标记类型(元素、文本、注释等)的信息。收到的事件是不可变的,因此我们可以传递应用程序以安全地处理它。

XMLEventReader reader = ...;
 
while(reader.hasNext()){
    XMLEvent event = reader.nextEvent();
 
    if(event.getEventType() == XMLEvent.START_ELEMENT){
        //process data
    } 
    //... more event types handled here...
}

与 Iterator 不同,游标的工作方式类似于 JDBC 中的 Resultset。如果光标移动到 XML 文档中的下一个元素。然后,您可以直接在游标上调用方法来获取有关当前事件的更多信息。

XMLStreamReader streamReader = ...;
 
while(streamReader.hasNext()){
    int eventType = streamReader.next();
 
    if(eventType == XMLStreamReader.START_ELEMENT){
        System.out.println(streamReader.getLocalName());
    }
 
    //... more event types handled here...
}

迭代器 API 示例

下面演示了如何使用 StAX 基于迭代器的API 将 XML 文档读取到对象。

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>

为了读取该文件,我按以下步骤编写了程序:

  • 创建一个迭代器并开始接收事件。

  • 一旦你得到open 'employee' tag– 创建新Employee对象。

  • 从员工标签中读取id属性并将其设置为当前对象。Employee

  • 迭代到下一个开始标记事件。这些是employee标记内的 XML 元素。读取这些标签内的数据。将读取的数据设置为当前Employee对象。

  • 继续迭代该事件。当你找到 tag 的结束元素事件时'employee',你可以说你已经读取了 current 的数据employee,因此将当前employee对象添加到employeeList集合中。

  • 最后通过打印验证读取的数据employeeList

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 ReadXmlWithIterator {

	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
	}
}

程序输出:

Cursor API示例

我将读取同一个employees.xml文件——现在使用基于游标的 API。

package xml.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 ReadXmlWithCursor {

	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);
	}
}

总结

这两个 API 都能够解析任何类型的 XML 文档,但Cursor API 比迭代器 API 更节省内存。因此,如果您的应用程序需要更好的性能,请考虑使用基于游标的 API。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hello_中年人

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值