Мне довелось прочитать главу о разборе XML и создании API в Java. И я опробовал другой парсер, доступный на примере XML. Затем я подумал о том, чтобы поделиться им в своем блоге, чтобы у меня была ссылка на код, а также ссылка для всех, кто читает это. В этом посте я анализирую один и тот же XML в разных синтаксических анализаторах, чтобы выполнить одну и ту же операцию: заполнить содержимое XML в объектах, а затем добавить объекты в список.
Пример XML, рассмотренный в примерах:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<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, определяется следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
|
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-парсера приведен ниже.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
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; }} |
Выход для вышеупомянутого будет:
|
1
2
3
|
Rakesh Mishra(111)BangaloreJohn Davis(112)ChennaiRajesh Sharma(113)Pune |
Использование SAX Parser
SAX Parser отличается от DOM Parser, где SAX Parser не загружает полный XML в память, вместо этого он анализирует XML строку за строкой, вызывая различные события, как и когда он встречает различные элементы, такие как: открывающий тег, закрывающий тег, символьные данные , комментарии и так далее. По этой причине SAX Parser называется анализатором событий.
Наряду с исходным XML-файлом мы также регистрируем обработчик, который расширяет класс DefaultHandler . Класс DefaultHandler предоставляет различные обратные вызовы, из которых мы были бы заинтересованы:
- startElement () — вызывает это событие, когда встречается начало тега.
- endElement () — вызывает это событие, когда встречается конец тега.
- characters () — вызывает это событие, когда встречает некоторые текстовые данные.
Код для синтаксического анализа XML с использованием SAX Parser приведен ниже:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
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; }} |
Выход для вышеупомянутого будет:
|
1
2
3
|
Rakesh Mishra(111)BangaloreJohn Davis(112)ChennaiRajesh 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:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
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; }} |
Выход для вышеупомянутого:
|
1
2
3
|
Rakesh Mishra(111) BangaloreJohn Davis(112) ChennaiRajesh Sharma(113) Pune |
При этом я рассмотрел анализ одного и того же XML-документа и выполнение одной и той же задачи по заполнению списка объектов Employee с использованием всех трех анализаторов, а именно: