Cách Đọc File XML Java ( DOM Parser )

Hướng dẫn này sẽ chỉ cho bạn cách sử dụng DOM parser  tích hợp sẵn của Java để đọc file XML.

Lưu ý:

Trình phân tích cú pháp DOM chậm và tiêu tốn nhiều bộ nhớ khi nó đọc một tài liệu XML lớn vì nó tải tất cả các nút vào bộ nhớ để duyệt và thao tác.

Thay vào đó, chúng ta nên xem xét trình phân tích cú pháp SAX để đọc một tài liệu XML có kích thước lớn, SAX nhanh hơn DOM và sử dụng ít bộ nhớ hơn.

Document Object Model (DOM) là gì?

DOM là viết tắt của Document Object Model ( gọi nôm na là mô hình tài liệu đối tượng ) sử dụng các nút để biểu diễn tài liệu HTML hoặc XML dưới dạng cấu trúc cây.

Ví dụ dưới đây là một tài liệu XML đơn giản:

<company>
    <staff id="1001">
        <firstname>tuan</firstname>
        <lastname>nguyen</lastname>
        <nickname>nguyentuan</nickname>
        <salary currency="USD">10000</salary>
    </staff>
</company>

Các thuật ngữ chung của DOM.

  • Là <company>phần tử gốc.
  • Với <staff>, <firstname> and all <?>là các nút phần tử.
  • Nút văn bản là giá trị được bao bọc bởi các nút phần tử; ví dụ, <firstname>tuan</firstname>là tuannút văn bản.
  • Thuộc tính là một phần của nút phần tử; ví dụ, <staff id="1001">là id thuộc tính của staff phần tử.

Xem thêm nếu bạn vẫn chưa hiểu: Wikipedia – Mô hình đối tượng tài liệu (DOM) hoặc Mozilla – Mô hình đối tượng tài liệu (DOM)

Đọc hoặc phân tích cú pháp tệp XML

Ví dụ này cho bạn thấy cách sử dụng các API trình phân tích cú pháp DOM tích hợp sẵn của Java để đọc hoặc phân tích cú pháp tệp XML.

2.1 Xem lại tệp XML bên dưới.

<?xml version="1.0"?>
<company>
    <staff id="1001">
        <firstname>tuan</firstname>
        <lastname>nguyen</lastname>
        <nickname>nguyentuan</nickname>
        <salary currency="USD">100000</salary>
    </staff>
    <staff id="2001">
        <firstname>low</firstname>
        <lastname>yin fong</lastname>
        <nickname>fong fong</nickname>
        <salary currency="INR">200000</salary>
    </staff>
</company>

2.2 Dưới đây là ví dụ về DOM parser về việc phân tích cú pháp hoặc đọc tệp XML ở trên.

