用dom4j操作xml文件

  XML的全称是eXtensible Markup Language,即“可扩展标记语言”。XML文件的作用主要是数据存储,文件配置,数据传输。

  html与xml的区别是:①html语法松散,xml语法严格;②html做页面展示,xml做数据存储;③html的所有标签都是预定义的,xml所有标签都是自定义的。xml文档中必须有且只能有一个根元素;元素需要正确闭合元素需要正确嵌套元素名称要遵守两点,一是元素名称区分大小写,二是数字不能开头属性值必须用引号引起来,单双引号都行;xml文档中的注释符为<!--   -->;xml文档中对于可能引起歧义的文本要使用转义字符,或者用<![CDATA[数据内容]],这样的话,数据内容可以原样显示。

<?xml version="1.0" encoding="UTF-8" ?>
<自定义标签>
    ...
</自定义标签> 

  xml的书写规则,有DTDschema。

  文档类型定义(DTD)可以定义合法的XML文档构建模块,约束自定义的语法规则。它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

   内部的 DOCTYPE 声明:

<!DOCTYPE 根元素 [元素声明]>

   带有 DTD 的 XML 文档实例:

<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

   以上 DTD 解释如下:
  !DOCTYPE note (第二行)定义此文档是 note 类型的文档。
  !ELEMENT note (第三行)定义 note 元素有四个元素:"to、from、heading,、body"
  !ELEMENT to (第四行)定义 to 元素为 "#PCDATA" 类型
  !ELEMENT from (第五行)定义 from 元素为 "#PCDATA" 类型
  !ELEMENT heading (第六行)定义 heading 元素为 "#PCDATA" 类型
  !ELEMENT body (第七行)定义 body 元素为 "#PCDATA" 类型

  假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:

<!DOCTYPE 根元素 SYSTEM "文件名">

   这个 XML 文档和上面的 XML 文档相同,但是拥有一个外部的 DTD:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note> 

   这是包含 DTD 的 "note.dtd" 文件:

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

   通过 DTD,我们的每一个 XML 文件均可携带一个有关其自身格式的描述。通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据。我们的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据。我们还可以使用 DTD 来验证自身的数据。

  XML Schema 的作用是定义 XML 文档的合法构建模块,类似 DTD。它是基于 XML 的 DTD 替代者。XML Schema 描述 XML 文档的结构。XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。

  XML Schema 最重要的能力之一就是对数据类型的支持。例:

user.xsd

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
	elementFormDefault="qualified" 
	targetNamespace="http://www.itszt2.com"
	xmlns="http://www.itszt2.com">	
	<xs:element name="用户" type="type_user"></xs:element>
	<!-- 复合类型;元素嵌套;自定义数据类型 -->
	<xs:complexType name="type_user">
		<!-- 规定显示的先后顺序 -->
		<xs:sequence>		
			<xs:element name="姓名" type="type_xm"></xs:element>
			<xs:element name="年龄" type="type_nl"></xs:element>			
			<xs:element name="性别" type="type_xb" minOccurs="1"
				maxOccurs="999999999"></xs:element>			
			<xs:element name="工资" type="type_gz">
			</xs:element>
			<xs:element name="出生日期" type="xs:date"></xs:element>
		</xs:sequence>	
	</xs:complexType>

	<!-- 定义姓名的类型 -->
	<xs:simpleType name="type_xm">
		<xs:restriction base="xs:string">
			<xs:pattern value="w{6,10}" />
		</xs:restriction>
	</xs:simpleType>

	<!-- 定义年龄的类型 -->
	<xs:simpleType name="type_nl">
		<xs:restriction base="xs:integer">
			<xs:minInclusive value="0"></xs:minInclusive>
			<xs:maxInclusive value="100"></xs:maxInclusive>
		</xs:restriction>
	</xs:simpleType>

	<!-- 定义性别类型 -->
	<xs:simpleType name="type_xb">
		<xs:restriction base="xs:string">
			<xs:enumeration value="男" />
		</xs:restriction>
	</xs:simpleType>

	<!-- 定义属性 -->
	<xs:complexType name="type_gz">
		<xs:attribute name="单位" type="xs:string" use="required" />
		<xs:attribute name="num" type="xs:decimal" />
	</xs:complexType>
