概述
xml:eXtensible Markup Language,可拓展标记语言。作用主要是做配置文件和数据传输载体。本文只说明它做配置文件的知识。下面介绍它的文档结构、元素&属性、注释&CDATA、解析、DTD约束、Schema约束。
文档结构
-
文档声明
任何一个xml文件都是的第一行都必须是文档声明。简单文档声明如下:<?xml version="1.0" ?>
。文档声明中可以存在属性,需要了解两个属性:encoding
,值是:解码规则,如utf-8
和standalone
,值是:yes或者no
。前者表明文档的解码规则,后者表明文档是否是独立的xml文档。由于一般都是独立的xml文档,所以这个属性不常用。 -
encoding
字符从输入到保存再到下次打开,会存在两次操作,一次是在保存的时候采用何种编码规则进行保存,一次是在打开的时候采用何种编码规则来打开,前者是编码规则,后缀是解码规则。解码规则和编码规则一直时才能把上次保存的字符展示出来,否则便是乱码。对于下面的一个简单xml文档。选择另存为的时候会发现有格式有很多的选择,其中默认的是本机的编码格式,对于国内来说也就是GBK编码。对于下面的这段文档,使用"utf-8"和"GBK"都能正常保存,但是使用"iso-8859-1"就不行了,因为中文字符不能被存为"iso-8859-1"。
<?xml version="1.0" encoding="utf-8"?> <stus> <stu> <name>张三</name> <age>18</age> </stu> <stu> <name>李四</name> <age>28</age> </stu> </stus>
-
内容结构
下面是一个很简单的xml文件配置文档。<?xml version="1.0" encoding="UTF-8"?> <stus> <stu> <name>张三</name> <age>18</age> </stu> <stu> <name>李四</name> <age>28</age> </stu> </stus>
在每个xml文件中,都有一个根元素,如上面的是stus
。而且所有的xml文档都是树形结构。上面的代码中stu
是stus
的孩子,name
和 age
又是stu
的孩子。可以总结为下图:
元素&属性
我们刚才写的代码中,stus
、stu
、name
、age
都是元素;在文档声明中encoding
是属性;“UTF-8”
是属性值,张三
、李四
等是文本。
-
自定义元素规则:
- 名称可以含字母、数字以及其他的字符
- 名称不能以数字或者标点符号开始
- 名称不能以字符 “xml”(或者 XML、Xml)开始
- 名称不能包含空格
-
属性规则
- 属性的名称没有要求
- 属性的值需要用引号引起来
注释&CDATA
-
xml文件的注释和html文件一致,都是:
<!-- 注释的内容 -->
-
CDATA:了解过html的人知道,如果有些数据我们不想让html解析器解析,可以使用
<pre></pre>
来处理数据。同样的,如果xml中有些数据不想被xml解析器解析,我们可以使用<![CDATA[...不被解析的内容...]]>
。 -
转义字符:xml文件中的转义字符有5个。
字符 > < & " ' 转义后 >
<
&
"
'
解析xml的方式
xml的解析方式有很多种,但是常用的有两种。DOM和SAX。
- DOM:document object model
DOM解析方式是把整个xml文档都加载到内存中,解析成树状结构。此文档被叫做document
。之前说过的元素被叫做element
,属性被叫做attribute
,文本被叫做text
,他们有一个共同的父亲Node
。
-
SAX:simple API for XML
基于事件驱动,即不再是全部加载进内存,而是逐行扫描文档,一边扫描一边解析,可以在解析文档的任意时刻停止解析。 -
区别
DOM不仅可以检索数据,还可以增加和删除,而SAX只能进行检索。而且SAX速度更快,效率更高。
解析xml的API
最常用的解析xml的API是dom4j。资源可以去我的网盘中下载,密码:7vah。
import java.io.InputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Test {
public static void main(String[] args) throws Exception {
//由xml文件创建流对象
InputStream xmlStream = Test.class.getResourceAsStream("/NewFile.xml");
//创建SAXReader
SAXReader sax = new SAXReader();
//获得文档对象
Document read = sax.read(xmlStream);
//获得根元素
Element root = read.getRootElement();
System.out.println(root.getName());
//获得第一个子元素
Element child1 = root.element("stu");
System.out.println(child1.getName());
//获得全部子元素
List<Element> elements = root.elements();
for(Element e : elements)
System.out.println(e);
//获得text值:获得第一个stu的age
Element child2 = child1.element("age");
System.out.println(child2.getText());
//获得text值:获得第二个stu的name
Element child3 = (Element) root.elements().get(1);
System.out.println(child3.element("name").getText());
/*
stus
stu
org.dom4j.tree.DefaultElement@7291c18f [Element: <stu attributes: []/>]
org.dom4j.tree.DefaultElement@34a245ab [Element: <stu attributes: []/>]
18
李四
*/
}
}
如果路径非常长的话使用上面的方式获得子元素非常麻烦,所以有一个XPath
技术帮我们快速定位到某元素。需要另外的包,我的网盘,密码:aizd。
import java.io.InputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class TextXPath {
public static void main(String[] args) throws Exception {
InputStream xmlStream = Test.class.getResourceAsStream("/NewFile.xml");
SAXReader sax = new SAXReader();
Document read = sax.read(xmlStream);
Element root = read.getRootElement();
//把某标签之内的所有名称为 :name的标签都取出来://name
//把某标签下一级名称为:name的标签取出来: /name
List<Element> nodes1 = read.selectNodes("//stu");
System.out.println(nodes1);
List<Element> nodes2 = read.selectNodes("/stu");
System.out.println(nodes2);
/*Console:
[org.dom4j.tree.DefaultElement@5e265ba4 [Element: <stu attributes: []/>], org.dom4j.tree.DefaultElement@2401f4c3 [Element: <stu attributes: []/>]]
[] * */
}
}
约束
如果大家比较细心的话,可以看到在eclipse中xml文件会有一个warning,它就是说xml文件缺少约束。约束的作用是约束xml文件的内容,比如学生的姓名可以重复但是学生的id不能重复,xml文件本身不能约束唯一或重复选项,所以存在约束。约束分为两种DTD和Schema,但文章里不包含如何书写约束,值叙述如何引入约束。
- DTD:Document Type Definition
- 引入网络上的DTD约束,语法如下:
<!文档类型 根标签名字 网络上的dtd dtd的名称 dtd的路径>
,举例:
- 引入网络上的DTD约束,语法如下:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
- 引入本地的DTD约束,语法如下:`<! 引入本地的DTD 根标签名字 引入本地的DTD dtd的位置 >`,举例如下:`<!DOCTYPE stus SYSTEM "stus.dtd">`
- Schema:Schema约束本身就是xml文件,它不是单独引入文件中,而是作为根元素的属性存在。
Schema不再像DTD一样,严格分为本地和网络,它在创建的时候会指定命名空间,引用的时候也要使用命名空间,通过命名空间可以指定引入的是哪些约束规则。
一个xml文档不能引入多个DTD约束,却可以引入多个Schema约束,引入之后可能不同的约束对名称相同元素进行了约束,引入命名空间后就能防止出现误解。引入的语法及使用如下:
<!-- xmlns:xsi : 这里必须是这样的写法,也就是这个值已经固定了。
xmlns : 这里是名称空间,也固定了,写的是schema里面的顶部目标名称空间
xsi:schemaLocation : 有两段: 前半段是名称空间,也是目标空间的值 , 后面是约束文档的路径。
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
>