前言
想必大家在日常工作或者开发中都会直接或者间接地使用到xml格式的文件,它存在于项目的配置文件中,也可能是作为服务器间系统交互的数据文件,那么你是否知道这种文件的作用是什么呢?你是否了解我们是如何获取文件中的数据的呢?对于一个开发人员来说,了解和掌握XML文件的使用是很有必要的。本篇文章将围绕XML文件的产生背景、文档的定义、解析和约束等进行讲解,希望能够让各位读者有所收获。
本篇文章是XML系列的上篇,对JAVA如何转换XML文件有兴趣的读者可以看完本篇文章后翻阅后篇:
XML系列(下篇)——Java和XML的这些事你可能真的不知道
一、什么是XML?
XML的全称是EXtensible Markup Language
,翻译成中文就是可拓展标记语言,听到这个名字大家可能会觉得有点耳熟,HTML叫超文本标记语言,这两者是不是有什么关系呢?
答案是,还真有关系。XML可以说是对HTML(局限性)的一种补充。
(一)XML的产生背景
在XML产生之前,就已经有了SGML((Standard Generalized Markup Language:标记通用语言)和HTML两种标记语言了,前者文档结构庞杂,主要用于大量高度结构化数据的访问和其他各种工业领域,后者由于其简单和跨平台性而广泛应用于Web服务的传输文件。同时二者都有着较为明显的缺点,SGML使用复杂,相关软件昂贵,而HTML则有着无法描述数据、可读性差等局限性。
随着Web应用的不断发展,而HTML又无法很好满足人们对数据的需求,这时人们又把目光转向SGML,再次改造SGML使之适应现在的网络需求。随着先辈的努力,1998年2月10日,W3C(World Wide Web Consortium,万维网联盟)公布XML 1.0标准,XML诞生了。
可以说,XML是在补充HTML局限性背景下的产物。
(二)XML的作用
XML格式文件如今已在我们工作中发挥重要的作用,总结起来主要是以下两点:
1. 作为存储数据的文件载体(基础)
2. 可以作为交换数据在不同系统、不同项目的通信间进行传输
二、XML文档的声明
(一)XML文档的定义
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
定义一个XML文档是十分简单的,其必要条件只有2个:
1. XML文档的头部至少要有<? xml version="1.0" ?>
2. 文档中至少拥有1个根标签
XML头部属性介绍如下:
- version:解析这个文档的时候用的是什么版本的解析器
- encoding:解析xml中文字的时候用的是哪种编码
- standlone: no: 该文档会依赖关联其他文档,yes:这是一个独立文档
(二)XML的文档结构
<?xml version="1.0" encoding="UTF-8"?>
<school>
<teachers>
<teacher>
<name>李连杰</name>
<age>25</age>
</teacher>
<teacher>
<name>李小龙</name>
<age>65</age>
</teacher>
</teachers>
<students>
<student>
<name>成龙</name>
<age>14</age>
</student>
<student>
<name>小明</name>
<age>12</age>
</student>
</students>
</school>
XML文档的阅读性较好,一个父标签下会嵌套1个或者多个子标签,子标签内可能还嵌套了子子标签。我们可以很容易的联想到,XML文档可以用树结构来表示。以上图为例,具体可以描述成下面这幅图:
XML解析树形图
(三)XML的元素和属性
元素的标签
XML中的元素(标签)可以分为简单元素和复杂元素。简单元素的内容是常见的string、int类型等数据,复杂元素是指标签里面嵌套了其他的元素的标签。比如下面的例子中student
属于复杂元素,name
属于简单元素。
元素的属性
属性定义在标签之间。比如下面例子中的id就是student
标签的属性。
<student id="9527">
<name>成龙</name>
<age>14</age>
</student>
(四)XML文档的注释
XML文档的注释和HTML一样,采用<!-- -->
的方式进行注释。这个没啥好说的
三、XML文档的CDATA
打开XML文档时,所有 XML 文档中的文本均会被解析器解析。当某个 XML 元素被解析时,其标签之间的文本也会被解析:只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。听上去似乎有点绕,我们举一个小例子吧。
CDATA案例演示
从上面的例子我们可以看到,对于一些特殊的文本内容,解析器可以会将其解析为标签符号。所以我们需要用转义字符来对此进行处理。
术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。常用的转移字符有如下五个:
转移字符 | 符号 | 含义 |
---|---|---|
< | < | 小于 |
> | > | 大于 |
& | & | 和号 |
' | ' | 省略号 |
" | " | 引号 |
(严格意义上来说,只有<
和&
不能被XML解析器正确的解析,但出于良好的编码习惯,建议还是都用转移字符)
如果文本中用到的特殊符号很多的话,,就可以用<![CDATA[ ]]>
来进行包裹。让XML解析器忽略这段文本内容解析。
<script>
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then
{
return 1;
}
else
{
return 0;
}
}
]]>
</script>
四、XML的解析方式
有关XML的解析方式网上流传的有DOM、SAX、dom4j、jdom乃至java中的JAXP、JAXB等等,但是本质上,XML的解析方式只有两种,DOM
和SAX
,其他的方式都是基于这两种解析标准进行的封装。也可以这么理解,由于读取方式不同,DOM和SAX定义了两种不同的标准(接口),我们现在使用的各种API是这两类接口的具体实现。
两种解析方式的介绍
DOM : document object model
把整个xml全部读到内存当中,形成树状结构。整个文档称之为document对象,属性对应Attribute对象,所有的元素节点对应Element对象,文本也可以称之为Text对象,以上所有对象都可以称之为Node节点。如果xml文件特别大,那么将会造成内存溢出。可以对文档进行增删操f作
SAX : Simple API for Xml
基于事件驱动。读取一行,解析一行。这种方式不会造成内存溢出。但不可以进行增删,只能查询。
我们可以看到,两种解析方式风格迥异,DOM虽然方便但是对内存的消耗比较大,在项目应用具体选择可以根据实际需要来定。
五、XML的解析手段
目前来说,由于dom4j
性能优异、功能强大和易于使用、开源的特点,使其成为了解析XML文档的最多选择之一。下面我们将简单演示一下dom4j
的使用。(想要了解更多解析XML的使用方式,可以参考本系列下篇文章。)
在springboot项目下引入如下依赖:
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- dom4j的jar包 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
<!-- dom4j使用XPath需要的jar包 -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
SpringBoot项目已经集成了junit
的包,可以不用引。如果是普通的java项目,就需要引入一下。
验证的主要步骤为:
1. 通过SAXReader对象读取和解析xml文件,获得Document对象,即xml树;
2. 调用Node的方法遍历打印xml树的节点;
3. 使用XPath查询指定节点。
具体的测试代码如下:
@Test
public void parseXmlByDom4j(){
// 1、 创建SAXReader对象
SAXReader reader = new SAXReader();
try{
// 2、指定要解析的XML文件
Document document = reader.read("这里写实际的xml文件存储路径").getDocument();
// 3、 遍历所有teacer节点下的内容
Element rootElement = document.getRootElement();
for (Element element : rootElement.element("teachers").elements()) {
String qname = element.getQName().getName();
String teacherName = element.element("name").getText();
String teacherAge = element.element("age").getText();
System.out.println(qname + ": name = " + teacherName + " age = " + teacherAge);
}
}catch (Exception e){
e.printStackTrace();
}
}
使用dom4j输出结果
六、XML的约束
我们知道,XML文档中可以让我们写入各种自定义的Tag
标签和其他属性,不过在实际应用中,我们往往会希望有一个文件可以约束XML文档中的书写规范,比如说这个xml文件是关于学校人员的信息,但文档中出现了<apple>
、<aaa>
这些毫无关联的标签就会变得很奇怪。为了避免文档中出现的不符合实际需要,不符合规范要求的文档,有一份对于XML的书写格式进行约束的文件,就很有必要了。
DTD
和Schema
都是基于这种实际需要的背景下出现的产物,其中DTD
出现的时间较早,但后起之秀Schema
却由于其功能更加强大,文档阅读性更好而被更多开发人员所使用。但目前来说,虽然Schema被认为未来将完全取代DTD约束,但现状还是有部分项目还有使用DTD
进行XML文档约束的。
下面将对两种约束的使用进行简单的讲解:
(一)DTD
引用DTD约束的三种方式:
- 在XML文档内部引入:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 根元素 [元素声明]>
- 引入XML外部的文档
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 根元素 SYSTEM "文件名">
- 引入网络上的DTD(需要网络资源)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 根元素 PUBLIC "DTD的位置" "文件名">
DTD的使用介绍
DTD的元素声明
<!ELEMENT 元素名称 (元素内容)>
DTD的属性声明
<!ATTLIST 元素名称 属性名称 属性类型 默认值>`
我们举个例子:
DTD演示用例
(二)Schema
介绍Schema之前,我们先看一份Schema文件长什么样子:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3school.com.cn"
xmlns="http://www.w3school.com.cn"
elementFormDefault="qualified">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
实际上,schema文件是以.xsd
作为文件格式后缀的,但其文件还是由XML来编写的,那么这样就存在一个问题,schema文件用来约束我们普通的XML文档,那么由XML编写的schema文件又应该让谁来约束呢?
答案是schema文件最终需要对标W3C的标准来编写。
如何在XML文件中引用Schema约束
<?xml version="1.0"?>
<文档类型 xmlns="http://www.w3school.com.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3school.com.cn schema文件名">
一般来说,我们需要只需要设置schemaLocation 属性即可。此属性有两个值。第一个值是需要使用的命名空间。第二个值是供命名空间使用的 XML schema 的位置。
如何书写Schema:
schema简单元素书写格式:
<xs:element name="xxx" type="yyy"/>
schema复杂元素书写格式:
<xs:element name="xxx">
<xs:complexType>
<xs:sequence>
<xs:element name="xxx" type="xs:yyy"/>
<xs:element name="xxx" type="xs:yyy"/>
</xs:sequence>
</xs:complexType>
</xs:element>
# 此处 xxx 指元素的名称,yyy 指元素的数据类型。
schema属性书写格式:
<xs:attribute name="xxx" type="yyy"/>
# 在此处,xxx 指属性名称,yyy 则规定属性的数据类型。
简单元素即只是一个内容为文本、数字,没有属性的简单标签,复杂标签往往嵌套了多个标签。
下面我们来举一个例子:
先看Schema文件内容:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.xiaoming.com.cn/school"
elementFormDefault="qualified">
<xs:element name="school">
<xs:complexType>
<xs:sequence>
<xs:element name="teachers" >
<xs:complexType>
<xs:sequence>
<xs:element name="teacher" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="students" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
有关元素的这里就不再赘述,定义Schema文件时需要注意的细节有两个。
1. 我们可以使用maxOccurs和minOccurs来定义某个元素出现的最大/最小次数,unbounded
表示没有限制
2. 定义Schema时,要注意头部<schema>
的书写:
-
xmlns:xs 这部分基本是固定的写法,表示schema 中用到的元素和数据类型来自命名空间"http://www.w3.org/2001/XMLSchema"。同时它还规定了相关元素和数据类型的使用需要加前缀
xs
-
targetNamespace 这个是可以自定义的,xml文件会用到,主要是和xml文件的
xmlns
相匹配 - elementFormDefault 这个部分一般也是固定的写法,表示任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定。
再来看XML文档的内容:
<?xml version="1.0" encoding="UTF-8"?>
<school
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://www.xiaoming.com.cn/school"
xsi:schemaLocation="http://www.xiaoming.com.cn/school test.xsd">
<teachers>
<teacher>
<name>李连杰</name>
<age>25</age>
</teacher>
<teacher>
<name>李小龙</name>
<age>65</age>
</teacher>
</teachers>
<students></students>
</school>
XML文档的内容没有什么特别的,关键在于在根标签<school>中定义了三个属性,使其和对应的.xsd
文件关联在了一起。主要的属性有三个,含义分别如下:
1. xmlns:xsi 这部分的内容基本固定,表示是schema文件的实例(这一块比schema的内容相比多了-instance
)
2. xmlns 这部分需要和对应.xsd
文件中的targetNamespace
中的内容保持一致
3. xsi:schemaLocation 这部分的内容为 .xsd
文件中的targetNamespace
+ .xsd
文件的存储位置 (这里因为是同级,所以就直接是文件名)
至此,对于XML的入门已经介绍完毕。如果对XML、DTD、Schema等知识点需要更深入了解的话,可以在W3C官网或者在本篇文章的参考资料中再进行查阅。
参考资料:
W3C DTD教程: https://www.w3school.com.cn/dtd/index.asp
W3C Schema教程:https://www.w3school.com.cn/schema/index.asp
W3C XML教程:https://www.w3school.com.cn/xml/index.asp
DOM、JDOM、DOM4J的区别:https://www.cnblogs.com/avivahe/p/5493060.html
百度百科-XML:https://baike.baidu.com/item/%E5%8F%AF%E6%89%A9%E5%B1%95%E6%A0%87%E8%AE%B0%E8%AF%AD%E8%A8%80/2885849
网友评论