XML--前浪

XML

本章目标

  • 理解XML概念及优势
  • 会编写格式良好的XML文档
  • 了解XML中特殊字符的处理方式
  • 了解解析器概念
  • 了解DOM树节点构造
  • 会使用DOM操作XML数据(添加/保存)

1. 使用XML存储数据

关键步骤如下:

  • 了解XML文档结构
  • 编写格式良好的XML文档
  • 编写保存图书信息的XML文档

1.1 认识XML

XML是Extensible Markup Language即可扩展标记语言的缩写,是一种简单的数据存储语言,使用一系列简单的标记来描述数据。XML技术应用广泛,最基本的如网站、应用程序的配置信息一般都采用XML文件描述。

XML特点如下:

  • XML与操作系统、编程语言的开发平台无关
  • 规范统一

作用如下:

  • 数据交互
  • 配置应用程序和网站
  • Ajax基石

1.2 XML 文档结构

先来了解XML文档结构,如下所示是描述图书信息的XML代码:

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <!--图书信息 -->
    <book id="bk101">
        <author>王珊</author>
        <title>.NET高级编程</title>
        <description>包含C#框架和网络编程等</description>
    </book>
    <book id="bk102">
        <author>李明明</author>
        <title>XML基础编程</title>
        <description>包含XML基础概念和基本作用</description>
    </book>
</books>
  1. XML声明

    <?xml version="1.0" encoding="UTF-8"?>表示XML声明,用以标明该文件是一个XML文档。XML文档总是以XML声明开始,它定义了XML的版本和使用的编码格式等信息。

    XML声明由以下几个部分组成:

    • version:文档符合XML 1.0规范
    • encoding:文档字符编码,默认为“UTF-8”。

    对于任何一个XML文档,其声明部分都是固定的格式。

  2. 标签
    在XML中,用尖括号<>括起来的各种标签(Tag)来标记数据,标签需成对使用来界定字符数据,例如<author>王珊</author>这一对标签中,<author>是开始标签,</author>结束标签,"王珊"是标签描述的内容,表示作者信息。XML文件可以包含任意数据。

  3. 根元素
    每个XML文档必须有且仅有一个根元素,如<books></books>

    根元素的特点如下:

    • 根元素是一个完全包括文档中其他所有元素的元素。
    • 根元素的起始标签要放在所有其他元素的起始标签之前。
    • 根元素的结束标签要放在所有其他元素的结束标签之后。
  4. 元素
    XML文档的主要部分是元素。元素由开始标签、元素内容和结束标签组成。元素内容可以包含子元素。字符数据等。如<author>王珊</author>就是一个元素。

    元素的命名规则如下:

    • 名称中可以包含字母、数字或者其他字符
    • 名称不能以数字或者标点符号开始
    • 名称不能以字符xml(或者XML,Xml)开始
    • 名称中不能包含空格
  5. 属性
    在描述图书信息的XML文档中,<book id="bk101">标签使用id属性描述图书的编号信息。属性定义语法格式如下。

    <元素名 属性名="属性值">
    

    属性值用一对双引号包含起来。

    注意:
    ① 一个元素可以有多个属性,它的基本格式为<元素名 属性名="属性值" 属性名="属性值">,多个属性之间用空格隔开

    ② 属性值中不能直接包含<"&等字符

    ③ 属性可以加在任何一个元素的起始标签上,但不能加在结束标签上。

  6. XML中的特殊字符的处理
    (1) 特殊字符需要进行转义,也就是使用XML中的预定义实体代替这些字符,对应关系如图所示:

    实体名称字符
    &lt;<
    &gt;>
    &amp;&
    &quot;"
    &apos;'

    (2) 如果在元素的文本中有大量的特殊字符,可以使用CDATA节处理。CDATA节中的所有字符都会被当作元素字符数据的常量部分,而不是XML标签。定义CDATA节的语法格式如下:<![CDATA[要显示的字符]]>

  7. XML中注释
    注释的语法格式如下:<!-- 注释内容 -->

  8. 格式良好的XML文档,需要遵循如下规则

  • 必须有XML声明语句
  • 必须有且仅有一个根元素
  • 标签大小写敏感
  • 属性值用双引号包含起来
  • 标签成对出现
  • 元素正确嵌套