</xs:schema>

-------------------------------------------------------------
test.xml

<?xml version="1.0"?>
<用户 xmlns="http://www.itszt2.com" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
	http://www.itszt2.com
 	user.xsd"> 	
     
 	<姓名>hehe123</姓名>
	<年龄>20</年龄>
	<性别>男</性别>
	<工资 单位="元" num="123.45" ></工资>
	<出生日期>1999-10-10</出生日期>	
	
</用户> 

  上述演示中,xmlns="http://www.w3school.com.cn"  规定了默认命名空间的声明。此声明会告知 schema 验证器,在此 XML 文档中使用的所有元素都被声明于 "http://www.w3school.com.cn" 这个命名空间。

  定义简易元素的语法:

<xs:element name="xxx" type="yyy"/>

   上面的 xxx 指元素的名称,yyy 指元素的数据类型。XML Schema 拥有很多内建的数据类型。  

最常用的类型是:
    xs:string
    xs:decimal
    xs:integer
    xs:boolean
    xs:date
    xs:time

   简易元素可拥有指定的默认值或固定值。当没有其他的值被规定时,默认值就会自动分配给元素。在下面的例子中,缺省值是 "red":

<xs:element name="color" type="xs:string" default="red"/>

   固定值同样会自动分配给元素,并且我们无法规定另外一个值。在下面的例子中,固定值是 "red":

<xs:element name="color" type="xs:string" fixed="red"/>

   简易元素无法拥有属性。假如某个元素拥有属性,它就会被当作某种复合类型。但是属性本身总是作为简易类型被声明的。

  定义属性的语法是:  

<xs:attribute name="xxx" type="yyy"/>

   在此处,xxx 指属性名称,yyy 则规定属性的数据类型。XML Schema 拥有很多内建的数据类型,与上面定义元素的类型相同。

  限定(restriction)用于为 XML 元素或者属性定义可接受的值。对 XML 元素的限定被称为 facet。

  复合元素指包含其他元素及/或属性的 XML 元素。

有四种类型的复合元素:
    空元素
    包含其他元素的元素
    仅包含文本的元素
    包含元素和文本的元素
注释:上述元素均可包含属性!   

   比如,导入xsd约束文档:

(1)编写根标签
(2)引入实例名称空间 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
(3)引入名称空间 xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"	
(4)引入默认的名称空间 

  在Java技术中,对xml文件的操作也是一个重要的部分。一般来说,xml的格式比较标准,在存储数据方面有着广泛的运用,例如,很多软件(如tomcat,nginx,redis等),包括框架(如Spring,mybatis等)中的一系列配置文件,就广泛地采用了xml来储存配置信息。接下来,我们看如何使用dom4j来对xml文件中的元素进行增删改查。

  在使用dom4j技术时,我们需要在项目中引入dom4j-1.6.1.jar和jaxen-1.1-beta-6.jar两个jar包,并设置为依赖,这样的话,我们就可以使用这两个jar包中的API了。当然,也可以导入dom4j的其他版本,请根据需要而定。

  我们先来看读取一个xml文件,并打印到控制台上:  

 1 import org.dom4j.Document;
 2 import org.dom4j.DocumentException;
 3 import org.dom4j.io.SAXReader;
 4 import org.dom4j.io.XMLWriter;
 5 import java.io.File;
 6 import java.io.IOException;
 7 /**
 8  * 读取一个xml文件,并将其内容打印到控制台上
 9  */
