Java中如何解析XML文件/内容


=Start=

缘由:

不忙的时候用Java实现一些常用的功能,一方面是熟悉Java语法,另一方面也是为了减缓编码能力的退化。这里简单整理一下在Java中如何解析XML的方法,方便后面有需要的时候参考。

正文:

参考解答:

XML(eXtensible Markup Language)是一种通用的数据交换格式,它具有平台无关、语言无关、系统无关等特性,方便数据集成与交互,所以在 json/yaml 等格式没出来之前很流行。但是现在储存和交换数据的格式种类繁多,而 XML 使用起来也没有那么方便,更推荐大家使用 JSON、YAML 等数据格式。

在不同的语言中,解析XML的方式都是一样的,只不过实现的语法不同而已。在Java中主流的方法有DOM、SAX、JDOM和DOM4J。

DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。

SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法指定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag,特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。优点:不用事先调入整个文档,占用资源少,效率和性能较高,能解析大于系统内存的文档;缺点:解析逻辑复杂,需要应用层自己负责逻辑处理,文档越复杂程序越复杂,单向导航,无法定位文档层次,很难同时同时访问同一文档的不同部分数据,不支持XPath;使用场合:有兼容性考虑,且对性能和内存有要求的场景。

其它的2种JDOM和DOM4J这里就不列举了,直接参考后面链接中的文档内容即可。

建议:如果XML文档较大且不考虑移植性问题建议采用DOM4J;如果XML文档较小则建议采用JDOM;如果需要及时处理而不需要保存数据则考虑SAX;如果XML文档较小性能又不是瓶颈点且只想快速解决问题可以选择DOM。但无论如何,还是那句话:适合自己的才是最好的,如果时间允许,建议大家讲这四种方法都尝试一遍然后选择一种适合自己的即可。

下面根据自己的实际场景和需求选择用DOM进行一个XML文档的解析,了解一下大概的方法即可。

用DOM读取XML其实主要就是根据XML文档的内容和结构调用各种现成的get方法来达到目的:
.getDocumentElement
.getAttribute
.getAttributes
.getChildNodes
.getElementsByTagName
.getNodeValue
node.getTextContent()
node.getNodeType()

slide1.xml 文档内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:sld xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:cdr="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" xmlns:dgm="http://schemas.openxmlformats.org/drawingml/2006/diagram" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" xmlns:p15="http://schemas.microsoft.com/office/powerpoint/2012/main" xmlns:p166="http://schemas.microsoft.com/office/powerpoint/2016/6/main" xmlns:a13cmd="http://schemas.microsoft.com/office/drawing/2013/main/command" xmlns:p13cmd="http://schemas.microsoft.com/office/powerpoint/2013/main/command" xmlns:p1510="http://schemas.microsoft.com/office/powerpoint/2015/10/main" xmlns:psez="http://schemas.microsoft.com/office/powerpoint/2016/sectionzoom" xmlns:pslz="http://schemas.microsoft.com/office/powerpoint/2016/slidezoom" xmlns:psuz="http://schemas.microsoft.com/office/powerpoint/2016/summaryzoom" xmlns:p173="http://schemas.microsoft.com/office/powerpoint/2017/3/main" xmlns:comp="http://schemas.openxmlformats.org/drawingml/2006/compatibility" xmlns:lc="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas" xmlns:p159="http://schemas.microsoft.com/office/powerpoint/2015/09/main" xmlns:p16="http://schemas.microsoft.com/office/powerpoint/2015/main" xmlns:p1710="http://schemas.microsoft.com/office/powerpoint/2017/10/main" xmlns:p184="http://schemas.microsoft.com/office/powerpoint/2018/4/main">
    <p:cSld>
        <p:spTree>
            <p:nvGrpSpPr>
                <p:cNvPr id="1" name=""/>
                <p:cNvGrpSpPr/>
                <p:nvPr/>
            </p:nvGrpSpPr>
            <p:grpSpPr>
                <a:xfrm>
                    <a:off x="0" y="0"/>
                    <a:ext cx="0" cy="0"/>
                    <a:chOff x="0" y="0"/>
                    <a:chExt cx="0" cy="0"/>
                </a:xfrm>
            </p:grpSpPr>
            <p:sp>
                <p:nvSpPr>
                    <p:cNvPr id="2" name="标题 1">
                        <a:extLst>
                            <a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}">