1.3 XML优势

XML的优势主要体现在以下几点:

  • 数据存储
  • 数据交换
  • 数据配置

1.4 XML中的命名空间

命名空间在XML文档中可以用作元素或属性名称的名称集合,它们用来标识来自特定域(标准组织、公司、行业)的名称。

  1. 命名空间的必要性。XML解析器在解析XML文档时,对于重名的元素,可能出现解析冲突。命名空间有助于标准化元素和属性,并为它们加上唯一的标识

  2. 声明命名空间。语法格式如下

    xmlns:[prefix]="[命名空间的URI]"
    
    • prefix 是前缀名称,它用作命名空间的别名
    • xmlns 是保留属性
  3. 属性和命名空间。除非带有前缀,否则属性属于它们的元素所在的命名空间

  4. 命名空间的应用。示例如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop">
        <context:component-scan base-package="cn.smbms.controller"/>
        <aop:config></aop:config>
    </beans>
    

    在示例中声明了两个命名空间,别名分别是"context""aop"。对应URI分别是http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/aop,第一个component-scan加上了前缀context,代码它属于context代表的命名空间,另一个config加上了前缀aop,则代表它属于aop代表的命名空间。这样就是的数据更加精确。

2. XML文档的验证

关键步骤如下:

  • 使用DTD验证XML文档
  • 使用Schema验证XML文档

2.1 使用DTD验证XML文档

DTD:Document Type Definition 记文档类型定义的缩写

合法的 XML 文档是“形式良好”的 XML 文档,同样遵守文档类型定义 (DTD) 的语法规则。

内部文档声明

内部DOCTYPE 声明:

假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中

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

带有 DTD 的 XML 文档实例:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
  <!ELEMENT note (to*,from?,heading,body+)>
  <!ELEMENT to      EMPTY>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (table|foot)>
  <!ATTLIST to 
  	address CDATA #REQUIRED 
  	url CDATA #IMPLIED>
  <!ATTLIST heading 
  	message CDATA "Hello">		
]>
<note>
    <to address="NewYork" />
    <to address="Beijing" />
    <from>John</from>
    <heading>Reminder</heading>
    <body>
    	<foot>foot</foot>
    </body>
</note> 
  • PCDATA(Parsed CDATA):可以是字符串、子元素、字符串和子元素
  • CDATA(Character Data):是指字符串
  • EMPTY:是指元素不能有内容,不能有尾标签

以上 DTD 解释如下:

  • !DOCTYPE note (第二行)定义此文档是 note 类型的文档。
  • !ELEMENT note (to*,from?,heading,body+) (第三行)定义 note 元素有四个子元素:“to、from、heading,、body”
    • to*:to元素在父级元素note可以出现0次或者任意多次
    • from?:from元素在父级元素note只能出现0次或者1次
    • heading:heading元素在父级元素note下只能出现一次
    • body+:body元素在父级元素note下最少出现一次,可以出现多次
  • !ELEMENT to (第四行)定义 to 元素为不能有内容,不能有尾标签,如:<to />
  • !ELEMENT from (第五行)定义 from 元素为 “#PCDATA” 类型
  • !ELEMENT heading (第六行)定义 heading 元素为 “#PCDATA” 类型
  • !ELEMENT body (table|foot) (第七行)定义 body 元素下为tablefoot,二者只能出现其一
  • !ATTLIST to定义to元素下的属性,分别为addressurl
  • #REQUIRED:属性是必须的
  • #IMPLIED :属性不是必须的
  • <!ATTLIST heading message CDATA "Hello">:定义heading元素下的属性名为message,使用字符串赋值,默认值为:Hello

DTD元素中一些符号的用途如表所示:

符号用途示例示例说明
( )用来给元素分组(古龙|金庸|梁羽生),(王朔|余杰),毛毛表示分成三组
|在列出的对象中选择一个(男人|女人)表示男人或者女人必须出现,并且两者至少选其一
对象必须按指定的顺序出现(西瓜,苹果,香蕉)表示西瓜、苹果、香蕉必须出现,并且按这个顺序出现
*该对象允许出现零次到任意多次(0或者多次)(爱好*)爱好可以出现零次或多次
该对象可以出现,但只能出现一次(0或1次)(菜鸟?)菜鸟可以出现,也可以不出现,如果出现的话,最多只能出现一次
+该对象最少出现一次,可以出现多次(1或多次)(成员+)表示成员必须出现,而且可以出现多个成员

