一 简介

在Java中,可以使用多种方式来解析XML文件,其中最常见的可能就是DOM、SAX、JDOM、DOM4J这四种方式了。其中,DOM和SAX这两种解析XML文件的方式有jdk自带的API,因此不需要额外引入第三方的jar包。与之相反的是,JDOM和DOM4J这两种解析方式都是第三方开源项目,因此在使用这两种方式解析XML文件时需要额外引入相关jar包

(1)DOM

DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合,这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作

因此在使用DOM这种方式来解析XML文件时,解析器需要将整个XML文件读到内存中,形成一个树形结构方便后面的操作优点: 整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种操作

缺点: 将整个文档调入内存(包括无用的节点),浪费时间和内存,如果XML过大容易出现内存溢出问题

(2)SAX

由于DOM解析XML文件时需要一次性读入整个文件,当文件过大时有诸多不足之处,因此为了解决这个问题,出现了SAX这种基于事件驱动的解析方式

SAX解析XML文件通过从上往下依次不断载入内容到内存中,当解析器发现元素的开始标志、结束标志、文本、文档的开始标志、文档的结束标志等相关标志时,将会触发一些对应的事件,我们需要做的就是在这些事件的方法中编写自定义代码,用于保存获取到的数据优点:不用事先载入整个文档,占用资源(内存)少;使用SAX方式解析编写的代码要比使用DOM解析编写的代码少

缺点:不是持久的;事件过后,若没保存数据,那么数据就丢了;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素

(3)JDOM

使用JDOM来解析XML文件跟使用DOM来解析从代码上来说解析思路是差不多的。JDOM与DOM主要有两方面不同:首先,JDOM仅使用具体类而不使用接口,这在某些方面简化了API,但是也限制了灵活性。其次是JDOM的API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用优点:开源项目;比DOM容易理解

缺点:JDOM自身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档

(4)DOM4J

DOM4J 是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的 Java 软件都在使用 DOM4J 来读写 XML

由于DOM4J无论在性能方面还是代码编写方面都是很强大的,特别是当XML文件很大时使用DOM4J来解析也会有较高的效率。因此,建议平时需要解析XML文件可以考虑尽可能使用DOM4J来解析。当然如果文件非常小的话使用DOM来解析也是可以的

优点:开源项目

DOM4J是JDOM的一种智能分支,它合并了需要超出基本XML文档的功能

具有性能优异、灵活性好、简单易用等特点

二 DOM解析XML文件

(1)在进行代码编写测试之前,需要准备一个XML文件,我这里准备的文件是:demo1.xml

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

zifangsky

10

male

https://www.zifangsky.cn

admin

20

male

https://www.tar.pub

(2)代码实例:package cn.zifangsky.xml;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NamedNodeMap;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

