# XML
# 基本概念
XML是可扩展标记语言(Extensible Markup Language),被设计用来存储和传输数据,在1998年,W3C就发布了XML1.0规范;它有个非常成功的前驱——HTML(Hyper Text Markup Language),是由Web的发明者Tim Berners-Lee和同事Daniel W. Connolly于1990年创立的一种标记语言,主要用来显示数据。
# XML和HTML
XML和HTML的主要区别都是:
- XML主要是传输储存数据;HTML主要是显示数据。
- XML标签是没有被预定义,可被扩展的,可被用户定义的;HTML标签基本都被定义了。
- XML的语法严格;HTML语法松散。
- XML主要用在配置文件、网络传输中;HTML主要用在网页中。
# 语法
- xml第一行必须定义为文档声明
- xml文档中有且仅有一个根标签
- 属性值必须使用引号(单双都可)引起来
- 标签必须正确关闭,要么是自闭合标签,要么是成对的开关闭合标签
- xml标签名称区分大小写,xml文档的后缀名为.xml
下面是一个xml示例:
<?xml version="1.0" encoding="utf-8" standalone='no' ?>
<?xml-stylesheet type="text/css" href="name.css" ?>
<users>
<user id='1'>
<name>wangwu</name>
<age>25</age>
<gender>male</gender>
<br/>
</user>
<user id='2'>
<name>zhenliu</name>
<age>27</age>
<gender>female</gender>
<code>
if(a < b && a > c){}
<![CDATA[
if(a < b && a > c) {}
]]]>
</code>
</user>
</users>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
上面name.css为控制name标签的样式变,其内容为:
name{
color:red;
}
2
3
# 组成
- 文档声明,它的格式为:<?xml 属性列表 ?>。属性列表有:
- version:版本号,必须的属性。
- encoding:编码方式,告知解析引擎当前文档使用的字符集,默认值为ISO-8859-1。
- standalone:是否独立,它有两个取值:yes(不依赖其他文件)和no(依赖其他文件)。
- 指令:结合css:<?xml-stylesheet type="text/css" href="a.css" ?>
- 标签:标签名称自定义的,它有一定规则:
- 名称可以包含字母、数字以及其他的字符。
- 名称不能以数字或者标点符号开始。
- 名称不能以字母xml(或者XML、Xml等等)开始,
- 名称不能包含空格。
- 属性:id属性值要唯一。
- 文本:CDATA,其格式为:
# 约束
前面说了XML是可以自定义标签的,那对这些标签编写的规则则是约束,它规定xml文档的书写规则。一般一个框架会定义这些规则,而框架的使用者则需要遵守规则编写xml文档。有两种约束技术:
- DTD:文档定义类型(DTD)可定义合法的XML文档来构建模块,使用一系列合法的元素来定义文档的结构。DTD可被成行地声明与XML文档中,也可以作为一个外部引用。
- Schema:XML Schema是基于XML的DTD替代者,用于描述XML文档结构。
# DTD
DTD相对于Schema技术来说相对简单,引入DTD文档到xml文档中有两种方式:
内部dtd:将约束规则定义在xml文档中
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE students [ <!ELEMENT students (student+)> <!ELEMENT student (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ATTLIST student number ID #REQUIRED> ]> <students> <student number="a1"> <name>wangwu</name> <age>19</age> <sex>male</sex> </student> <student number="b2"> <name>zhenliu</name> <age>24</age> <sex>female</sex> </student> </students>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23外部dtd:将约束的规则定义在外部的dtd文件中,然后在xml中引用进去。
引用本地dtd:<!DOCTYPE 根标签名 SYSTEM "dtd文件的位置">
引用网络dtd:<!DOCTYPE 根标签名 PUBLIC "dtd文件名字" "dtd文件的位置URL">
student.dtd内容:
<!ELEMENT students (student+) > <!ELEMENT student (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ATTLIST student number ID #REQUIRED>
1
2
3
4
5
6student.xml内容:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE students SYSTEM "student.dtd"> <students> <student number="a1"> <name>wangwu</name> <age>19</age> <sex>male</sex> </student> <student number="b2"> <name>zhenliu</name> <age>24</age> <sex>female</sex> </student> </students>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# DTD定义解释
上面DTD的定义解释如下:
- <!DOCTYPE students:定义此文档为students类型文档。
- <!ELEMENT students (student+)>:students元素中最少要出现一个student元素。
- <!ELEMENT student (name,age,sex)>:student元素中必须包含name,age,sex元素。
- <!ELEMENT name (#PCDATA)>:声明student元素中name元素为PCDATA类型。
# PCDATA和CDATA区别
PCDATA的意思是被解析的字符数据(parsed character data),可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。该标记中下列字符应该被相应实体替换。被解析的字符数据不应当包含任何 字符;需要使用 & < > 实体来分别替换它们。
字符 | 实体 |
---|---|
& | & |
< | < |
> | > |
" | " |
' | ' |
CDATA的意思是字符数据(character data),它是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
# Schema
XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD),它是基于 XML 的 DTD 替代者,用来描述XML文档的结构。它相对于DTD会复杂一些,对数据类型的支持更完善:
- 可更容易地描述允许的文档内容
- 可更容易地验证数据的正确性
- 可更容易地与来自数据库的数据一并工作
- 可更容易地定义数据约束(data facets)
- 可更容易地定义数据模型
- 可更容易地在不同的数据类型间转换数据
# Schema引用
引入Schema文档步骤: 1.填写xml文档的根元素。 2.引入xsi前缀:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3.引入xsd文件命名空间:xsi:schemaLocation="http://localhost/xml student.xsd" 4.为每一个xsd约束声明一个前缀,作为标识:xmlns="http://localhost/xml"
下面是一个xsd文件:
<?xml version="1.0"?>
<xsd:schema xmlns="http://localhost/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://localhost/xml" elementFormDefault="qualified">
<xsd:element name="students" type="studentsType"/>
<xsd:complexType name="studentsType">
<xsd:sequence>
<xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="studentType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="sex" type="sexType" />
</xsd:sequence>
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="sexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male"/>
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="256"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="test_\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
下面是样例引入schema文件:
<?xml version="1.0" encoding="UTF-8"?>
<students xmlns="http://localhost/xml" xmlns:s2="http://localhost/xml2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost/xml student.xsd http://localhost/xml2 student2.xsd">
<student number="test_0001">
<name>xie</name>
<age>20</age>
<sex>male</sex>
</student>
</students>
2
3
4
5
6
7
8
# Java验证xsd
使用Java通过xsd来验证xml格式是否正确:
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
/**
* XPath查询
*/
public class Main {
public static boolean validateXml(String xsdPath, String xmlPath) throws SAXException, IOException {
// 建立schema工厂
SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
// 建立验证文档文件对象,利用此文件对象所封装的文件进行schema验证
File schemaFile = new File(xsdPath);
// 利用schema工厂,接收验证文档文件对象生成Schema对象
Schema schema = schemaFactory.newSchema(schemaFile);
// 通过Schema产生针对于此Schema的验证器,利用schenaFile进行验证
Validator validator = schema.newValidator();
// 得到验证的数据源
Source source = new StreamSource(xmlPath);
// 开始验证,成功输出success!!!,失败输出fail
validator.validate(source);
return true;
}
public static void main(String[] args) {
String xsdPath = Main.class.getClassLoader().getResource("student.xsd").getPath();
String xmlPath = Main.class.getClassLoader().getResource("student.xml").getPath();
try {
if (validateXml(xsdPath, xmlPath)) {
System.out.println("校验通过");
}
} catch (SAXException e) {
System.out.println("校验失败");
e.printStackTrace();
} catch (IOException e) {
System.out.println("校验失败");
e.printStackTrace();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Schema文档规则
<schema> 元素是每一个 XML Schema 的根元素。
xsd中元素分为:
- 简易元素,是指那些仅包含文本的元素,不会包含任何其他元素或属性。定义简易元素的语法为:
<xs:element name="xxx" type="yyy"/>
- 其中可使用default设置默认值,使用fixed来设置固定值,常用的类型(type)有:
- xs:string
- xs:decimal
- xs:integer
- xs:boolean
- xs:date
- xs:time
- 其中可使用default设置默认值,使用fixed来设置固定值,常用的类型(type)有:
- 复合元素,是指包含其他元素或属性的XML元素,它又分为:
空元素
xml元素为: <product prodid="12345" /> xsd定义为: <xs:element name="product"> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:integer"> <xs:attribute name="prodid" type="xs:positiveInteger"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element>
1
2
3
4
5
6
7
8
9
10
11
12
13包含其他元素的元素
xml元素为: <person> <firstname>li</firstname> <lastname>wang</lastname> </person> xsd定义为: <xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15仅包含文本的元素
xml元素为: <area country="china">20</shoesize> xsd定义为: <xs:element name="area"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:integer"> <xs:attribute name="country" type="xs:string" /> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element>
1
2
3
4
5
6
7
8
9
10
11
12
13包含元素和文本的元素
xml元素为: <letter> Dear Mr.<name>xie</name>. Your order <orderid>1024</orderid> will be shipped on <shipdate>2010-01-02</shipdate>. </letter> xsd定义为: <xs:element name="letter"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="orderid" type="xs:positiveInteger"/> <xs:element name="shipdate" type="xs:date"/> </xs:sequence> </xs:complexType> </xs:element>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 简易元素,是指那些仅包含文本的元素,不会包含任何其他元素或属性。定义简易元素的语法为:
xsd中的所有属性均作为简易类型来声明,简易元素无法拥有属性,如果一个元素拥有属性,它会被当作复合类型。声明方式为:
<xs:attribute name="xxx" type="yyy"/>
xsd限定(Facets)用于xml元素或属性定义可接受的值:
限定一个age元素,其值不能低于0或高于120: <xs:element name="age"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:minInclusive value="0"/> <xs:maxInclusive value="120"/> </xs:restriction> </xs:simpleType> </xs:element> 把xml元素的内容限制为一组可接收的值,使用枚举约束(enumeration constraint): <xs:element name="fruit"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="apple"/> <xs:enumeration value="banana"/> <xs:enumeration value="orange"/> </xs:restriction> </xs:simpleType> </xs:element>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Schema解析
Schema解析有两个基本操作:
- 将文档中的数据读取到内存中。
- 将内存中的数据保存到xml文档中。
解析xml的方式有两种:
- DOM:将标记语言文档一次性加载进内存,在内存中形成一棵dom树。
- 优点:操作方便,可以对文档进行CRUD的所有操作
- 缺点:占内存
- SAX:逐行读取,基于事件驱动的。
- 优点:不占内存,比较快。
- 缺点:只能读取,不能增删改。
xml常见的解析器:
- JAXP(Java API for XMLProcessing):sun公司提供的解析器,支持dom和sax两种方式。
- DOM4J:一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
- Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
- PULL:Android操作系统内置的解析器,sax方式的。
# Jsoup入门
使用Jsoup步骤:
- 导入jar包
- 获取Document对象
- 获取对应的标签Element对象
- 获取数据
示例:
import java.io.File;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Main {
public static void main(String[] args) throws Exception {
//得到xml文件路径
String path = Main.class.getClassLoader().getResource("student.xml").getPath();
//解析xml文档,加载文档进内存,获取dom树--->Document
Document document = Jsoup.parse(new File(path), "utf-8");
//获取元素对象 Element
Elements elements = document.getElementsByTag("name");
System.out.println(elements.size());
//获取第一个name的Element对象
Element element = elements.get(0);
//获取数据
String name = element.text();
System.out.println(name);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Jsoup对象
Jsoup:工具类,常使用parse方法来解析html或xml文档,返回Document。
- parse(File in, String charsetName):解析xml或html文件的
- parse(String html):解析xml或html字符串
- parse(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.io.File; import java.io.IOException; import java.net.URL; public class Main { public static void main(String[] args) throws IOException { //1. 解析xml文档,加载文档进内存,获取dom树 String path = Main.class.getClassLoader().getResource("student.xml").getPath(); Document document1 = Jsoup.parse(new File(path), "utf-8"); System.out.println(document1); //2. parse(String html):解析xml或html字符串 String str = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "\n" + "<students>\n" + "\t<student number=\"heima_0001\">\n" + "\t\t<name>tom</name>\n" + "\t\t<age>18</age>\n" + "\t\t<sex>male</sex>\n" + "\t</student>\n" + "\t<student number=\"heima_0002\">\n" + "\t\t<name>jack</name>\n" + "\t\t<age>18</age>\n" + "\t\t<sex>female</sex>\n" + "\t</student>\n" + "\n" + "</students>"; Document document2 = Jsoup.parse(str); System.out.println(document2); //3. parse(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象 URL url = new URL("http://www.baidu.com");//代表网络中的一个资源路径 Document document3 = Jsoup.parse(url, 10000); System.out.println(document3); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40Document:文档对象,代表内存中的dom树,可以获取Element对象。
- getElementById(String id):根据id属性值获取唯一的element对象
- getElementsByTag(String tagName):根据标签名称获取元素对象集合
- getElementsByAttribute(String key):根据属性名称获取元素对象集合
- getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合
Elements:元素Element对象的集合。可以当做ArrayList<Element>来使用,示例如下:
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.File; import java.io.IOException; /** * Document/Element 对象功能 */ public class Main { public static void main(String[] args) throws IOException { //1.获取student.xml的path String path = Main.class.getClassLoader().getResource("student.xml").getPath(); //2.获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //3.获取元素对象了。 //3.1获取所有student对象 Elements elements = document.getElementsByTag("student"); System.out.println(elements); System.out.println("-----------"); //3.2 获取属性名为id的元素对象们 Elements elements1 = document.getElementsByAttribute("id"); System.out.println(elements1); System.out.println("-----------"); //3.3 获取number属性值为test_0002的元素对象 Elements elements2 = document.getElementsByAttributeValue("number", "test_0002"); System.out.println(elements2); System.out.println("-----------"); //3.4 获取id属性值的元素对象 Element someObj = document.getElementById("test1"); System.out.println(someObj); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39Element:元素对象
- 获取子元素对象
- getElementById(String id):根据id属性值获取唯一的element对象
- getElementsByTag(String tagName):根据标签名称获取元素对象集合
- getElementsByAttribute(String key):根据属性名称获取元素对象集合
- getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合
- 获取属性值
- String attr(String key):根据属性名称获取属性值
- 获取文本内容
- String text():获取文本内容
- String html():获取标签体的所有内容(包括字标签的字符串内容)
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.File; import java.io.IOException; /** *Element对象功能 */ public class Main { public static void main(String[] args) throws IOException { //获取student.xml的path String path = Main.class.getClassLoader().getResource("student.xml").getPath(); //获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //通过Document对象获取name标签,获取所有的name标签,可以获取到两个 Elements elements = document.getElementsByTag("name"); System.out.println(elements.size()); System.out.println("----------------"); //通过Element对象获取子标签对象 Element element_student = document.getElementsByTag("student").get(0); Elements ele_name = element_student.getElementsByTag("name"); System.out.println(ele_name.size()); //获取student对象的属性值 String number = element_student.attr("NUMBER"); System.out.println(number); System.out.println("------------"); //获取文本内容 String text = ele_name.text(); String html = ele_name.html(); System.out.println(text); System.out.println(html); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37- 获取子元素对象
Node:节点对象,是Document和Element的父类
# Jsoup查询
Jsoup中查询元素有两种方式:
selector选择器。
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; import java.io.File; import java.io.IOException; /** *选择器查询 */ public class Main { public static void main(String[] args) throws IOException { //1.获取student.xml的path String path = Main.class.getClassLoader().getResource("student.xml").getPath(); //2.获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //3.查询name标签 Elements elements = document.select("name"); System.out.println(elements); System.out.println("=----------------"); //4.查询id值为itcast的元素 Elements elements1 = document.select("#test"); System.out.println(elements1); System.out.println("----------------"); //5.1.获取student标签并且number属性值为test_0001 Elements elements2 = document.select("student[number=\"test_0001\"]"); System.out.println(elements2); System.out.println("----------------"); //5.2获取student标签并且number属性值为test_0001的age子标签 Elements elements3 = document.select("student[number=\"test_0001\"] > age"); System.out.println(elements3); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35XPath:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言,注意使用Jsoup的Xpath需要额外导入jar包,作者为JsoupXpath (opens new window)
import cn.wanghaomiao.xpath.exception.XpathSyntaxErrorException; import cn.wanghaomiao.xpath.model.JXDocument; import cn.wanghaomiao.xpath.model.JXNode; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.io.File; import java.io.IOException; import java.util.List; /** *XPath查询 */ public class Main { public static void main(String[] args) throws IOException, XpathSyntaxErrorException { //1.获取student.xml的path String path = Main.class.getClassLoader().getResource("student.xml").getPath(); //2.获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //3.根据document对象,创建JXDocument对象 JXDocument jxDocument = new JXDocument(document); //4.结合xpath语法查询 //4.1查询所有student标签 List<JXNode> jxNodes = jxDocument.selN("//student"); for (JXNode jxNode : jxNodes) { System.out.println(jxNode); } System.out.println("--------------------"); //4.2查询所有student标签下的name标签 List<JXNode> jxNodes2 = jxDocument.selN("//student/name"); for (JXNode jxNode : jxNodes2) { System.out.println(jxNode); } System.out.println("--------------------"); //4.3查询student标签下带有id属性的name标签 List<JXNode> jxNodes3 = jxDocument.selN("//student/name[@id]"); for (JXNode jxNode : jxNodes3) { System.out.println(jxNode); } System.out.println("--------------------"); //4.4查询student标签下带有id属性的name标签 并且id属性值为itcast List<JXNode> jxNodes4 = jxDocument.selN("//student/name[@id='test']"); for (JXNode jxNode : jxNodes4) { System.out.println(jxNode); } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55