以下是属性类型的选项:

类型描述
CDATA值为字符数据 (character data)
(en1|en2|…)此值是枚举列表中的一个值
ID值为唯一的 id
IDREF值为另外一个元素的 id
IDREFS值为其他 id 的列表
NMTOKEN值为合法的 XML 名称
NMTOKENS值为合法的 XML 名称的列表
ENTITY值是一个实体
ENTITIES值是一个实体列表
NOTATION此值是符号的名称
xml:值是一个预定义的 XML 值

默认值参数可使用下列值:

解释
属性的默认值
#REQUIRED属性值是必需的
#IMPLIED属性不是必需的
#FIXED value属性值是固定的
外部文档声明

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

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

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

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

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
    <to address="NewYork" />
    <to address="Beijing" />
    <from>John</from>
    <heading>Reminder</heading>
    <body>
    	<foot>foot</foot>
    </body>
</note> 

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

<!DOCTYPE note [
  <!ELEMENT note (to*,from?,heading,body+)>
  <!ELEMENT to      EMPTY>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (table|foot)>
  <!ATTLIST to 
  	address CDATA #REQUIRED 
  	url CDATA #IMPLIED>
  <!ATTLIST heading 
  	message CDATA "Hello">		
]>

2.2 使用Schema验证XML文档

XML Schema 是基于 XML 的 DTD 替代者。

XML Schema 描述 XML 文档的结构。

XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。

什么是 XML Schema?

XML Schema 的作用是定义 XML 文档的合法构建模块,类似 DTD。

XML Schema:
  • 定义可出现在文档中的元素
  • 定义可出现在文档中的属性
  • 定义哪个元素是子元素
  • 定义子元素的次序
  • 定义子元素的数目
  • 定义元素是否为空,或者是否可包含文本
  • 定义元素和属性的数据类型
  • 定义元素和属性的默认值以及固定值
XML Schema 是 DTD 的继任者

我们认为 XML Schema 很快会在大部分网络应用程序中取代 DTD。

理由如下:
  • XML Schema 可针对未来的需求进行扩展
  • XML Schema 更完善,功能更强大
  • XML Schema 基于 XML 编写
  • XML Schema 支持数据类型
  • XML Schema 支持命名空间
一个简单的XML文档

请看这个名为 “note.xml” 的 XML 文档:

<?xml version="1.0" encoding="utf-8"?>
<note>
    <to id="12" />
    <to id="23" />
    <from>John</from>
    <heading>Reminder</heading>
    <body>
    	<foot>foot</foot>
    </body>
</note> 

下面这个例子是一个名为 “note.xsd” 的 XML Schema 文件,它定义了上面那个 XML 文档的元素:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
		xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		elementFormDefault="qualified">

	<!--定义元素to  -->
	<xsd:element name="to"  >
		<xsd:complexType>
			<!--定义to元素的属性id 引用上面定义的id属性-->
			 <!--定义属性id 要求值是必须的 而且必须为正整数-->
            <xsd:attribute name="id" use="required" type="xsd:positiveInteger"/>
		</xsd:complexType>
	</xsd:element>
 

	<!--定义元素note 包含子元素 -->
	<xsd:element name="note">
		<xsd:complexType>
			<xsd:sequence>
               <!--定义note的子元素to 出现0次或者任意多次 -->
				<xsd:element ref="to"  maxOccurs="unbounded" 
					minOccurs="0" />
				 <!--定义note的子元素from 出现0次或者1次 -->
				<xsd:element name="from" type="xsd:string" maxOccurs="1"
					minOccurs="0" />
                <!--定义note的子元素heading 只能出现一次 -->
				<xsd:element name="heading" type="xsd:string" />
                 <!--定义note的子元素body 出现1次或者任意多次 -->
				<!--定义元素body 包含子元素 -->	
				<xsd:element ref="body" maxOccurs="unbounded" minOccurs="1" >
					 <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="foot" type="xsd:string"/>
                        </xsd:sequence>
                    </xsd:complexType>
				</xsd:element>
			</xsd:sequence>
			<!--定义元素note 的id属性 引用定义的属性 -->
			<xsd:attribute ref="id" use="required" />
		</xsd:complexType>
	</xsd:element>