public class DomParseTest {

public static void main(String[] args) {

DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();

try {

DocumentBuilder dBuilder = dFactory.newDocumentBuilder();

// 加载一个xml文件

Document document = dBuilder

.parse("src/cn/zifangsky/xml/demo1.xml");

// 获取user节点集合

NodeList userList = document.getElementsByTagName("user");

int userListLength = userList.getLength();

System.out.println("此xml文件一共有" + userListLength + "个'user'节点\n");

// 遍历

for (int i = 0; i

// 通过item方法获取指定的节点

Node userNode = userList.item(i);

// *********************解析属性***********************

// 获取该节点的所有属性值,如:id="1"

NamedNodeMap userAttributes = userNode.getAttributes();

System.out.println("'user'节点" + i + "有"

+ userAttributes.getLength() + "个属性:");

/**

* 1 在不清楚有哪些属性的情况下可以遍历所有属性,

* 并获取每个属性对应的属性名和属性值

* */

for (int j = 0; j

// 'user'节点的每个属性组成的节点

Node attrnNode = userAttributes.item(j);

System.out.println("属性" + j + ": 属性名: "

+ attrnNode.getNodeName() + " ,属性值: "

+ attrnNode.getNodeValue());

}

/**

* 2 在知道有哪些属性值的情况下,可以获取指定属性名的属性值

* */

Element userElement = (Element) userList.item(i);

System.out.println("属性为'id'的对应值是: "

+ userElement.getAttribute("id"));

// *********************解析子节点************************

NodeList childNodes = userNode.getChildNodes();

System.out.println("\n该节点一共有" + childNodes.getLength()

+ "个子节点,分别是:");

// 遍历子节点

for (int k = 0; k

Node childNode = childNodes.item(k);

// 从输出结果可以看出,每行后面的换行符也被当做了一个节点,因此是:4+5=9个子节点

// System.out.println("节点名: " + childNode.getNodeName() +

// ",节点值: " + childNode.getTextContent());

// 仅取出子节点中的'ELEMENT_NODE',换行符组成的Node是'TEXT_NODE'

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

// System.out.println("节点名: " + childNode.getNodeName()

// + ",节点值: " + childNode.getTextContent());

// 最低一层是文本节点,节点名是'#text'

System.out.println("节点名: " + childNode.getNodeName()

+ ",节点值: "

+ childNode.getFirstChild().getNodeValue());

}

}

System.out.println("***************************");

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

从上面的代码可以看出,在使用DOM来解析XML文件时一般需要做以下几步操作:创建一个文档构建器工厂(DocumentBuilderFactory)实例

通过上面的DocumentBuilderFactory生成一个新的文档构建器(DocumentBuilder)

使用上面的DocumentBuilder解析(parse)一个XML文件,生成文档树(Document)

通过Document获取指定id的节点或根据节点名获取所有符合条件的节点集合

遍历每个节点,可以获取该节点的属性、属性值等相关参数

如果该节点还存在子节点,可以根据上面的方式继续遍历它的所有子节点

(3)上面的代码输出如下:此xml文件一共有2个'user'节点

'user'节点0有1个属性:

属性0: 属性名: id ,属性值: 1

属性为'id'的对应值是: 1

该节点一共有9个子节点,分别是:

节点名: name,节点值: zifangsky

节点名: age,节点值: 10

节点名: sex,节点值: male

节点名: contact,节点值: https://www.zifangsky.cn

***************************

'user'节点1有1个属性:

属性0: 属性名: id ,属性值: 2

属性为'id'的对应值是: 2

该节点一共有9个子节点,分别是:

节点名: name,节点值: admin

节点名: age,节点值: 20

节点名: sex,节点值: male

节点名: contact,节点值: https://www.tar.pub

***************************

三 SAX解析XML文件

在进行本次测试时,并不引入其他XML文件,仍然使用上面的demo1.xml文件

由于SAX解析XML文件跟DOM不同,它并不是将整个文档都载入到内存中。解析器在解析XML文件时,通过逐步载入文档,从上往下一行行的解析XML文件,在碰到文档开始标志、节点开始标志、文本文档、节点结束标志、文档结束标志时进行对应的事件处理。因此,我们首先需要构造一个这样的解析处理器来申明:当解析到这些标志时,我们需要进行怎样的自定义处理

(1)解析处理器SAXParseHandler.java:package cn.zifangsky.xml;

import org.xml.sax.Attributes;

import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

public class SAXParseHandler extends DefaultHandler {

/**

* 用来遍历XML文件的开始标签

* */

@Override

public void startElement(String uri, String localName, String qName,

Attributes attributes) throws SAXException {

super.startElement(uri, localName, qName, attributes);

//解析'user'元素的属性值

//if(qName.equals("user"))

//System.out.println("'user'元素的id属性值是:" + attributes.getValue("id"));

//遍历并打印元素的属性

int length = attributes.getLength();

if(length > 0){

System.out.println("元素'" + qName + "'的属性是:");

for(int i=0;i

System.out.println("    属性名:" + attributes.getQName(i) + ",属性值: " + attributes.getValue(i));

}

System.out.println();

}

System.out.print("");

}

/**

* 用来遍历XML文件的结束标签

* */

@Override

public void endElement(String uri, String localName, String qName)

throws SAXException {

super.endElement(uri, localName, qName);

System.out.println("");

}

/**

* 文本内容

* */

public void characters(char[] ch, int start, int length)

throws SAXException {

super.characters(ch, start, length);

String value = new String(ch, start, length).trim();

if(!value.equals(""))

System.out.print(value);

}

/**

* 用来标识解析开始

* */

@Override

public void startDocument() throws SAXException {

System.out.println("SAX解析开始");

super.startDocument();

}

/**

* 用来标识解析结束

* */

@Override

public void endDocument() throws SAXException {

System.out.println("SAX解析结束");

super.endDocument();

}

}

关于上面代码的一些含义我这里就不再做解释了,可以自行参考注释内容

(2)测试:

SAXParseTest.java文件:package cn.zifangsky.xml;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;

public class SAXParseTest {

public static void main(String[] args) {

SAXParserFactory sFactory = SAXParserFactory.newInstance();

try {

SAXParser saxParser = sFactory.newSAXParser();

//创建自定义的SAXParseHandler解析类

SAXParseHandler saxParseHandler = new SAXParseHandler();

saxParser.parse("src/cn/zifangsky/xml/demo1.xml", saxParseHandler);

} catch (Exception e) {

e.printStackTrace();

}

}

}

从上面的代码可以看出,使用SAX解析XML文件时,一共传递进去了两个参数,分别是:XML文件路径和前面定义的解析处理器。有了具体的XML文件以及对应的处理器来处理对应的标志事情,因此SAX这种解析方式就可以顺利地进行解析工作了

(3)上面测试的输出如下:SAX解析开始

元素'user'的属性是:

属性名:id,属性值: 1

zifangsky

10

male

https://www.zifangsky.cn

元素'user'的属性是:

属性名:id,属性值: 2

admin

20

male

https://www.tar.pub

SAX解析结束

四 JDOM解析XML文件

跟前面两种解析方式不同的是,使用JDOM来解析XML文件需要下载额外的jar包

(1)下载jar包并导入到项目中:

然后将下载得到的“jdom-2.0.6.jar”文件导入到测试项目中

注:关于如何在一个Java项目中导入额外的jar,这里将不多做解释,不太会的童鞋可以自行百度

(2)测试代码:

JDOMTest.java:package cn.zifangsky.xml;

import java.util.List;

import org.jdom2.Document;

import org.jdom2.Element;

import org.jdom2.input.SAXBuilder;

public class JDOMTest {

/**

* @param args

*/

public static void main(String[] args) {

SAXBuilder saxBuilder = new SAXBuilder();

try {

Document document = saxBuilder.build("src/cn/zifangsky/xml/demo1.xml");

//获取XML文件的根节点

Element rootElement = document.getRootElement();

//System.out.println(rootElement.getName());

List usersList = rootElement.getChildren();  //获取子节点

for(Element u : usersList){

//List attributes = u.getAttributes();

//for(Attribute attribute : attributes){

//System.out.println("属性名:" + attribute.getName() + ",属性值:" + attribute.getValue());

//}

System.out.println("'id'的值是: " + u.getAttributeValue("id"));

}

}catch (Exception e) {

e.printStackTrace();

}

}

}

从上面的代码可以看出,使用JDOM来解析XML文件,主要需要做以下几个步骤:新建一个SAXBuilder

通过SAXBuilder的build方法传入一个XML文件的路径得到Document

通过Document的getRootElement方法获取根节点

通过getChildren方法获取根节点的所有子节点

然后是遍历每个子节点,获取属性、属性值、节点名、节点值等内容

如果该节点也有子节点,然后同样可以通过getChildren方法获取该节点的子节点

后面的步骤跟上面一样,不断递归到文本节点截止

(3)上面测试的输出如下:'id'的值是: 1

'id'的值是: 2

五 DOM4J解析XML文件

同样,在使用DOM4J解析XML文件时需要往项目中引入“dom4j-1.6.1.jar”文件

(1)一个简单实例:

i)DOM4JTest.java:package cn.zifangsky.xml;

import java.io.File;

import java.util.Iterator;

import java.util.List;

import org.dom4j.Attribute;

import org.dom4j.Document;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

public class DOM4JTest {

public static void main(String[] args) {

SAXReader reader = new SAXReader();

try {

Document document = reader.read(new File("src/cn/zifangsky/xml/demo1.xml"));

//获取XML文件的根节点

Element rootElement = document.getRootElement();

System.out.println(rootElement.getName());

//通过elementIterator方法获取迭代器

Iterator iterator = rootElement.elementIterator();

//遍历

while(iterator.hasNext()){

Element user = iterator.next();

//获取属性并遍历

List aList = user.attributes();

for(Attribute attribute : aList){

System.out.println("属性名:" + attribute.getName() + ",属性值:" + attribute.getValue());

}

//子节点

Iterator childList = user.elementIterator();

while(childList.hasNext()){

Element child = childList.next();

//System.out.println(child.getName() + " : " + child.getTextTrim());

System.out.println(child.getName() + " : " + child.getStringValue());

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

从上面的代码可以看出,跟前面的JDOM解析方式流程是差不多的,并且关键地方也有注释,因此这里就不多做解释了

ii)上面的代码输出如下:employees

属性名:id,属性值:1

name : zifangsky

age : 10

sex : male

contact : https://www.zifangsky.cn

属性名:id,属性值:2

name : admin

age : 20

sex : male

contact : https://www.tar.pub

(2)将XML文件解析成Java对象:

i)为了方便测试,这里准备一个新的XML文件:

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

zifangsky

100

https://www.zifangsky.cn

旺财

九头猫妖

ii)同时准备一个Java实体类,恰好跟上面的XML文件中的属性相对应:

User.java:package cn.zifangsky.xml;

import java.util.List;

public class User {

private String name;

private String sex;

private int age;

private String contact;

private List ownPet;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSex() {

return sex;

}

public void setSex(String sex) {

this.sex = sex;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getContact() {

return contact;

}

public void setContact(String contact) {

this.contact = contact;

}

protected List getOwnPet() {

return ownPet;

}

protected void setOwnPet(List ownPet) {

this.ownPet = ownPet;

}

@Override

public String toString() {

return "User [name=" + name + ", sex=" + sex + ", age=" + age

+ ", contact=" + contact + ", ownPet=" + ownPet + "]";

}

}

iii)测试代码:

XMLtoJava.java:package cn.zifangsky.xml;

import java.io.File;

import java.util.ArrayList;

import java.util.List;

import org.dom4j.Document;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

public class XMLtoJava {

public User parseXMLtoJava(String xmlPath){

User user = new User();

List ownPet = new ArrayList();

SAXReader saxReader = new SAXReader();

try {

Document document = saxReader.read(new File(xmlPath));

Element rootElement = document.getRootElement();  //获取根节点

List children = rootElement.elements();  //获取根节点的子节点

//遍历

for(Element child : children){

String elementName = child.getName();  //节点名

String elementValue = child.getStringValue();  //节点值

switch (elementName) {

case "name":

user.setName(elementValue);

break;

case "sex":

user.setSex(elementValue);

break;

case "age":

user.setAge(Integer.valueOf(elementValue));

break;

case "contact":

user.setContact(elementValue);

break;

case "ownPet":

ownPet.add(elementValue);

break;

default:

break;

}

}

user.setOwnPet(ownPet);

} catch (Exception e) {

e.printStackTrace();

}

return user;

}

public static void main(String[] args) {

XMLtoJava demo = new XMLtoJava();

User user = demo.parseXMLtoJava("src/cn/zifangsky/xml/demo2.xml");

System.out.println(user);

}

}

经过前面的分析之后,上面这个代码也是很容易理解的:通过遍历节点,如果节点名跟Java类中的某个属性名相对应,那么就将节点值赋值给该属性

iv)上面的代码输出如下:User [name=zifangsky, sex=男, age=100, contact=https://www.zifangsky.cn, ownPet=[旺财, 九头猫妖]]

(3)解析一个XML文件并尽可能原样输出:

DOM4JTest2:package cn.zifangsky.xml;

import java.io.File;

import java.util.List;

import org.dom4j.Attribute;

import org.dom4j.Document;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

public class DOM4JTest2 {

/**

* 解析XML文件并尽可能原样输出

*

* @param xmlPath

*            待解析的XML文件路径

* @return null

* */

public void parse(String xmlPath) {

SAXReader saxReader = new SAXReader();

try {

Document document = saxReader.read(new File(xmlPath));

Element rootElement = document.getRootElement();

print(rootElement, 0);

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 打印一个XML节点的详情

*

* @param element

*            一个XML节点

* @param level

*            用于判断xml节点前缩进多少的标识,每深入一层则多输出4个空格

* @return null

* */

public void print(Element element, int level) {

List elementList = element.elements(); // 当前节点的子节点List

// 空格

StringBuffer spacebBuffer = new StringBuffer("");

for (int i = 0; i

spacebBuffer.append("    ");

String space = spacebBuffer.toString();

// 输出开始节点及其属性值

System.out.print(space + "

List attributes = element.attributes();

for (Attribute attribute : attributes)

System.out.print(" " + attribute.getName() + "=\""

+ attribute.getText() + "\"");

// 有子节点

if (elementList.size() > 0) {

System.out.println(">");

// 遍历并递归

for (Element child : elementList) {

print(child, level + 1);

}

// 输出结束节点

System.out.println(space + "" + element.getName() + ">");

} else {

// 如果节点没有文本则简化输出

if (element.getStringValue().trim().equals(""))

System.out.println(" />");

else

System.out.println(">" + element.getStringValue() + ""

+ element.getName() + ">");

}

}

public static void main(String[] args) {

DOM4JTest2 test2 = new DOM4JTest2();

test2.parse("src/cn/zifangsky/xml/demo3.xml");

}

}

这段代码同样没有什么新的东西,原理就是利用递归来不断进行解析输出,注意一下不同层次的节点的缩进即可。刚开始测试时建议用一些结构比较简单的代码,如上面的demo1.xml和demo2.xml文件。在测试没问题时可以选择一些复杂的XML文件来测试是否能够正常输出,比如:

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

xmlns:xs="http://www.w3.org/2001/XMLSchema">

为什么我在标题上说的是尽可能原样输出,其原因就是上面那段解析代码在碰到下面这种XML节点时,输出就不一样了:

这段XML文档节点最后输出如下:admin

运维

zabbix

端口

参考文章:

java jdom dom4j_Java基础系列17:使用DOM、SAX、JDOM、DOM4J解析XML文件详解相关推荐

  1. Java数据持久层框架 MyBatis之API学习六(Mapper XML 文件详解)

    对于MyBatis的学习而言,最好去MyBatis的官方文档:http://www.mybatis.org/mybatis-3/zh/index.html 对于语言的学习而言,马上上手去编程,多多练习 ...

  2. java中四种操作(DOM、SAX、JDOM、DOM4J)xml方式详解与比较(转)

    java中四种操作(DOM.SAX.JDOM.DOM4J)xml方式详解与比较(转) http://wishlife.javaeye.com/blog/181865 posted on 2010-12 ...

  3. java dom xml 换行,dom4j解析xml文件_用DOM解析XML文件,怎么才能让解析出来的文本不用换行_dom解析xml文件...

    网友求助:dom4j解析xml文件_用DOM解析XML文件,怎么才能让解析出来的文本不用换行_dom解析xml文件 问题importjava.text.SimpleDateFormat; import ...

  4. Java中DOM4J解析xml文件浅析

      DOM4J解析它是JDOM的一种智能分支.它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持.XML Schema支持以及用于大文档或流化文档的基于事件的处理.它还提供了构建文档表 ...

  5. Java - DOM4J解析XML文件

    文章目录 1. XML文档说明 2. XML解析 2.1 常见的解析方式 2.2 DOM4J解析xml 2.3 XPath表达式解析XML 3. 解析XML并封装到类中 4. 参考资料 1. XML文 ...

  6. java使用DOM4j解析XML文件

    1.简介 dom4j是java中的XML API,性能优异.功能强大.开放源代码. 也是所有解析XML文件方法中最常用的! 2.代码实操 准备需要j的ar包添加到lib目录下,dom4j-2.1.1. ...

  7. java中document解析jsp,JSP基于dom解析xml实例详解

    本文实例讲述了JSP基于dom解析xml的方法.分享给大家供大家参考,具体如下: 初次学习用dom操作xml文件,有很多不足之处,牛人多给点建议,练习时我没对中文做乱码处理,也没做验证哦!O(∩_∩) ...

  8. maven系列一:pom.xml文件详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  9. Java自动化测试框架-12 - TestNG之xml文件详解篇 (详细教程)

    1.简介 现在这篇,我们来学习TestNG.xml文件,前面我们已经知道,TestNG就是运行这个文件来执行测试用例的.通过本篇,你可以进一步了解到:这个文件是配置测试用例,测试套件.简单来说,利用这 ...

最新文章

  1. 【跨域报错解决方案】Access to XMLHttpRequest at ‘http://xxx.com/xxx‘ from origin ‘null‘ has been blocked by
  2. SCCM 2012 R2---安装SCCM 2012 R2
  3. 2019年上半年收集到的人工智能GAN干货文章
  4. 币圈“水逆”,暴跌与高危漏洞
  5. 前端开发学习笔记(二)
  6. Django简介Django 各个环境下的安装
  7. java中ATM与数据库Mysql的连接
  8. java订单超时取消设计_PHP如何实现处理过期或者超时订单的,并还原库存
  9. 洛谷 P4009 汽车加油行驶问题 题解
  10. 【java】Java -jar 运行的程序如何 本地代码远程调试服务器程序
  11. 测试面试题,自动化测试与性能测试篇(附答案)
  12. jQuery日历控件(JS日期拾取器)实用精简
  13. linux系统网桥管理工具brctl 安装及使用
  14. 基于asp.net固定资产管理系统设计
  15. 环境准备以及服务器的搭建(2)
  16. 《阿里云服务器教程2》:如何远程连接linux系统阿里云服务器ECS
  17. JMeter常用函数整理
  18. 手写webpack得打包流程
  19. 数字人民币智能合约的一个颠覆式创新应用
  20. 宝存 shannon PCI-E SSD VS OCZ RevoDrive3 X2 PCI-E SSD on CentOS 6.5 2.6.32-431.el6.x86_64

热门文章

  1. 组合数学 —— 排列数
  2. chatgpt赋能python:Python用什么软件搜题?推荐4款具有高效与准确性的题库搜索工具
  3. keepalived 防火墙配置
  4. 疫情期间去澳洲的注意事项、签证持有者的限制信息
  5. asic面试题目 英伟达_NVIDIA校招面试经历
  6. Extreme DAX中文第3章 DAX的用法
  7. 13 使用Vue + FormData + axios实现图片上传功能实战
  8. 这几种好用的英语图片翻译方法,你们千万不能错过
  9. ALDS1_5_A:Exhaustive search(穷举搜索)
  10. tag开发实例源代码