Статьи

Разбор XML с использованием DOM, SAX и StAX Parser в Java

Мне довелось прочитать главу о разборе 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)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 приведен ниже:

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)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:

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) Bangalore
John Davis(112) Chennai
Rajesh Sharma(113) Pune

При этом я рассмотрел анализ одного и того же XML-документа и выполнение одной и той же задачи по заполнению списка объектов Employee с использованием всех трех анализаторов, а именно:

Ссылка: парсинг XML с использованием DOM, SAX и StAX Parser на Java от нашего партнера JCG Мохамеда Санауллы в блоге Experiences Unlimited .