10 public class Test1 {
11     public static void main(String[] args) {
12         String filePath = "book.xml";
13         Document document = readXMLFile(filePath);
14         printToControl(document);
15     }
16     private static void printToControl(Document document) {//打印到控制台
17         try {
18             XMLWriter writer = new XMLWriter();
19             writer.write(document);
20             writer.flush();
21             writer.close();
22         } catch (IOException e) {
23             e.printStackTrace();
24         }
25     }
26     private static Document readXMLFile(String filePath) {//读取一个xml文件
27         SAXReader saxReader = new SAXReader();
28         File file = new File(filePath);
29         try {
30             return saxReader.read(file);
31         } catch (DocumentException e) {
32             e.printStackTrace();
33         }
34         return null;
35     }
36 }

  执行上述代码,读取到名称为book.xml的文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<图书信息 desc="书籍信息">
  <图书>
    <书名>《战争与和平》</书名>
    <作者>列夫·托尔斯泰</作者>
    <内容>描述了拿破仑争霸时期,以俄国为社会背景的爱恨情仇</内容>
  </图书>
  <图书>
    <书名>《红楼梦》</书名>
    <作者>曹雪芹</作者>
    <内容>以贾王史薛四大家族为背景,描述了贾宝玉与林黛玉的感人爱情故事</内容>
  </图书>
</图书信息>

  我们还可以把读取到的xml文件储存到一个文件里,在此,我们在上述的Test1类里增加一个储存xml文件的方法,代码如下:

//保存xml文件到指定路径
    static boolean saveDocument(Document document,String filePath){
        OutputFormat outputFormat = OutputFormat.createPrettyPrint();
        outputFormat.setEncoding("UTF-8");
        XMLWriter writer = null;
        try {
            writer = new XMLWriter(new FileWriter(filePath), outputFormat);
            writer.write(document);
            writer.flush();
            writer.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

  上述代码执行成功后,会在项目下创建一个名称为book2.xml的文件,并返回为true。

  另外,我们还可以创建一个xml文件,这个方法返回一个Document对象,代码如下:

//创建一个xml文件
    public static Document createXMLDoc() {
        Document document = DocumentHelper.createDocument();
        Element root =  DocumentHelper.createElement("图书信息");
        document.setRootElement(root);
        root.addAttribute("desc","书籍信息");

        Element book1 = root.addElement("图书");
        Element book1_name = book1.addElement("书名");
        book1_name.addText("《战争与和平》");
        Element book1_author = book1.addElement("作者");
        book1_author.addText("列夫·托尔斯泰");
        Element book1_content = book1.addElement("内容");
        book1_content.addText("描述了拿破仑争霸时期,以俄国为社会背景的爱恨情仇");

        Element book2 = root.addElement("图书");
        Element book2_name = book2.addElement("书名");
        book2_name.addText("《红楼梦》");
        Element book2_author = book2.addElement("作者");
        book2_author.addText("曹雪芹");
        Element book2_content = book2.addElement("内容");
        book2_content.addText("以贾王史薛四大家族为背景,描述了贾宝玉与林黛玉的感人爱情故事");
        return document;
    }

  我们还可以获取父元素下指定名称的第一个节点,代码如下:

//获取父元素下的指定名称第一个节点
    static Element getFirstChildNodeByName(Element root,String nodeName){
        return (Element)root.selectSingleNode(nodeName);
    }

  我们还可以父元素下指定名称的所有节点信息,代码如下:

//获取父元素下的指定名称的所有节点
    static List<Element> getAllChildNodeByName(Element root, String nodeName){
        return root.selectNodes(nodeName);
    }

  我们再来看删除指定节点的属性,代码如下:

//删除指定节点的属性
    static void removeAttr(Element root,String nodeName,String attrName){
        Element node = root.element(nodeName);
        Attribute attr = node.attribute(attrName);
        node.remove(attr);
    }

  更改指定节点的属性值,代码如下:

//更改指定节点的属性值
    static void updateAttrVal(Element root,String nodeName,String attrName,String newValue){
        Element node = root.element(nodeName);
        Attribute attr = node.attribute(attrName);
        attr.setValue(newValue);
    }

  为指定节点添加属性值,代码如下:

//为指定节点添加属性
    static void addAttr(Element node, String attrKey, String attrValue) {
        node.addAttribute(attrKey, attrValue);
    }

  对指定节点添加子节点及其文本内容,代码如下:

//对指定节点添加子节点及其文本内容
    static Element addNode(Element parentNode,String childNode){
        Element element = parentNode.addElement(childNode);
        element.setText("haha");
        return element;
    }
原文地址:https://www.cnblogs.com/lizhangyong/p/8386522.html