</xsd:schema>
对 XML Schema 的引用

此文件包含对 XML Schema 的引用:

<?xml version="1.0" encoding="UTF-8" ?>
<note xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="note.xsd" id="1">
    <to id="12" />
    <to id="23" />
    <from>John</from>
    <heading>Reminder</heading>
    <body>
    	<foot>foot</foot>
    </body>
</note>
XSD 元素
元素解释
all规定子元素能够以任意顺序出现,每个子元素可出现零次或一次。
annotationannotation 元素是一个顶层元素,规定 schema 的注释。
any使创作者可以通过未被 schema 规定的元素来扩展 XML 文档。
anyAttribute使创作者可以通过未被 schema 规定的属性来扩展 XML 文档。
appInfo规定 annotation 元素中应用程序要使用的信息。
attribute定义一个属性。
attributeGroup定义在复杂类型定义中使用的属性组。
choice仅允许在 <choice> 声明中包含一个元素出现在包含元素中。
complexContent定义对复杂类型(包含混合内容或仅包含元素)的扩展或限制。
complexType定义复杂类型。
documentation定义 schema 中的文本注释。
element定义元素。
extension扩展已有的 simpleType 或 complexType 元素。
field规定 XPath 表达式,该表达式规定用于定义标识约束的值。
group定义在复杂类型定义中使用的元素组。
import向一个文档添加带有不同目标命名空间的多个 schema。
include向一个文档添加带有相同目标命名空间的多个 schema。
key指定属性或元素值(或一组值)必须是指定范围内的键。
keyref规定属性或元素值(或一组值)对应指定的 key 或 unique 元素的值。
list把简单类型定义为指定数据类型的值的一个列表。
notation描述 XML 文档中非 XML 数据的格式。
redefine重新定义从外部架构文件中获取的简单和复杂类型、组和属性组。
restriction定义对 simpleType、simpleContent 或 complexContent 的约束。
schema定义 schema 的根元素。
selector指定 XPath 表达式,该表达式为标识约束选择一组元素。
sequence要求子元素必须按顺序出现。每个子元素可出现 0 到任意次数。
simpleContent包含对 complexType 元素的扩展或限制且不包含任何元素。
simpleType定义一个简单类型,规定约束以及关于属性或仅含文本的元素的值的信息。
union定义多个 simpleType 定义的集合。
unique指定属性或元素值(或者属性或元素值的组合)在指定范围内必须是唯一的。

详细说明请参考官方手册:https://www.w3school.com.cn/schema/schema_elements_ref.asp

3. 使用DOM解析XML

关键步骤如下:

  • 使用DOM读取XML数据
  • 使用DOM添加XML数据
  • 使用DOM修改XML数据
  • 使用DOM删除XML数据

3.1 XML解析

在实际应用中,经常需要对XML文档进行各种操作。例如,在应用程序启动时读取XML配置文件信息,或者把数据库中的内容读取出来转换为XML文档形式,这是都会用到XML文档的解析技术。

目前常用的XML解析技术有4种:

  1. DOM

    DOM:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。其优缺点分别为:

    优点:把XML文件在内存中构造树形结构,可以遍历和修改节点

    缺点:如果文件比较大,内存有压力,解析的时间会比较长

  2. SAX

    SAX(simple API for XML)是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析。 其优缺点分别为:

    优点: 解析可以立即开始,速度快,没有内存压力

    缺点: 不能对节点做修改

  3. DOM4J

    非常优秀的Java XML API

    性能优异、功能强大

    开放源代码。官网:https://dom4j.github.io/

3.2 使用DOM读取XML数据

1. DOM概念

DOM(Document Object Model)把XML文档映射成一个倒挂的树,如图所示:
在这里插入图片描述

Oracle公司提供了JAXP(Java API for XML Processing)来解析XML。JAXP会把XML文档转换成一个DOM树。JAXP包含3个包,这3个包都在JDK中:

  • org.w3c.dom:W3C推荐的用于使用DOM解析XML文档的接口
  • org.xml.sax:用于使用SAX解析XML文档的接口
  • javax.xml.parsers:解析器工厂工具,通过该包下的类可以获得并配置特殊的分析器。如:通过调用DocumentBuilder类的parse(XML文件名)方法,可以得到解析XML文件的Document对象

DOM解析使用到的类都在这些包中,在使用DOM解析XML时需要导入这些相关的类。

2. 使用DOM读取手机收藏信息

使用DOM解析XML文件步骤如下:

  • 创建解析器工厂对象,即:DocumentBuilderFactory对象
  • 由解析器工厂对象创建解析器对象,即:DocumentBuilder对象
  • 由解析器对象对指定的XML文件进行解析,构建对应的DOM树,创建Document对象
  • 以Document对象为起点对DOM树的节点进行增加、删除、修改、查询等操作

下面通过示例使用DOM读取XML数据

手机收藏信息中的品牌和型号信息的XML文档代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<PhoneInfo>
    <Brand name="华为">
        <Type name="U8650"/>
        <Type name="HW123"/>
        <Type name="HW321"/>
    </Brand>
    <Brand name="苹果">
        <Type name="iPhone4"/>
    </Brand>
</PhoneInfo>
访问DOM树节点
  • 显示收藏信息.xml文件中收藏的手机品牌和型号

    DOM解析XML文件步骤

    1. 创建解析器工厂对象

    2.解析器工厂对象创建解析器对象

    3.解析器对象指定XML文件创建Document对象

    4.以Document对象为起点操作DOM树

示例代码如下:

//DOM解析XML文件步骤
//创建解析器工厂对象
//1.创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//2.解析器工厂对象创建解析器对象
DocumentBuilder builder =  factory.newDocumentBuilder();
//3.解析器对象指定XML文件创建Document对象
Document doc = builder.parse(new File("src/收藏信息.xml"));
//4.以Document对象为起点操作DOM树
//获取所有brand节点列表信息
NodeList list = doc.getElementsByTagName("Brand");
System.out.println("手机\t型号");
for (int i = 0; i < list.getLength(); i++) {
    Element element = (Element)list.item(i);
    String name = element.getAttribute("name");
    //获取所有Type节点列表信息
    NodeList typeNodes = element.getElementsByTagName("Type");
    for (int j = 0; j < typeNodes.getLength(); j++) {
        Element type = (Element)typeNodes.item(j);
        String typeName = type.getAttribute("name");
        //获取元素的文本节点信息
        //String text = type.getTextContent();
        System.out.println(name+"\t"+typeName);
    }
}

常用的接口以及接口中方法说明如下表所示:

常用接口常用方法说明
Document:表示整个 XML 文档NodeList getElementsByTagName(String Tag)按文档顺序返回文档中指定标记名称的所有元素集合
Element createElement(String tagName)创建指定标记名称的元素
Node:该文档树中的单个节点NodeList getChildNodes()获取该元素的所有子节点,返回节点集合
Element:XML 文档中的一个元素String getTagName()获取元素名称
保存XML文件
  • 步骤如下:
  1. 获得TransformerFactory对象
  2. 创建Transformer对象
  3. 创建Document对象并添加节点信息
  4. 创建DOMSource对象 (包含XML信息)
  5. 设置输出属性(字符编码以及输出格式)
  6. 创建StreamResult对象(包含保存文件的信息)
  7. 将XML保存到指定文件中

示例代码如下:

//1. 获得TransformerFactory对象
TransformerFactory factory = TransformerFactory.newInstance();
//2. 创建Transformer对象
Transformer transformer = factory.newTransformer();
//3. 创建Document对象并添加节点信息
//3.1.创建解析器工厂对象
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
//3.2.解析器工厂对象创建解析器对象
DocumentBuilder builder =  docFactory.newDocumentBuilder();
//3.3. 使用解析器对象创建Document对象
Document doc = builder.newDocument();

//3.4. 使用Document对象创建PhoneInfo节点
Element phoneInfo = doc.createElement("PhoneInfo");
//将PhoneInfo节点追加到文档的子节点中
doc.appendChild(phoneInfo);

