Мне довелось прочитать главу о разборе XML и создании API в Java. И я попробовал разные парсеры на примере XML. Затем я подумал о том, чтобы поделиться им в своем блоге, чтобы у меня была ссылка на код, а также ссылка для всех, кто читает это. В этом посте я анализирую один и тот же XML в разных синтаксических анализаторах, чтобы выполнить одну и ту же операцию: заполнить содержимое XML-объектов объектами, а затем добавить объекты в список.
Пример XML, рассмотренный в примерах:
<employees>
<employee id="111">
<firstName>Rakesh</firstName>
<lastName>Mishra</lastName>
<location>Bangalore</location>
</employee>
<employee id="112">
<firstName>John</firstName>
<lastName>Davis</lastName>
<location>Chennai</location>
</employee>
<employee id="113">
<firstName>Rajesh</firstName>
<lastName>Sharma</lastName>
<location>Pune</location>
</employee>
</employees>
И объект, в который должен быть извлечен контент XML, определяется следующим образом:
class Employee{
String id;
String firstName;
String lastName;
String location;
@Override
public String toString() {
return firstName+" "+lastName+"("+id+")"+location;
}
}
Есть 3 основных анализатора, для которых я привел пример кода:
Использование DOM Parser
Я использую реализацию парсера DOM, которая поставляется с JDK, и в моем примере я использую JDK 7. Парсер DOM загружает весь XML-контент в древовидную структуру. И мы перебираем Node и NodeList, чтобы получить содержимое XML. Код для разбора XML с использованием DOM-парсера приведен ниже.
public class DOMParserDemo {
public static void main(String[] args) throws Exception {
//Get the DOM Builder Factory
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//Get the DOM Builder
DocumentBuilder builder = factory.newDocumentBuilder();
//Load and Parse the XML document
//document contains the complete XML as a Tree.
Document document =
builder.parse(
ClassLoader.getSystemResourceAsStream("xml/employee.xml"));
List<Employee> empList = new ArrayList<>();
//Iterating through the nodes and extracting the data.
NodeList nodeList = document.getDocumentElement().getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
//We have encountered an <employee> tag.
Node node = nodeList.item(i);
if (node instanceof Element) {
Employee emp = new Employee();
emp.id = node.getAttributes().
getNamedItem("id").getNodeValue();
NodeList childNodes = node.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node cNode = childNodes.item(j);
//Identifying the child tag of employee encountered.
if (cNode instanceof Element) {
String content = cNode.getLastChild().
getTextContent().trim();
switch (cNode.getNodeName()) {
case "firstName":
emp.firstName = content;
break;
case "lastName":
emp.lastName = content;
break;
case "location":
emp.location = content;
break;
}
}
}
empList.add(emp);
}
}
//Printing the Employee list populated.
for (Employee emp : empList) {
System.out.println(emp);
}
}
}
class Employee{
String id;
String firstName;
String lastName;
String location;
@Override
public String toString() {
return firstName+" "+lastName+"("+id+")"+location;
}
}
Выход для вышеупомянутого будет:
Rakesh Mishra(111)Bangalore John Davis(112)Chennai Rajesh Sharma(113)Pune
Использование SAX Parser
SAX Parser отличается от DOM Parser, где SAX Parser не загружает полный XML в память, вместо этого он анализирует XML строку за строкой, вызывая различные события, как и когда он встречает различные элементы, такие как: открывающий тег, закрывающий тег, символьные данные , комментарии и так далее. По этой причине SAX Parser называется анализатором событий.
Наряду с исходным XML-файлом мы также регистрируем обработчик, который расширяет класс DefaultHandler . Класс DefaultHandler предоставляет различные обратные вызовы, из которых мы были бы заинтересованы:
- startElement () — вызывает это событие, когда встречается начало тега.
- endElement () — вызывает это событие, когда встречается конец тега.
- characters () — вызывает это событие, когда встречает некоторые текстовые данные.
Код для синтаксического анализа XML с использованием SAX Parser приведен ниже:
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SAXParserDemo {
public static void main(String[] args) throws Exception {
SAXParserFactory parserFactor = SAXParserFactory.newInstance();
SAXParser parser = parserFactor.newSAXParser();
SAXHandler handler = new SAXHandler();
parser.parse(ClassLoader.getSystemResourceAsStream("xml/employee.xml"),
handler);
//Printing the list of employees obtained from XML
for ( Employee emp : handler.empList){
System.out.println(emp);
}
}
}
/**
* The Handler for SAX Events.
*/
class SAXHandler extends DefaultHandler {
List<Employee> empList = new ArrayList<>();
Employee emp = null;
String content = null;
@Override
//Triggered when the start of tag is found.
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
switch(qName){
//Create a new Employee object when the start tag is found
case "employee":
emp = new Employee();
emp.id = attributes.getValue("id");
break;
}
}
@Override
public void endElement(String uri, String localName,
String qName) throws SAXException {
switch(qName){
//Add the employee to list once end tag is found
case "employee":
empList.add(emp);
break;
//For all other end tags the employee has to be updated.
case "firstName":
emp.firstName = content;
break;
case "lastName":
emp.lastName = content;
break;
case "location":
emp.location = content;
break;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
content = String.copyValueOf(ch, start, length).trim();
}
}
class Employee {
String id;
String firstName;
String lastName;
String location;
@Override
public String toString() {
return firstName + " " + lastName + "(" + id + ")" + location;
}
}
Выход для вышеупомянутого будет:
Rakesh Mishra(111)Bangalore John Davis(112)Chennai Rajesh Sharma(113)Pune
Использование StAX Parser
StAX означает потоковый API для XML, а StAX Parser отличается от DOM тем же, что и SAX Parser. Парсер StAX также немного отличается от парсера SAX.
- Анализатор SAX отправляет данные, но анализатор StAX извлекает необходимые данные из XML.
- Синтаксический анализатор StAX поддерживает курсор в текущей позиции в документе, что позволяет извлечь содержимое, доступное для курсора, тогда как синтаксический анализатор SAX выдает события по мере появления определенных данных.
XMLInputFactory и XMLStreamReader — это два класса, которые можно использовать для загрузки файла XML. И когда мы читаем XML-файл с использованием XMLStreamReader, события генерируются в форме целочисленных значений, а затем сравниваются с константами в XMLStreamConstants . В приведенном ниже коде показано, как анализировать XML с помощью анализатора StAX:
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class StaxParserDemo {
public static void main(String[] args) throws XMLStreamException {
List<Employee> empList = null;
Employee currEmp = null;
String tagContent = null;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader =
factory.createXMLStreamReader(
ClassLoader.getSystemResourceAsStream("xml/employee.xml"));
while(reader.hasNext()){
int event = reader.next();
switch(event){
case XMLStreamConstants.START_ELEMENT:
if ("employee".equals(reader.getLocalName())){
currEmp = new Employee();
currEmp.id = reader.getAttributeValue(0);
}
if("employees".equals(reader.getLocalName())){
empList = new ArrayList<>();
}
break;
case XMLStreamConstants.CHARACTERS:
tagContent = reader.getText().trim();
break;
case XMLStreamConstants.END_ELEMENT:
switch(reader.getLocalName()){
case "employee":
empList.add(currEmp);
break;
case "firstName":
currEmp.firstName = tagContent;
break;
case "lastName":
currEmp.lastName = tagContent;
break;
case "location":
currEmp.location = tagContent;
break;
}
break;
case XMLStreamConstants.START_DOCUMENT:
empList = new ArrayList<>();
break;
}
}
//Print the employee list populated from XML
for ( Employee emp : empList){
System.out.println(emp);
}
}
}
class Employee{
String id;
String firstName;
String lastName;
String location;
@Override
public String toString(){
return firstName+" "+lastName+"("+id+") "+location;
}
}
Выход для вышеупомянутого:
Rakesh Mishra(111) Bangalore John Davis(112) Chennai Rajesh Sharma(113) Pune
При этом я рассмотрел анализ одного и того же XML-документа и выполнение одной и той же задачи по заполнению списка Employeeобъектов с использованием всех трех анализаторов, а именно: