浅谈几款XML文档解析工具以及优缺点

一、简介

XML,一种可扩展标记语言,通常被开发人员用来传输和存储数据,定义也比较简单,通常如下方式开头,用来表述文档的一些信息。

<?xml version="1.0" encoding="UTF-8"?>

例如下面这个简单的文档。

<?xml version="1.0" encoding="UTF-8"?>
<site>
  <name>博客网站</name>
  <url>https://www.pzblog.cn</url>
  <desc>技术学习网站</desc>
</site>

其中sitenameurldesc表示标签名称,内容表示标签对应的值。

因 XML 的平台无关性、语言无关性、系统无关性等特点,给系统之间的数据传输带来了极大的便利,广受开发者欢迎。

事实上,在 1996 年诞生之后,XML 逐渐成为了一种通用的数据交换格式。

不同的编程语言,解析 XML 的逻辑基本都是一样的,只不过实现的语法稍有不同。

今天我们就一起来学习一下,采用 Java 编程语言来解析 XML,有哪些方法以及对应的优缺点。

经过整理,通过 Java 程序解析 XML 文件,目前比较主流的有以下四种方式:

  • DOM 解析

  • SAX 解析

  • JDOM 解析

  • DOM4J  解析

下面我们以如下的 XML 文件为例,分别介绍每种方式的解析实现。

<?xml version="1.0" encoding="utf-8" ?>
<class>
    <student id="1">
        <name>张三</name>
        <gender>男</gender>
        <age>26</age>
    </student>
    <student id="2">
        <name>里斯</name>
        <gender>男</gender>
        <age>36</age>
    </student>
 <student id="3">
        <name>王五</name>
        <gender>女</gender>
        <age>24</age>
    </student>
</class>

二、DOM 解析

DOM 的全称是:Document Object Model,是 Java 中最早支持的一种 XML 解析方式,可以不用依赖任何第三方包,通过 JDK 提供的 w3c 包里面的 api,即可实现快速解析,代码编程简单。

DOM 解析 XML 文档的时候,会在内存中加载整个文档来构造层次结构,因此优势比较突出:

  • 1.能快速遍历 XML 中任意节点数据,同时允许应用程序对数据和结构做出更改

  • 2.可以在任何时候在树中上下导航,获取和操作任意部分的数据

当然也有缺点:

  • 加载小的 XML 文档问题不大,加载大的 XML 文档,内存消耗会很大,有内存溢出的风险

总的来说,DOM 解析方式,对于数据量比较小的 XML 文档,基本够用。

实现过程如下:

import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;

public class DomDemo {
    