//3.5. 使用Document对象创建Brand节点
Element huawei = doc.createElement("Brand");
//华为
huawei.setAttribute("name", "华为");
//huawei.setTextContent("设置元素内容");
//将Brand节点追加至PhoneInfo子节点中
phoneInfo.appendChild(huawei);

//3.6. 使用Document对象创建Type节点
Element type = doc.createElement("Type");
type.setAttribute("name", "U8650");
//将Type节点追加至华为的子节点中
huawei.appendChild(type);
type = doc.createElement("Type");
type.setAttribute("name", "HW123");
huawei.appendChild(type);
type = doc.createElement("Type");
type.setAttribute("name", "HW321");
huawei.appendChild(type);

//苹果
Element phone = doc.createElement("Brand");
phone.setAttribute("name", "苹果");
phoneInfo.appendChild(phone);
//创建子节点Type
type = doc.createElement("Type");
type.setAttribute("name", "iPhone4");
phone.appendChild(type);

//4. 创建DOMSource对象 (包含XML信息)
DOMSource source = new DOMSource(doc);
//5. 设置输出属性(字符编码、版本号以及输出格式)
transformer.setOutputProperty("encoding", "utf-8");
transformer.setOutputProperty("version", "1.0");
transformer.setOutputProperty("indent", "yes");
//6. 创建StreamResult对象(包含保存文件的信息)
StreamResult result = new StreamResult(new FileOutputStream("src/news.xml"));
//7. 将XML保存到指定文件中
transformer.transform(source, result);
System.out.println("写入成功");
添加DOM节点

给手机收藏信息XML中添加新的手机信息

  • 添加新的Brand:三星

  • 给Brand节点添加新的子标签Type:Note4

  • 将Brand添加到DOM树中

实现步骤如下:

  • 1.为XML文档构造DOM树
  • 2.创建新节点,并设置子节点
  • 3.将节点加到其所属父节点上
  • 4.保存XML文档

示例代码如下:

//1.创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//2.解析器工厂对象创建解析器对象
DocumentBuilder builder =  factory.newDocumentBuilder();
//3.解析器对象指定XML文件创建Document对象
String fileName = "src/收藏信息.xml";
Document doc = builder.parse(new File(fileName));
//4.以Document对象为起点操作DOM树
//获取PhoneInfo节点
Element phoneInfo = (Element)doc.getElementsByTagName("PhoneInfo").item(0);
//创建Brand节点分别设置name属性
Element san = doc.createElement("Brand");
san.setAttribute("name", "三星");
//将其追加到PhoneInfo节点下
phoneInfo.appendChild(san);
//
Element type = doc.createElement("Type");
type.setAttribute("name", "note4");
san.appendChild(type);

