=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=