<a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main" id="{0C4965C3-8E25-5064-CA94-43ECAEC4C9DA}"/>
                            </a:ext>
                        </a:extLst>
                    </p:cNvPr>
                    <p:cNvSpPr>
                        <a:spLocks noGrp="true"/>
                    </p:cNvSpPr>
                    <p:nvPr>
                        <p:ph type="ctrTitle"/>
                    </p:nvPr>
                </p:nvSpPr>
                <p:spPr/>
                <p:txBody>
                    <a:bodyPr/>
                    <a:lstStyle/>
                    <a:p>
                        <a:r>
                            <a:rPr kumimoji="true" lang="en-US" altLang="zh-CN" dirty="false"/>
                            <a:t>This is title</a:t>
                        </a:r>
                        <a:endParaRPr kumimoji="true" lang="zh-CN" altLang="en-US" dirty="false"/>
                    </a:p>
                </p:txBody>
            </p:sp>
            <p:sp>
                <p:nvSpPr>
                    <p:cNvPr id="3" name="副标题 2">
                        <a:extLst>
                            <a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}">
<a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main" id="{F7249D54-FC9D-6E07-5BE5-0C5D513920D2}"/>
                            </a:ext>
                        </a:extLst>
                    </p:cNvPr>
                    <p:cNvSpPr>
                        <a:spLocks noGrp="true"/>
                    </p:cNvSpPr>
                    <p:nvPr>
                        <p:ph type="subTitle" idx="1"/>
                    </p:nvPr>
                </p:nvSpPr>
                <p:spPr/>
                <p:txBody>
                    <a:bodyPr/>
                    <a:lstStyle/>
                    <a:p>
                        <a:r>
                            <a:rPr kumimoji="true" lang="en-US" altLang="zh-CN" dirty="false"/>
                            <a:t>Subtitle here</a:t>
                        </a:r>
                        <a:endParaRPr kumimoji="true" lang="zh-CN" altLang="en-US" dirty="false"/>
                    </a:p>
                </p:txBody>
            </p:sp>
            <p:pic>
                <p:nvPicPr>
                    <p:cNvPr id="4136" name="Picture 1" descr="1.png"/>
                    <p:cNvPicPr>
                        <a:picLocks noChangeAspect="true"/>
                    </p:cNvPicPr>
                    <p:nvPr/>
                </p:nvPicPr>
                <p:blipFill>
                    <a:blip cstate="print" r:link="rId3"/>
                    <a:stretch>
                        <a:fillRect/>
                    </a:stretch>
                </p:blipFill>
                <p:spPr>
                    <a:xfrm>
                        <a:off x="0" y="0"/>
                        <a:ext cx="1" cy="1"/>
                    </a:xfrm>
                    <a:prstGeom prst="rect">
                        <a:avLst/>
                    </a:prstGeom>
                </p:spPr>
            </p:pic>
        </p:spTree>
        <p:extLst>
            <p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}">
                <p14:creationId val="3160098309"/>
            </p:ext>
        </p:extLst>
    </p:cSld>
    <p:clrMapOvr>
        <a:masterClrMapping/>
    </p:clrMapOvr>
</p:sld>

opXml.java 代码内容如下:

package com.example;

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

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.StringReader;

/**
 * @author ixyzero
 * Created on 2022-05-08
 */
