Научитесь анализировать и читать XML-файлы с помощью парсера Java StAX. StAX(Streaming API for XML) предоставляет два способа анализа XML:
- API на основе курсора
- API на основе итератора
В этом руководстве будут рассмотрены оба API для анализа XML-файла.
1. Введение в StAX Parser
Как и SAX parser, StAX API предназначен для парсинга XML-потоков. Разница в следующем:
- StAX — это API «pull». SAX — это API «push».
- StAX может выполнять как чтение, так и запись XML. SAX может выполнять только чтение XML.
StAX — это API в стиле pull. Это означает, что нам придется самостоятельно перемещать парсер StAX от элемента к элементу в XML-файле, как мы делаем это со стандартным Iterator или JDBC ResultSet. Затем мы можем получить доступ к XML-информации через парсер StAX для каждого такого «элемента», обнаруженного в XML-файле.
2. Разница между API курсора и итератора
При чтении XML-документа итератор-читатель возвращает объект события XML из своих вызовов nextEvent(). Это событие предоставляет информацию о том, с каким типом XML-тега(элемент, текст, комментарий и т. д.) мы столкнулись. Полученное событие является неизменяемым, поэтому мы можем передать его приложению для безопасной обработки.
XMLEventReader reader = ...;while(reader.hasNext()){XMLEvent event = reader.nextEvent();if(event.getEventType() == XMLEvent.START_ELEMENT){//process data}//... more event types handled here...}
В отличие от Iterator, курсор работает как Resultset в JDBC. Если курсор перемещается на следующий элемент в 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...}
3. Пример API итератора
Ниже показано, как использовать API на основе итератора StAX для чтения XML-документа в объект.
XML-файл выглядит следующим образом:
<сотрудники><сотрудник id="101"><name>Локеш Гупта</name><title>Автор</title></сотрудник><сотрудник id="102"><name>Брайан Лара</name><title>Игрок в крикет</title></сотрудник></сотрудники>
Для чтения файла я написал программу, выполнив следующие шаги:
- Создайте итератор и начните получать события.
- Как только вы откроете тег «сотрудник» — создайте новый объект «Сотрудник».
- Считать атрибут id из тега сотрудника и установить его для текущего объекта Employee.
- Итерация к следующему началу событий тега. Это элементы XML внутри тега employee. Прочитать данные внутри этих тегов. Установить прочитанные данные для текущего объекта Employee.
- Продолжайте итерацию события. Когда вы найдете событие конечного элемента для тега 'employee', вы можете сказать, что вы прочитали данные для текущего сотрудника, поэтому добавьте объект текущего сотрудника в коллекцию employeeList.
- Наконец, проверьте считанные данные, распечатав employeeList.
import com.howtodoinjava.xml.model.Employee;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 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}}
Вывод программы:
[Employee [id=101, name=Lokesh Gupta, title=Author],Employee [id=102, name=Brian Lara, title=Cricketer]]
4. Пример API курсора
Я прочитаю тот же файл employees.xml – теперь с API на основе курсора.
import com.howtodoinjava.xml.model.Employee;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 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.setFirstName(streamReader.getElementText());}//Read title dataif(streamReader.getLocalName().equalsIgnoreCase("title")) {employee.setLastName(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);}}
5. Заключение
Итак, в этом уроке по парсеру StAX мы узнали следующее:
- Что такое парсер StAX, основанный на API потоковой передачи XML?
- Разница между парсерами StAX и SAX.
- Как читать XML с помощью API итератора StAX на примере.
- Как читать XML с помощью API курсора StAX на примере.
Оба API способны анализировать любой тип XML-документа, но API курсора более эффективно использует память, чем API итератора. Поэтому, если вашему приложению требуется более высокая производительность, рассмотрите возможность использования API на основе курсора.
Пишите мне свои вопросы в комментариях.