package com.sharecs.xml.dom;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class ReadXmlDomParser {

  private static final String FILENAME = "/users/sharecs/staff.xml";

  public static void main(String[] args) {

      // Instantiate the Factory
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

      try {

          // optional, but recommended
          // process XML securely, avoid attacks like XML External Entities (XXE)
          dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

          // parse XML file
          DocumentBuilder db = dbf.newDocumentBuilder();

          Document doc = db.parse(new File(FILENAME));

          // optional, but recommended
          // http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
          doc.getDocumentElement().normalize();

          System.out.println("Root Element :" + doc.getDocumentElement().getNodeName());
          System.out.println("------");

          // get <staff>
          NodeList list = doc.getElementsByTagName("staff");

          for (int temp = 0; temp < list.getLength(); temp++) {

              Node node = list.item(temp);

              if (node.getNodeType() == Node.ELEMENT_NODE) {

                  Element element = (Element) node;

                  // get staff's attribute
                  String id = element.getAttribute("id");

                  // get text
                  String firstname = element.getElementsByTagName("firstname").item(0).getTextContent();
                  String lastname = element.getElementsByTagName("lastname").item(0).getTextContent();
                  String nickname = element.getElementsByTagName("nickname").item(0).getTextContent();

                  NodeList salaryNodeList = element.getElementsByTagName("salary");
                  String salary = salaryNodeList.item(0).getTextContent();

                  // get salary's attribute
                  String currency = salaryNodeList.item(0).getAttributes().getNamedItem("currency").getTextContent();

                  System.out.println("Current Element :" + node.getNodeName());
                  System.out.println("Staff Id : " + id);
                  System.out.println("First Name : " + firstname);
                  System.out.println("Last Name : " + lastname);
                  System.out.println("Nick Name : " + nickname);
                  System.out.printf("Salary [Currency] : %,.2f [%s]%n%n", Float.parseFloat(salary), currency);

              }
          }

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

}

Kết quả đưa ra cho bạn thấy:

Root Element :company
------
Current Element :staff
Staff Id : 1001
First Name : tuan
Last Name : nguyen
Nick Name : nguyentuan
Salary [Currency] : 100,000.00 [USD]

Current Element :staff
Staff Id : 2001
First Name : low
Last Name : yin fong
Nick Name : fong fong
Salary [Currency] : 200,000.00 [INR]

Phân tích và đọc file XML Java ( Unicode )

Trong phân tích DOM, không có sự khác biệt giữa việc đọc tệp XML bình thường và Unicode.

Ví dụ tệp XML bên dưới có chứa một số ký tự Trung Quốc (Unicode).

<?xml version="1.0"?>
<company>
    <staff id="1001">
        <firstname>揚</firstname>
        <lastname>木金</lastname>
        <nickname>sharecs</nickname>
        <salary currency="USD">100000</salary>
    </staff>
    <staff id="2001">
        <firstname>low</firstname>
        <lastname>yin fong</lastname>
        <nickname>fong fong</nickname>
        <salary currency="INR">200000</salary>
    </staff>
</company>

Ví dụ dưới đây phân tích cú pháp tệp XML ở trên; nó lặp lại tất cả các nút lần lượt và in ra.

package com.sharecs.xml.dom;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;

public class ReadXmlDomParserLoop {

  public static void main(String[] args) {

      // Instantiate the Factory
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

      try (InputStream is = readXmlFileIntoInputStream("staff-unicode.xml")) {

          // parse XML file
          DocumentBuilder db = dbf.newDocumentBuilder();

          // read from a project's resources folder
          Document doc = db.parse(is);

          System.out.println("Root Element :" + doc.getDocumentElement().getNodeName());
          System.out.println("------");

          if (doc.hasChildNodes()) {
              printNote(doc.getChildNodes());
          }

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

  private static void printNote(NodeList nodeList) {

      for (int count = 0; count < nodeList.getLength(); count++) {

          Node tempNode = nodeList.item(count);

          // make sure it's element node.
          if (tempNode.getNodeType() == Node.ELEMENT_NODE) {

              // get node name and value
              System.out.println("\nNode Name =" + tempNode.getNodeName() + " [OPEN]");
              System.out.println("Node Value =" + tempNode.getTextContent());

              if (tempNode.hasAttributes()) {

                  // get attributes names and values
                  NamedNodeMap nodeMap = tempNode.getAttributes();
                  for (int i = 0; i < nodeMap.getLength(); i++) {
                      Node node = nodeMap.item(i);
                      System.out.println("attr name : " + node.getNodeName());
                      System.out.println("attr value : " + node.getNodeValue());
                  }

              }

              if (tempNode.hasChildNodes()) {
                  // loop again if has child nodes
                  printNote(tempNode.getChildNodes());
              }

              System.out.println("Node Name =" + tempNode.getNodeName() + " [CLOSE]");

          }

      }

  }

  // read file from project resource's folder.
  private static InputStream readXmlFileIntoInputStream(final String fileName) {
      return ReadXmlDomParserLoop.class.getClassLoader().getResourceAsStream(fileName);
  }

}

Kết quả:

Root Element :company
------

Node Name =company [OPEN]
Node Value =

        揚
        木金
        sharecs
        100000


        low
        yin fong
        fong fong
        200000



Node Name =staff [OPEN]
Node Value =
        揚
        木金
        sharecs
        100000

attr name : id
attr value : 1001

Node Name =firstname [OPEN]
Node Value =揚
Node Name =firstname [CLOSE]

Node Name =lastname [OPEN]
Node Value =木金
Node Name =lastname [CLOSE]

Node Name =nickname [OPEN]
Node Value =sharecs
Node Name =nickname [CLOSE]

Node Name =salary [OPEN]
Node Value =100000
attr name : currency
attr value : USD
Node Name =salary [CLOSE]
Node Name =staff [CLOSE]

Node Name =staff [OPEN]
Node Value =
        low
        yin fong
        fong fong
        200000

attr name : id
attr value : 2001

Node Name =firstname [OPEN]
Node Value =low
Node Name =firstname [CLOSE]

Node Name =lastname [OPEN]
Node Value =yin fong
Node Name =lastname [CLOSE]

Node Name =nickname [OPEN]
Node Value =fong fong
Node Name =nickname [CLOSE]

Node Name =salary [OPEN]
Node Value =200000
attr name : currency
attr value : INR
Node Name =salary [CLOSE]
Node Name =staff [CLOSE]
Node Name =company [CLOSE]

Phân tích cú pháp phản hồi XML API của Alexa

Ví dụ này cho thấy cách sử dụng trình phân tích cú pháp DOM để phân tích cú pháp phản hồi XML từ API của Alexa.

Gửi yêu cầu tới API Alexa sau.

https://data.alexa.com/data?cli=10&url=sharecs.net

API Alexa sẽ trả về phản hồi XML sau. Xếp hạng Alexa nằm bên trong POPULARITY phần tử, TEXT thuộc tính.

<!--  Need more Alexa data?  Find our APIs here: https://aws.amazon.com/alexa/  -->
<ALEXA VER="0.9" URL="sharecs.net/" HOME="0" AID="=" IDN="sharecs.net/">
     <SD>
          <POPULARITY URL="sharecs.net/" TEXT="1252153" SOURCE="panel"/>
          <REACH RANK="1121536"/>
          <RANK DELTA="+379865"/>
          <COUNTRY CODE="VN" NAME="Vietnam" RANK="17410"/>
     </SD>
</ALEXA>

Mình sẽ phân tích cú pháp DOM để chọn trực tiếp POPULARITY phần tử và in ra giá trị của TEXT thuộc tính.

package com.sharecs.xml.dom;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class ReadXmlAlexaApi {

    private static final String ALEXA_API = "http://data.alexa.com/data?cli=10&url=";
    private final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

    public static void main(String[] args) {

        ReadXmlAlexaApi obj = new ReadXmlAlexaApi();
        int alexaRanking = obj.getAlexaRanking("sharecs.net");

        System.out.println("Ranking: " + alexaRanking);

    }

    public int getAlexaRanking(String domain) {

        int result = 0;

        String url = ALEXA_API + domain;

        try {

            URLConnection conn = new URL(url).openConnection();

            try (InputStream is = conn.getInputStream()) {

                // unknown XML better turn on this
                dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

                DocumentBuilder dBuilder = dbf.newDocumentBuilder();

                Document doc = dBuilder.parse(is);

                Element element = doc.getDocumentElement();

                // find this tag "POPULARITY"
                NodeList nodeList = element.getElementsByTagName("POPULARITY");
                if (nodeList.getLength() > 0) {

                    Element elementAttribute = (Element) nodeList.item(0);
                    String ranking = elementAttribute.getAttribute("TEXT");
                    if (!"".equals(ranking)) {
                        result = Integer.parseInt(ranking);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Invalid request for domain : " + domain);
        }

        return result;
    }

}

Kết quả trả về miền sharecs.net Ranking: 17410

Cảm ơn các bạn đã ghé thăm. Chúc các bạn thành công!

Đánh giá bài viết giúp mình nhé!