在Java中使用DOM,SAX和StAX解析器解析XML

本文深入探讨了使用Java中的DOM、SAX和StAX解析器处理XML文档的方法。通过实例演示了如何利用三种不同的解析器从XML中提取数据,填充对象并将其添加到列表中。

我碰巧通读了有关Java中的XML解析和构建API的章节。 我试用了样本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解析器

我正在使用JDK附带的DOM解析器实现,在我的示例中,我使用的是JDK7。DOM解析器将完整的XML内容加载到Tree结构中。 然后,我们遍历NodeNodeList以获取XML的内容。 下面给出了使用DOM解析器进行XML解析的代码。

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解析器

SAX解析器不同于DOM解析器,在DOM解析器中,SAX解析器不会将完整的XML加载到内存中,而是在遇到不同元素(例如:打开标签,关闭标签,字符数据)时逐行触发不同事件来解析XML ,评论等。 这就是SAX解析器被称为基于事件的解析器的原因。

除了XML源文件,我们还注册了一个扩展DefaultHandler类的处理程序。 DefaultHandler类提供了我们感兴趣的不同回调:

  • startElement() –遇到标签开始时触发此事件。
  • endElement() –遇到标签结尾时触发此事件。
  • character() –遇到一些文本数据时触发此事件。

下面给出了使用SAX Parser解析XML的代码:

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解析器

StAX代表XML的Streaming API,并且StAX Parser与DOM有所不同,就像SAX Parser一样。 StAX解析器与SAX解析器也有细微的区别。

  • SAX解析器推送数据,但是StAX解析器从XML提取所需的数据。
  • StAX解析器将光标保留在文档的当前位置,从而可以提取光标处可用的内容,而SAX解析器在遇到某些数据时发出事件。

XMLInputFactoryXMLStreamReader是两个可用于加载XML文件的类。 当我们使用XMLStreamReader读取XML文件时,将以整数值的形式生成事件,然后将这些事件与XMLStreamConstants中的常量进行比较。 以下代码显示了如何使用StAX解析器解析XML:

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对象列表的相同任务:

参考:来自JCG合作伙伴 Mohamed Sanaulla的Javas,使用Java中的DOM,SAX和StAX Parser解析XML,来自Experiences Unlimited博客。

翻译自: https://www.javacodegeeks.com/2013/05/parsing-xml-using-dom-sax-and-stax-parser-in-java.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值