//获得TransformerFactory对象
TransformerFactory transFactory = TransformerFactory.newInstance();
//创建Transformer对象
Transformer transformer = transFactory.newTransformer();
//设置格式化输出
transformer.setOutputProperty("indent", "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new FileOutputStream(fileName));
transformer.transform(source, result);
System.out.println("添加成功!!");		
修改DOM节点

修改手机收藏信息,需求如下:

  • 给所有的Brand标签添加id属性,并分别赋值
  • 将品牌信息为“华为”的节点属性修改为“HuaWei”

实现步骤如下:

  • 1.为XML文档构造DOM树
  • 2.找到符合修改条件的节点
  • 3.为该节点增加新的属性id,并为id赋值
  • 4.找到name属性的值为“华为”的节点,修改值为“HuaWei”
  • 5.保存XML文档

示例代码如下:

//1.创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//2.解析器工厂对象创建解析器对象
DocumentBuilder builder =  factory.newDocumentBuilder();
//3.解析器对象指定XML文件创建Document对象
String fileName = "src/收藏信息.xml";
Document doc = builder.parse(new File(fileName));
//4.以Document对象为起点操作DOM树
//获取所有brand节点列表信息
NodeList phoneInfo = doc.getElementsByTagName("Brand");
for (int i = 0; i < phoneInfo.getLength(); i++) {
	Element node = (Element)phoneInfo.item(i);
	//增加id属性
	node.setAttribute("id", i+1+"");
	if(node.getAttribute("name").equals("华为")) {
		//为name属性设置值
		node.setAttribute("name", "HuaWei");
	}
}

//获得TransformerFactory对象
TransformerFactory transFactory = TransformerFactory.newInstance();
//创建Transformer对象
Transformer transformer = transFactory.newTransformer();
//设置格式化输出
transformer.setOutputProperty("indent", "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new FileOutputStream(fileName));
transformer.transform(source, result);
System.out.println("修改成功!!");
删除DOM节点

删除手机收藏信息,需求如下:

  • 删除手机品牌信息“三星”

实现步骤如下:

  • 1.为XML文档构造DOM树
  • 2.找到符合删除条件的节点
  • 3.调用该节点的方法获取父节点,通过父节点删除子节点
  • 4.保存XML文档

示例代码如下:

//1.创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//2.解析器工厂对象创建解析器对象
DocumentBuilder builder =  factory.newDocumentBuilder();
//3.解析器对象指定XML文件创建Document对象
String fileName = "src/收藏信息.xml";
Document doc = builder.parse(new File(fileName));
//4.以Document对象为起点操作DOM树
//获取所有brand节点列表信息
NodeList phoneInfo = doc.getElementsByTagName("Brand");
for (int i = 0; i < phoneInfo.getLength(); i++) {
	Element node = (Element)phoneInfo.item(i);
	if(node.getAttribute("name").equals("三星")) {
		//删除 找到该节点的父节点实现其子节点的删除功能
		node.getParentNode().removeChild(node);
	}
}

//获得TransformerFactory对象
TransformerFactory transFactory = TransformerFactory.newInstance();
//创建Transformer对象
Transformer transformer = transFactory.newTransformer();
//设置格式化输出
transformer.setOutputProperty("indent", "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new FileOutputStream(fileName));
transformer.transform(source, result);
System.out.println("删除成功!!");

4. 使用 DOM4J 解析XML

关键步骤如下:

  • 了解DOM4J的相关接口
  • 使用DOM4J读取、添加、修改、删除XML数据

补充知识:

DOM4J是目前使用非常广泛的一种解析XML的技术,与DOM相比,其使用灵活,操作简单,学习时要灵活理解几个重要接口的用法。DOM4J官网https://dom4j.github.io/

4.1 DOM4J解析

DOM4J是 dom4j.org 出品的一个开源 XML 解析包。DOM4J应用于 Java 平台,采用了 Java 集合框架并完全支持 DOM,SAX 和 JAXP。

DOM4J 使用起来非常简单。只要你了解基本的 XML-DOM 模型,就能使用。

DOM4J 最大的特色是使用大量的接口。

它的主要接口都在org.dom4j里面定义:

Attribute定义了 XML 的属性。
Branch指能够包含子节点的节点。如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为
CDATA定义了 XML CDATA 区域
CharacterData是一个标识接口,标识基于字符的节点。如CDATA,Comment, Text.
Comment定义了 XML 注释的行为
Document定义了XML 文档
DocumentType定义 XML DOCTYPE 声明
Element定义XML 元素
ElementHandler定义了Element 对象的处理器
ElementPath被 ElementHandler 使用,用于取得当前正在处理的路径层次信息
Entity定义 XML entity
Node为dom4j中所有的XML节点定义了多态行为
NodeFilter定义了在dom4j 节点中产生的一个滤镜或谓词的行为(predicate)
ProcessingInstruction定义 XML 处理指令
Text定义 XML 文本节点
Visitor用于实现 Visitor模式
XPath在分析一个字符串后会提供一个 XPath 表达式

4.2 使用DOM4J操作XML

1. 读取XML文档

使用DOM4J读取手机收藏信息

实现步骤如下:

  • 1.导入DOM4J的jar包
  • 2.指定要解析的XML文件
  • 3.把XML文件转换成Document对象
  • 4.获取节点属性或文本的值

关键代码如下:

SAXReader reader = new SAXReader();
Document doc = reader.read(new File("src/news.xml"));
// 获取XML的根节点
Element root = doc.getRootElement();
// 遍历所有的Brand标签
for(Iterator<Element> its = root.elementIterator();its.hasNext();) {
    Element item = its.next();
    //Attribute attr = item.attribute("name");
    // 输出标签的name属性
    System.out.println("手机品牌是:"+item.attributeValue("name"));
    // 遍历Type标签
    for(Iterator<Element> types = item.elementIterator();types.hasNext();) {
        Element type = types.next();
        //获取元素内容
        //System.out.println(type.getText());
        //Attribute at = type.attribute("name");
        // 输出标签的name属性
        System.out.println("型号是:"+type.attributeValue("name"));
    }
}
2. 保存XML文档

使用DOM4J保存手机收藏信息

实现步骤如下:

  • 1.导入DOM4J的jar包
  • 2.使用DocumentHelper创建Document对象
  • 3.创建根节点
  • 4.创建子节点并添加属性值

关键代码如下:

//使用DocumentHelper创建Document对象
Document document = DocumentHelper.createDocument();
//创建根节点
Element phoneInfo = document.addElement("PhoneInfo");
//华为
Element brand = phoneInfo.addElement("Brand").addAttribute("name", "华为");
brand.addElement("Type").addAttribute("name", "U8650");
brand.addElement("Type").addAttribute("name", "HW123");
brand.addElement("Type").addAttribute("name", "HW321");
//苹果
Element phone = phoneInfo.addElement("Brand").addAttribute("name", "苹果");
phone.addElement("Type").addAttribute("name", "iPhone4");
phone.addElement("Type").addAttribute("name", "iPhone12").setText("元素内容");
//三星
Element san = phoneInfo.addElement("Brand").addAttribute("name", "三星");
san.addElement("Type").addAttribute("name", "note4");
san.addElement("Type").addAttribute("name", "note5").setText("元素内容");
//设置输出格式
OutputFormat format = OutputFormat.createPrettyPrint();
FileWriter out = new FileWriter("foo.xml");
XMLWriter writer = new XMLWriter(out, format);
writer.write(document);
out.close();
System.out.println("写入成功!!");
3. 修改XML文档
  • 修改手机收藏信息,需求如下:

    • 给所有的Brand标签添加id属性,并分别赋值
    • 将品牌信息为“华为”的节点属性修改为“HuaWei”

实现步骤如下:

  • 1.导入DOM4J的jar包
  • 2.指定要解析的XML文件
  • 3.把XML文件转换成Document对象
  • 4.修改子节点属性

关键代码如下:

SAXReader reader = new SAXReader();
String path = "src/news.xml";
Document document = reader.read(new File(path));
Element root = document.getRootElement();
int id = 0;
//遍历子节点
for (Iterator<Element> it = root.elementIterator(); it.hasNext();) {
    Element element = it.next();
    id++;
    element.addAttribute("id", id+"");
    if(element.attribute("name").getValue().equals("华为")) {
        element.addAttribute("name", "huawei");
        //element.addText("设置元素内容");
    }
}

//设置输出格式
OutputFormat format = OutputFormat.createPrettyPrint();
FileWriter out = new FileWriter(path);
XMLWriter writer = new XMLWriter(out, format);
writer.write(document);
out.close();
System.out.println("修改成功!!");
4. 删除XML文档

删除手机收藏信息,需求如下:

  • 删除手机品牌信息“三星”

实现步骤如下:

  • 1.导入DOM4J的jar包
  • 2.指定要解析的XML文件
  • 3.把XML文件转换成Document对象
  • 4.获取根节点
  • 5.遍历子节点,找到符合条件的子节点
  • 6.调用该节点的方法获取父节点,通过父节点删除子节点

代码如下:

SAXReader reader = new SAXReader();
String path = "src/news.xml";
Document document = reader.read(new File(path));
Element root = document.getRootElement();
for(Iterator<Element> its = root.elementIterator();its.hasNext();) {
    Element brand = its.next();
    if("三星".equals(brand.attributeValue("name"))) {
        brand.getParent().remove(brand);
    }
}
//设置输出格式
OutputFormat format = OutputFormat.createPrettyPrint();
FileWriter writer = new FileWriter(path);
XMLWriter xml = new XMLWriter(writer,format);
xml.write(document);
writer.close();
System.out.println("删除成功!!");
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值