    public static void main(String[] args) {
        // 1.获取xml文件流
        InputStream inputStream = DomDemo.class.getClassLoader().getResourceAsStream("demo.xml");
        // 2.创建DocumentBuilderFactory对象
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 3.创建DocumentBuilder对象
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document d = builder.parse(inputStream);
            NodeList stdList = d.getElementsByTagName("student");
            for (int i = 0; i <stdList.getLength() ; i++) {
                Node std = stdList.item(i);
                // 遍历标签属性
                NamedNodeMap attrs = std.getAttributes();
                for(int j=0; j< attrs.getLength(); j++){
                    Node attr = attrs.item(j);
                    System.out.println(attr.getNodeName()+":"+attr.getNodeValue());
                }
                // 遍历标签子节点
                NodeList childNodes = std.getChildNodes();
                for (int k = 0; k <childNodes.getLength() ; k++) {
                    if (childNodes.item(k).getNodeType()== Node.ELEMENT_NODE) {
                        System.out.println(childNodes.item(k).getNodeName() + ":" + childNodes.item(k).getTextContent());
                    }
                }
                System.out.println("==============");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

id:1
name:张三
gender:男
age:26
==============
id:2
name:里斯
gender:男
age:36
==============
id:3
name:王五
gender:女
age:24
==============

三、SAX 解析

SAX 的全称是:Simple API for XML,也是 JDK 提供的另一种 XML 解析方式。

相比于 DOM,SAX 每次解析只在内存中加载 XML 文件的一小部分,即使针对较大的 XML 文件,它也不需要占用太多的内存,也不会存在内存溢出的问题。

优点如下:

  • 1.采用事件驱动模式一段一段的来解析数据,占用内存小

  • 2.只在读取数据时检查数据,不需要保存在内存中

  • 3.效率和性能较高,能解析大于系统内存的文档

当然也有缺点:

  • 1.与 DOM 解析器相比,使用 SAX 解析器读取 XML 文件时,解析逻辑比较复杂

  • 2.同时无法定位文档层次,很难同时访问同一文档的不同部分数据,不支持 XPath

实现过程如下:

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

public class SAXDemo {

    public static void main(String[] args) throws Exception {
        // 1.获取xml文件流
        InputStream inputStream = SAXDemo.class.getClassLoader().getResourceAsStream("demo.xml");
        // 2.获取SAXParserFactory实例
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 3.获取SAXparser实例
        SAXParser saxParser = factory.newSAXParser();
        // 4.创建Handel对象
        SAXDemoHandel handel = new SAXDemoHandel();
        // 5.解析XML文件
        saxParser.parse(inputStream, handel);
        // 6.获取读取结果
        List<Map<String, String>> students = handel.getStudents();
        for (Map<String, String> student : students) {
            System.out.println(student.toString());
        }
    }
}
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SAXDemoHandel extends DefaultHandler {

    private String value;

    private Map<String, String> student;

    private List<Map<String, String>> students = new ArrayList<>();

    public List<Map<String, String>> getStudents() {
        return students;
    }

    /**
     * xml 解析开始
     * @throws SAXException
     */
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("xml 解析开始");
    }

    /**
     * xml 解析结束
     * @throws SAXException
     */
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("xml 解析结束");
    }

    /**
     * 解析 XML 元素开始
     * @param uri
     * @param localName
     * @param qName
     * @param attributes
     * @throws SAXException
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        System.out.println("开始遍历节点:" +  qName);

        if (qName.equals("student")){
            student = new HashMap<>();
            for(int i=0; i<attributes.getLength();i++){
                student.put(attributes.getQName(i), attributes.getValue(i));
            }
        }
    }

    /**
     * 解析 XML 元素结束
     * @param uri
     * @param localName
     * @param qName
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        System.out.println("节点遍历结束:" +  qName);

        if(qName.equals("student")){
            students.add(student);
            student = null;
        } else if(qName.equals("name") || qName.equals("gender") || qName.equals("age")){
            student.put(qName, value);
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);

        // 获取节点值数组
        value = new String(ch,start,length).trim();
        if (!value.equals("")) {
            System.out.println(value);
        }
    }
}

运行结果如下:

{gender=男, name=张三, id=1}
{gender=男, name=里斯, id=2}
{gender=女, name=王五, id=3}

四、JDOM 解析

JDOM 是 Java 生态中一个非常优秀的 XML 开源文档解析库,你可以把它看成是 DOM 及 SAX 的结合版,同时在设计上弥补了 DOM 及 SAX 在实际应用当中的不足之处。

优点如下:

  • 1.基于树的模型处理 XML 文件,数据会加载在内存中

  • 2.没有向下兼容的限制,因此比 DOM 简单

  • 3.速度快,缺陷少

  • 4.具有 SAX 的解析特征

  • 5.API 比 DOM 更容易理解

当然也有缺点:

  • 1.能处理大于内存的 XML 文档

  • 2.不支持与 DOM 中相应遍历包

总体来讲,JDOM 对于大多数需要使用 XML 应用程序来说还是非常实用的。

实现过程如下:

<!--jdom -->
<dependency>
    <groupId>org.jdom</groupId>
    <artifactId>jdom</artifactId>
    <version>1.1.3</version>
</dependency>
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import java.io.InputStream;
import java.util.List;


public class JdomDemo {

    public static void main(String[] args) throws Exception {
        // 1.获取xml文件流
        InputStream inputStream = JdomDemo.class.getClassLoader().getResourceAsStream("demo.xml");
        // 2.创建SAXBuilder对象
        SAXBuilder saxBuilder = new SAXBuilder();
        // 3.将输入流加载到build中
        Document document = saxBuilder.build(inputStream);
        // 4.获取根节点
        Element rootElement = document.getRootElement();
        // 5.获取子节点
        List<Element> children = rootElement.getChildren();
        for (Element child : children) {
            List<Attribute> attributes = child.getAttributes();
            // 遍历标签属性
            for (Attribute attr : attributes) {
                System.out.println(attr.getName()+":"+attr.getValue());
            }
            // 遍历标签子节点
            List<Element> childrenList = child.getChildren();
            for (Element  o: childrenList) {
                System.out.println(o.getName() + ":" + o.getValue());
            }
            System.out.println("==============");
        }
    }
}

运行结果如下:

id:1
name:张三
gender:男
age:26
==============
id:2
name:里斯
gender:男
age:36
==============
id:3
name:王五
gender:女
age:24
==============

五、DOM4J 解析

DOM4J 也是 Java 生态中一款非常非常优秀的 XML 开源文档解析库,是 JDOM 的升级品。

最初,它是 JDOM 的一种分支,后来合并了许多超出基本 XML 文档表示的功能,最后单独作为一工具对外发布。

优点如下:

  • 1.性能优异,功能强大,极端易使用

  • 2.开发简便,同时也提供了一些提高性能的代替方法

  • 3.支持 XPath

唯一的缺点:

  • API 过于复杂

实现过程如下:

 <!-- dom4j -->
 <dependency>
     <groupId>dom4j</groupId>
     <artifactId>dom4j</artifactId>
     <version>1.6.1</version>
</dependency>
public class Dom4jDemo {

    public static void main(String[] args) throws Exception {
        // 1.获取xml文件流
        InputStream inputStream = Dom4jDemo.class.getClassLoader().getResourceAsStream("demo.xml");
        // 2.创建Reader对象
        SAXReader reader = new SAXReader();
        // 3.加载xml
        Document document = reader.read(inputStream);
        // 4.获取根节点
        Element rootElement = document.getRootElement();
        // 5.遍历元素
        Iterator iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element stu = (Element) iterator.next();
            // 遍历标签属性
            List<Attribute> attributes = stu.attributes();
            for (Attribute attribute : attributes) {
                System.out.println(attribute.getName() + ":" + attribute.getValue());
            }

            // 遍历标签子节点
            Iterator iterator1 = stu.elementIterator();
            while (iterator1.hasNext()){
                Element stuChild = (Element) iterator1.next();
                System.out.println(stuChild.getName()+":"+stuChild.getStringValue());
            }
            System.out.println("==============");
        }
    }
}

运行结果如下:

id:1
name:张三
gender:男
age:26
==============
id:2
name:里斯
gender:男
age:36
==============
id:3
name:王五
gender:女
age:24
==============

六、小结

最后总结一下,目前许多开源项目中大量采用 DOM4J,例如 Hibernate 框架中就用到 DOM4J 来读取 XML 配置文件,连 Sun 的 JAXM 也在用 DOM4J。

因此对于需要使用 XML 解析工具,如果项目中没有什么包袱,首选 DOM4J。

对于一些已经在项目中用到的 XML 解析工具,如果不考虑移植性问题,也可以改成 DOM4J 来实现,当然具体问题具体分析,如果迁移成本很高,以前的工具依然能正常运行,也没必要进行迁移。总之就是,适合的才是最好的,是否值得迁移,需要评估资源成本和时间以及必要性。

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
package com.hexiang.utils; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * 本类是专门解析XML文件的,主要用于为系统读取自己的配置文件时提供最方便的解析操作 * @author HX * */ public class XmlManager { /** * 得到某节点下某个属性的值 * @param element 要获取属性的节点 * @param attributeName 要取值的属性名称 * @return 要获取的属性的值 * @author HX_2010-01-12 */ public static String getAttribute( Element element, String attributeName ) { return element.getAttribute( attributeName ); } /** * 获取指定节点下的文本 * @param element 要获取文本的节点 * @return 指定节点下的文本 * @author HX_2010-01-12 */ public static String getText( Element element ) { return element.getFirstChild().getNodeValue(); } /** * 解析某个xml文件,并在内存中创建DOM树 * @param xmlFile 要解析XML文件 * @return 解析某个配置文件后的Document * @throws Exception xml文件不存在 */ public static Document parse( String xmlFile ) throws Exception { // 绑定XML文件,建造DOM树 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document domTree = db.parse( xmlFile ); return domTree; } /** * 获得某节点下的某个子节点(指定子节点名称,和某个属性的值) * 即获取parentElement下名字叫childName,并且属性attributeName的值为attributeValue的子结点 * @param parentElement 要获取子节点的那个父节点 * @param childName 要获取的子节点名称 * @param attributeName 要指定的属性名称 * @param attributeValue 要指定的属性的值 * @return 符合条件的子节点 * @throws Exception 子结点不存在或有多个符合条件的子节点 * @author HX_2008-12-01 */ public static Element getChildElement( Element parentElement, String childName, String attributeName, String attributeValue ) throws Exception { NodeList list = parentElement.getElementsByTagName( childName ); int count = 0; Element curElement = null; for ( int i = 0 ; i < list.getLength() ; i ++ ) { Element child = ( Element )list.item( i ); String value = child.getAttribute( attributeName ); if ( true == value.equals( attributeValue ) ) { curElement =
好的,关于 Android XML 解析工具类,可以使用 Android 提供的 XmlPullParser 类来解析 XML 文件。XmlPullParser 是 Android 系统中提供的一个轻量级的解析器,用于解析 XML 文件。 下面是一个简单的示例代码,展示如何使用 XmlPullParser 来解析 XML 文件: ```java public static List<Entry> parse(InputStream is) throws XmlPullParserException, IOException { List<Entry> entries = new ArrayList<>(); XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(is, null); int eventType = parser.getEventType(); Entry currentEntry = null; while (eventType != XmlPullParser.END_DOCUMENT) { String name = parser.getName(); switch (eventType) { case XmlPullParser.START_TAG: if (name.equals("entry")) { currentEntry = new Entry(); } else if (currentEntry != null) { if (name.equals("title")) { currentEntry.setTitle(parser.nextText()); } else if (name.equals("link")) { currentEntry.setLink(parser.nextText()); } else if (name.equals("description")) { currentEntry.setDescription(parser.nextText()); } else if (name.equals("pubDate")) { currentEntry.setPubDate(parser.nextText()); } } break; case XmlPullParser.END_TAG: if (name.equals("entry") && currentEntry != null) { entries.add(currentEntry); } break; } eventType = parser.next(); } return entries; } ``` 在这个示例中,我们使用 XmlPullParser 解析 XML 文件,并将每个 entry 元素解析为一个 Entry 对象。在解析过程中,我们使用了 XmlPullParser 的一些方法,例如 parser.getEventType()、parser.getName()、parser.nextText() 等。 希望这个示例代码能够帮助你了解如何使用 XmlPullParser 类来解析 XML 文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ISBN图书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值