XML的概述
XML是可扩展的标记语言,之所以说它是可扩展的是因为标签是自定义的。HTML是用来展示数据的描述语言,XML是用来存储数据的语言。
我们通过这个例子来了解一下XML的作用email.xml。
<?xml version="1.0" encoding="utf-8"?>
<email>
<from>发件人:qdl</from>
<to>收件人:qjg</to>
<title>邮件的标题</title>
<text>邮件的正文</text>
</email>
XML什么都没干只是存储了一个邮件,如果需要它有意义,我们应该通过一些方式将它发出去,我们约定一个规范,接收人通过定义好的各个标签的含义就可以分析出这个邮件想要表达的具体意义。
XML的DTD约束(.dtd)
约束顾名思义就是对数据的限制,我们通过一定规则来限制XML中的数据。我们来稍微认识一下约束,不求完全弄清楚各个语法等,只需要对约束有个基本的认知即可。约束分为两种分别是DTD约束Schema约束,先来认识一下DTD约束。
创建一个email.dtd文件
<!ELEMENT email (from,to,title,text)>
<!ELEMENT from(#PCDATA)>
<!ELEMENT to(#PCDATA)>
<!ELEMENT title(#PCDATA)>
<!ELEMENT text(#PCDATA)>
如何将约束引用到xml文件中?
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE email SYSTEM "email.dtd" >
<email>
<from>发件人:qdl</from>
<to>收件人:qjg</to>
<title>邮件的标题</title>
<text>邮件的正文</text>
</email>
如果想深入了解,可查阅”菜鸟教程”相关章节。
我们在该XML文件中使用刚才定义的DTD文件,请参见第2行代码。此时,我们假如写了DTD中未声明的标签就会报错;类似地,其他未遵守DTD文件的写法也会报错。其实,利用DTD文件约束XML的方式还是有些呆板,可读性也不强。所以,请看下面的Schema约束。
XML的Schema约束(.xsd)
先反手上一段代码,再根据代码解释,建议先仔细阅读代码即使之前没接触过也要自己去体会xsd的语法格式,这样更加利用理解xsd语义。
加约束之前的hero.xml文件
<?xml version="1.0" encodint="utf-8"?>
<persons>
<person>
<name>戚继光</name>
<age>50</age>
<person>
<person>
<name>郑成功</name>
<age>55</age>
</person>
</persons>
约束hero.xsd文件
<?xml version="1.0"?>
<xsd:schema
xmlns="http://blog.youkuaiyun.com/weixin_36244867"
xmlns:xsd="http://blog.youkuaiyun.com/weixin_36244867"
targetNamespace="http://blog.youkuaiyun.com/weixin_36244867"
elementFormDefault="qualified">
<!-- 声明元素persons -->
<xsd:element name="persons" type="personsType" />
<!-- 声明类型personsType -->
<xsd:complexType name="personsType" >
<xsd:sequence>
<xsd:element name="person" type="personType" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<!-- 声明类型personType -->
<xsd:complexType name="personType" >
<xsd:sequence>
<xsd:element name="name" type="xsd:string" />
<xsd:element name="age" type="ageType" />
</xsd:sequence>
</xsd:complexType>
<!-- 声明类型ageType -->
<xsd:complexType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0" />
<xsd:maxInclusive value="150">
</xsd:restriction>
</xsd:complexType>
</xsd:schema>
加上约束的.xml文件
<?xml version="1.0" encodint="utf-8"?>
<persons
xmlns="http://blog.youkuaiyun.com/weixin_36244867"
xsi:schemaLocation="http://blog.youkuaiyun.com/weixin_36244867"
xmlns:xsi="http://blog.youkuaiyun.com/weixin_36244867" >
<person>
<name>戚继光</name>
<age>50</age>
<person>
</persons>
对Schema格式的一个简单的理解:
- 先声明根元素persons,名为persons,类型为personsType;
- 再去声明类型personsType,如果标签中仍有标签那么在声明类型时通过声明序列将其子标签声明出来,此例中persons只有一种类型的子标签person。所以在personsType中声明person,名为person,类型为personType;
- 声明类型personType,因为person中仍有子标签所以继续在personType中声明标签name,age,其中name类型为xsd中的string类型,而age为自定义的ageType类型;
- 继续声明ageType,因为age不再有子标签所以不必再序列声明标签元素,只需要设置ageType类型约束即可,例子中我们设置了age为integer类型,最小为0,最大为150。
XML的解析方式
XML常见的解析方式有DOM和SAX两种。
DOM解析
将XML文档加载进内存形成一颗DOM树(document对象)并将文档的各个组成部分封装为对象。所以,可以对DOM树进行增删改查。但是DOM树非常占内存,解析速度较慢,故DOM解析不适合较为复杂的XML文件。
如果说Java是面向对象编程,那么DOM是面向节点编程 。
- 整个XML文档就是一个文档(Document)节点;
- 文档中每个元素是也是一个元素(Element)节点;
- 元素中的文字则是文本(Text)节点;
- 元素的属性是属性(Attr)节点;
- 标签之间的空格换行也是节点;
- 总之,XML文档中的每个成分都是一个节点;
由此可见,XML文档中每一个组成部分都是节点。所以,元素一定是节点,而节点不一定是元素。
SAX解析
相比于DOM,SAX是一种速度更快,更有效的方法。SAX基于事件驱动,它逐行读取文档,一边读取一边解析,所以该方式占内存非常小,速度很快。而且在解析过程的任意时刻均可停止解析,但是该方式只能读取XML不能回写。
利用DOM4J解析XML
public static void main(String[] args) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read("res/student.xml");
Element rootElement = document.getRootElement();
List<Element> elementList = rootElement.elements();
int elementSize = elementList.size();
int nodeCount = rootElement.nodeCount();
System.out.println("XML有几条数据:" + elementSize);
System.out.println("XML有几个节点:" + nodeCount);
System.out.println("---------------------------------------");
analyzeElement(rootElement);
}
private static void analyzeElement(Element element){
for(int i=0; i<element.nodeCount(); i++){
Node node = element.node(i);
if( node instanceof Element ){
Element elem = (Element) node;
String elemName = elem.getName();
List<Attribute> attributeList = elem.attributes();
int attributeSize = attributeList.size();
System.out.println(elemName + "有属性" + attributeSize + "个");
for( Attribute attribute : attributeList ){
String attributeName = attribute.getName();
String attributeText = attribute.getText();
System.out.println(attributeName + ":" + attributeText);
}
analyzeElement(elem);
System.out.println(elemName+"是元素Element");
}else {
String nodeText=node.getText();
System.out.println(nodeText+"文本是节点Node");
}
}
System.out.println("---------------------------------------");
}
student.xml
<?xml version="1.0" encoding="utf-8"?>
<students>
<student number="student1">
<name>戚继光</name>
<age>35</age>
<job>蓟州总兵</job>
</student>
<student number="student2">
<name>郑成功</name>
<age>40</age>
<job>收复台湾</job>
</student>
</students>
在该示例中展示了利用DOM4J加载XML,并解析出XML中的元素和节点且获取出元素的名称,节点的文本,属性的值等等内容。在此,务必注意区分元素和节点;请切记:标签之间的空格换行也是一个节点!!!!至于,DOM4J的其他API在此不在依次举出。
当你看完这个例子,如果还不了解元素和节点的区别,请您参照菜鸟教程。
利用XPATH解析XML
public void testXPATH01() throws DocumentException{
SAXReader read = new SAXReader();
Document document = read.read("res/student.xml");
Node node = document.selectSingleNode("/students/student[1]/name");
String text=node.getText();
System.out.println(text);
}
public void testXPATH02() throws DocumentException{
SAXReader read = new SAXReader();
Document document = read.read("res/student.xml");
List<Node> nodeList = document.selectNodes("//*");
for(Node node : nodeList){
System.out.println(node.getName() + ":" + node.getText());
}
}
方法1获取第一个学生的name。
方法2获取所有节点信息。