public class opXml {
    public static void main(String[] args) {
        String filePath = "slide1.xml";
        try {
            Document document = loadXMLFromFile(filePath);

            System.out.println(document.getDocumentElement()); // 根结点元素 [p:sld: null]
            System.out.println(document.getDocumentElement().getNodeName()); // 根结点名称 p:sld
            System.out.println(document.getDocumentElement().getAttributes().getLength()); // 根结点属性的个数-28
            System.out.println(document.getDocumentElement().getChildNodes().getLength()); // 一级节点(根结点下一层)的个数-5
            System.out.println(Node.ELEMENT_NODE); // 元素节点ELEMENT_NODE的type对应数值为 1

            // 遍历特定tag的元素获取其内容
            NodeList nodeList = document.getElementsByTagName("a:t");
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                System.out.println(node.getTextContent());
            }

            // 遍历特定tag的元素并打印出其子元素类型为ELEMENT_NODE的子元素的类型和节点名称
            NodeList nList = document.getElementsByTagName("p:sp");
            for (int i = 0; i < nList.getLength(); i++) {
                Node nNode = nList.item(i);
                System.out.println(String.format("\nCurrent Element: %s, childNode count: %d",
                        nNode.getNodeName(), nNode.getChildNodes().getLength()));
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element eElement = (Element) nNode;
                    for (int j = 0; j < eElement.getChildNodes().getLength(); j++) {
                        System.out.println(eElement.getChildNodes().item(j).getNodeType() + "\t" + eElement.getChildNodes().item(j).getNodeName());
                    }
                }
            }

            /*
            XPath常用语法
            http://www.51gjie.com/java/747.html

            https://stackoverflow.com/questions/4282147/use-xpath-to-parse-element-name-containing-a-colon
            https://newbedev.com/xpath-query-for-xml-node-with-colon-in-node-name

            //*     ->  获得所有节点
            //*[@cx] ->  获得存在属性cx的所有节点
            //*[@cx="1"] ->  获得存在属性cx且值为1的所有节点
            //*[name()='p:sp']  -> 获得所有p:sp节点
            //*[name()='p:sp'][1]  -> 获得第一个p:sp节点
            //*[local-name()='sp']  ->  *:sp
            //element_name  ->  获得所有element_name节点,如果element_name字符串中没有冒号(:)的话直接用这种方式就OK

             */
            XPath xPath =  XPathFactory.newInstance().newXPath();
            String expression = "//*[name()='p:sp'][1]";
            NodeList nodeList1 = (NodeList) xPath.compile(expression).evaluate(document, XPathConstants.NODESET);
            System.out.println(nodeList1.getLength());
            for (int i = 0; i < nodeList1.getLength(); i++) {
                Node nNode = nodeList1.item(i);
                System.out.println(String.format("Current Element: %s, childNode count: %d",
                        nNode.getNodeName(), nNode.getChildNodes().getLength()));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Document loadXMLFromFile(String filePath) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new File(filePath));
    }

    public static Document loadXMLFromString(String xml) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(xml));
        return builder.parse(is);
    }

}
参考链接:

A Guide to XML in Java
https://www.baeldung.com/java-xml

XML Libraries Support in Java #有 DOM/SAX/STAX/JAXB 4者的优劣对比
https://www.baeldung.com/java-xml-libraries

Java XML Tutorial #用 DOM/SAX/StAX/JDOM 读写XML,用 JAXB 在XML和对象之间做转换
https://mkyong.com/tutorials/java-xml-tutorials/

细说java解析xml文档的常用方法(含实例)
https://www.w3cschool.cn/java/java-mxl.html

Java 解析XML 4种方法总结
http://www.51gjie.com/java/740.html

Java解析XML文件的方式
https://www.cnblogs.com/JavaArchitect/p/12243296.html

JAVA解析XML的四种方式优缺点对比
https://www.jianshu.com/p/9b3835299b99

详解Java解析XML的四种方法
https://www.jianshu.com/p/ed0d6b96fd14

Java XML解析器
https://www.yiibai.com/java_xml/java_xml_parsers.html

How to retrieve element value of XML using Java?
https://stackoverflow.com/questions/4076910/how-to-retrieve-element-value-of-xml-using-java

XML 元素
https://www.runoob.com/xml/xml-elements.html

=END=

, ,

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注