XML快速入门的保姆级教程!!!
- 简介
- 基础语法
- 组成部分
- 约束
-
- 约束分类
-
- DTD
- schema
- 解析
- Jsoup
-
- Jsoup:工具类,可以解析html或xml文档,返回Document对象
- Document:文档对象。代表内存中的dom树(Document对象继承Elements对象,其获取Elements的方法也是继承自这个Elements对象)
- Elements:元素Element对象的集合。可以当做 ArrayList来使用
- Element:元素对象
- Node:节点对象
- 快捷查询方式:
-
- 1. selector:选择器(根据类似于HTML中的选择器来查询XML中的标签元素)
- 2.xPathXPath:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。
简介
基础语法
<?xml version='1.0' ?><!--文档第一行必须声明-->
<users>
<user id='1'>
<name>dhy</name>
<br/><!--自闭合标签-->
</user>
<user id='2'>
<name>xpy</name>
<br/><!--自闭合标签-->
</user>
</users>
组成部分
约束
约束分类
- DTD: 一种简单的约束技术
- Schema: 一种复杂的约束技术
DTD
1.引入DTD到xml文档中
- 内部dtd,将约束规则定义在xml文档中
- 外部dtd,将约束规定定义在外部的dtd文件中
dtd:
<!--ELEMENT用来定义标签-->
<!--stus标签下能放stu子标签,又因为这里是stu+,跟正则表达式一样,这里stu子标签至少出现一次-->
<!ELEMENT stus (stu+)>
<!--stu标签里面能够出现name,age,sex标签,并且必须按照顺序出现-->
<!ELEMENT stu (name,age,sex)>
<!--PCDATA代表类型是字符串-->
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!--ATTLIST声明一个属性,stu标签有属性,属性名叫numebr,属性类型为ID,ID表名该number的属性值必须唯一-->
<!--number属性是#REQUIRED,表明该属性必须出现-->
<!ATTLIST stu number ID #REQUIRED> <!--ATTLIST用来定义属性-->
xml:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE stus SYSTEM "stu.dtd">
<stus>
<stu number="s001">
<name>dhy</name>
<age>18</age>
<sex>man</sex>
</stu>
</stus>
内部dtd用的很少,下面给出一种演示:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE stus [
<!--ELEMENT用来定义标签-->
<!--stus标签下能放stu子标签,又因为这里是stu+,跟正则表达式一样,这里stu子标签至少出现一次-->
<!ELEMENT stus (stu+)>
<!--stu标签里面能够出现name,age,sex标签,并且必须按照顺序出现-->
<!ELEMENT stu (name,age,sex)>
<!--PCDATA代表类型是字符串-->
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!--ATTLIST声明一个属性,stu标签有属性,属性名叫numebr,属性类型为ID,ID表名该number的属性值必须唯一-->
<!--number属性是#REQUIRED,表明该属性必须出现-->
<!ATTLIST stu number ID #REQUIRED> <!--ATTLIST用来定义属性-->
]>
<stus>
<stu number="s001">
<name>dhy</name>
<age>18</age>
<sex>man</sex>
</stu>
</stus>
schema
- 首先是dtd约束的局限性,schema相对于dtd来说,它可以对内容进行限定。
schema文档
* Schema:
* 引入:
1.填写xml文档的根元素
2.引入xsi前缀. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3.引入xsd文件命名空间. xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"
4.为每一个xsd约束声明一个前缀,作为标识 xmlns="http://www.itcast.cn/xml"
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"
xmlns="http://www.itcast.cn/xml">
schema的约束文档“student.xsd”
<?xml version="1.0"?>
<xsd:schema xmlns="http://www.itcast.cn/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn/xml" elementFormDefault="qualified">
<xsd:element name="students" type="studentsType"/> <!--声明一个student元素,类型是studentsType,下面会定义studentsType这个类型-->
<xsd:complexType name="studentsType">
<xsd:sequence> <!--这里声明Sequence,表示按顺序出现下面元素-->
<!--下面一行声明student标签,类型为studentType类型,最少出现minOccurs 0次,最多出现maxOccurs无限次-->
<xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType> <!--这里对前面定义的studentsType这个类型进行定义-->
<xsd:complexType name="studentType">
<xsd:sequence> <!--这里声明Sequence,表示按顺序出现下面元素-->
<!--下面定义3个元素,并指定这三个元素的类型-->
<xsd:element name="name" type="xsd:string"/> <!--姓名是xsd:string字符串类型,这是是schema约束规定的类型,不需要我们自定义-->
<xsd:element name="age" type="ageType" /> <!--年龄定义ageType类型-->
<xsd:element name="sex" type="sexType" /> <!--性别定义sexType类型-->
</xsd:sequence>
<!--定义student标签的属性number,类型是numberType类型,必须出现-->
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType> <!--这里对前面定义的studentType这个类型进行定义-->
<!--下面3个类型是简单类型,简单类型内部不定义其他标签,并且简单类型有相应的值,可以对值进行限定-->
<xsd:simpleType name="sexType">
<xsd:restriction base="xsd:string"> <!--基本的限定类型为schema自定义的字符串string类型-->
<xsd:enumeration value="male"/> <!--使用枚举类型限定sexType类型的值,要么是female,要么是male-->
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer"> <!--限定ageType的值是integer类型,数字-->
<xsd:minInclusive value="0"/> <!--限制最小值是0-->
<xsd:maxInclusive value="256"/> <!--限制最大值为256-->
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string"> <!--限定numberType类型的值为字符串string类型-->
<xsd:pattern value="heima_\d{4}"/> <!--限制这个numberType类型值的格式必须为“heima_”+4个数字-->
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
<!--schema文档本身就是一个xml文档。这个文档看起来很复杂,其实与前面的dtd文档类似-->
xml文件student.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--
下面是schema文档的引入规则(比较复杂,其实我们看得懂即可,以后使用的时候配置文件一般会提供,我们修改即可)
1.填写xml文档的根元素
2.引入xsi前缀. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
显示当前约束的版本,这是一个版本的命名空间,并给这个命名空间设置前缀为xsi。这是一种固定格式
3.引入xsd文件命名空间. xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"
第二部分是当前schema约束文档的路径,并使用命名空间给schema文档的路径起一个名字。以后如果我们想要使用schema文档的元素,必须加上命名空间。
如想使用students标签,必须写作“http://www.itcast.cn/xml:students”,如果都要加上会很麻烦。因此在下面我们给命名空间加一个前缀。
4.为每一个xsd约束声明一个前缀,作为标识 xmlns="http://www.itcast.cn/xml"
比如我们声明一个前缀“xmlns:a="http://www.itcast.cn/xml"”,以后我们使用student.xsd约束的元素的时候,就使用a表示命名空间,如“a:students”
使用的所有student.xsd文档的文件必须都要写a:
当我们只引入一个约束文档的时候,也可以不给命名空间加前缀,而是元素前面什么都不写,默认使用了当前唯一的命名空间。
如果我们引入多个约束文档,必须给约束文档定义命名空间。而2个元素文档的标签元素可能相同,必须使用命名空间来区分这些约束。
如果使用命名空间,看起来会很长,因此我们可以给命名空间起一个前缀名,这样看起来就简洁很多
-->
<a:students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"
xmlns:a="http://www.itcast.cn/xml">
<a:student number="heima_0001">
<a:name>zhangsan</a:name>
<a:age>23</a:age>
<a:sex>male</a:sex>
</a:student>
</a:students>
解析
解析:操作xml文档,将文档中的数据读取到内存中。
- 我们对xml文档会进行2种操作——解析与写入(解析使用得比较多,而写入用得比较少)
- 解析(读取):将文档中的数据读取到内存中
- 写入:将内存中的数据保存到xml文档中。持久化的存储
- 解析xml的方式:服务器端一般使用DOM思想,而在移动端会使用SAX思想。(一般标记型语言文档也是下面2类解析方式)
DOM:将标记语言文档一次性加载进内存,在内存中形成一颗dom树
* 优点:操作方便,可以对文档进行CRUD的所有操作
* 缺点:占内存SAX:逐行读取,基于事件驱动的。
* 优点:不占内存。
* 缺点:只能读取,不能增删改
- xml常见的解析器:
JAXP:sun公司提供的解析器,支持dom和sax两种思想
DOM4J:一款非常优秀的解析器
Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
PULL:Android操作系统内置的解析器,sax方式的。
Jsoup
- 步骤:
1. 导入jar包
2. 获取Document对象
3. 获取对应的标签Element对象
获取Document对象的方式有3种(下面代码我们使用第一种)
1) 从一个URL,文件或字符串中解析HTML;
2) 使用DOM或CSS选择器来查找、取出数据;
3) 可操作HTML元素、属性、文本;
4. 获取数据(比如我们可以获取文本内容等)
首先,同样记得将对应的jar包放入一个文件夹(如libs),并将这个文件add as library。然后我们创建java的类,使用java语言来对XML文档进行解析(java可以调用用于解析XML的相关jar包的功能,从而实现XML的解析)。
演示:
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;
public class main {
public static void main(String[] args) throws IOException {
//1、导入jsoup的相关jar包(完成)
//2、获取Document对象。我们通过xml文档来获取该文档的Document对象。
//首先通过当前的jsoupDemo1的Class对象获取类加载器,再使用类加载器的getResource方法获取相关xml文档的URL,根据URL的getPath方法获取此URL的String路径
//2.1获取student.xml的path
String path = main.class.getClassLoader().getResource("stu.xml").getPath();
//2.2解析xml文档,加载文档进内存,获取dom树--->Document,通过Jsoup的parse方法,同时可以指定解析字符集(字符串必须与XML文件的字符集一致)
Document dom = Jsoup.parse(new File(path), "utf-8");//这里接收File对象,必须将XML文档的path转换为File对象。
//3.获取元素对象 Element——public class Elements extends ArrayList<Element>(将Elements看做一个存放Element元素的ArrayList集合即可)
Elements elements = dom.getElementsByTag("name");
System.out.println(elements.size());//既然Elements可以看作一个ArrayList集合,长度使用size()方法
for(int x=0 ; x<elements.size() ; x++) {
//3.1获取name的Element对象
Element element = elements.get(x);//使用ArrayList集合的get方法
//3.2获取数据
String text = element.text();
System.out.println(text);
}
}
}
Jsoup:工具类,可以解析html或xml文档,返回Document对象
- parse(静态方法):解析html或xml文档,返回Document
* parse(File in, String charsetName):解析xml或html文件的。
* parse(String html):解析xml或html字符串
* parse(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象
/**
* Jsoup对象功能:解析xml或html文档,并返回document对象
* parse方法的三个重载形式
*/
public class main {
public static void main(String[] args) throws IOException {
//1、parse(File in, String charsetName):解析xml或html文件的。
String path = main.class.getClassLoader().getResource("stu.xml").getPath();
Document doc1 = Jsoup.parse(new File(path), "utf-8");
// System.out.println(doc1);//将整个student.xml文档的内容显示出来
//2.parse(String html):解析xml或html字符串
String str = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
"<students>\n" +
"\t<student number=\"heima_0001\">\n" +
"\t\t<name id=\"itcast\">\n" +
"\t\t\t<xing>张</xing>\n" +
"\t\t\t<ming>三</ming>\n" +
"\t\t</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" +
"</students>";//这里直接将student.xml的内容复制过来即可
Document doc2 = Jsoup.parse(str);
// System.out.println(doc2);//将整个student.xml文档的内容显示出来
//3.parse(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象(多用于解析网络HTML页面)
URL url = new URL("https://baike.baidu.com/item/jsoup/9012509?fr=aladdin");//代表网络中的一个资源路径。我们在这里解析一个html页面演示
Document doc3 = Jsoup.parse(url, 10000);//第二个参数设置的是超时的时间
System.out.println(doc3);//打印出对应页面的html源代码
}
}
Document:文档对象。代表内存中的dom树(Document对象继承Elements对象,其获取Elements的方法也是继承自这个Elements对象)
- 在XML中,Document对象主要用来获取Element对象
* getElementById(String id):根据id属性值获取唯一的element对象
* getElementsByTag(String tagName):根据标签名称获取元素对象集合
* getElementsByAttribute(String key):根据属性名称获取元素对象集合
* getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合
代码演示:
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;
public class main {
public static void main(String[] args) throws IOException {
//获取Document对象
String path = main.class.getClassLoader().getResource("stu.xml").getPath();
Document doc = Jsoup.parse(new File(path), "utf-8");
//3.获取元素对象了。
//3.1获取所有student对象的Elements集合
Elements elements = doc.getElementsByTag("student");
// System.out.println(elements);//打印出2个student对象的源代码
System.out.println("-----------");
//3.2根据id的属性值,获取相应的的元素对象的集合(返回单个的Elements对象,因为id的值唯一)
Element ly = doc.getElementById("ly");
// System.out.println(ly);//打印id值为“ly”的元素的代码
System.out.println("-----------");
//3.3 获取属性名为id的元素对象们(既获取包含id属性的标签)
Elements elements1 = doc.getElementsByAttribute("id");
// System.out.println(elements1);//只要标签中有包含id属性,就都会被打印出来
System.out.println("-----------");
//3.4获取 number属性值为s001的元素对象
Elements elements2 = doc.getElementsByAttributeValue("number", "s001");//根据标签属性以及属性值查找标签
System.out.println(elements2);//属性值number值为“s001”的标签会被打印
System.out.println("-----------");
}
}
Elements:元素Element对象的集合。可以当做 ArrayList来使用
这个Elements对象只是一个存储Element元素的ArrayList集合。
Element:元素对象
获取子元素对象(与前面通过Document获取标签集合的方法相同,但是这里只能获取一个标签内的子标签) getElementById(String id):根据id属性值获取唯一的element对象
getElementsByTag(String tagName):根据标签名称获取元素对象集合
getElementsByAttribute(String key):根据属性名称获取元素对象集合
getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合//下面的方法是Element对象继承其父类Node对象的方法
获取属性值 * 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;
public class main {
public static void main(String[] args) throws IOException {
//获取Document对象
String path = main.class.getClassLoader().getResource("stu.xml").getPath();
Document doc = Jsoup.parse(new File(path), "utf-8");
//通过Document对象获取name标签,获取所有的name标签,可以获取到两个
Elements elements = doc.getElementsByTag("name");//包含所有名为name的标签
System.out.println(elements.size());
System.out.println("----------------");
//通过Element对象获取子标签对象
Element element_student = doc.getElementsByTag("stu").get(0);//获取第一个名为“stu”的元素
Elements ele_name = element_student.getElementsByTag("name");//获取这个“stu”标签下的名为name的标签
System.out.println(ele_name.size());//只能获取到一个name
System.out.println("----------------");
//获取stu对象的属性值
//这个方法不区分大小写
String number = element_student.attr("number");//根据stu标签的number属性名,获取该number属性的值
System.out.println(number);
System.out.println("------------");
//获取student标签下子标签name标签的相应值
String text = ele_name.text();//获取name标签下的相应的纯文本
String html = ele_name.html();//获取name标签体的所有内容(包括子标签的字符串内容,包括子标签的标签以及文本)
System.out.println(text);
System.out.println(html);
}
}
Node:节点对象
- 是Document和Element的父类,Node里面定义了很多方法
快捷查询方式:
使用上面的getElement方法,如果我们想要查询某个标签,必须一级一级查询,很麻烦。而Jsoup提供了2个便捷的查询方法
1. selector:选择器(根据类似于HTML中的选择器来查询XML中的标签元素)
使用的方法:Elements select(String cssQuery)(这个方法是Element类下的方法)
使用选择器查询的语法:参考Selector类中定义的选择器的语法(查询Jsoup文档)
代码示例:
//获取Document对象
String path = main.class.getClassLoader().getResource("stu.xml").getPath();
Document doc = Jsoup.parse(new File(path), "utf-8");
//虽然select方法是Element类中的方法,但是Document对象继承自Element对象,因此一般我们使用Document对象来调用select方法
//查询name标签
/* 类似于CSS中的元素选择器,如html的div选择器。
div{
}
*/
Elements elements = doc.select("name");//这里查询的格式:直接使用标签名
// System.out.println(elements);//将xml文档中name标签全部查询出来
System.out.println("----------------");
//4.查询id值为itcast的元素。类似于CSS的id选择器,查询的格式为:#id名
Elements elements1 = doc.select("#ly");
// System.out.println(elements1);//将id名为“ly”的元素全部查询出来
System.out.println("----------------");
//5.获取stu标签并且number属性值为s001的age子标签(这里是元素选择器结合属性选择器)
//5.1.获取stu标签并且number属性值为s001
Elements elements2 = doc.select("stu[number=\"s001\"]");//这里既可以使用转义字符\",也可以直接使用'
// System.out.println(elements2);
System.out.println("----------------");
//5.2获取stu标签并且number属性值为s001的age子标签
Elements elements3 = doc.select("stu[number='s001'] > age");
System.out.println(elements3);
2.xPathXPath:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。
- XPath是一门对XML树形结构进行直接操作的语言。因此在java中使用的时候,需要导入额外的jar包。
- 这里相当于是用Jsoup先获取XML文档的Document对象,然后使用XPath的jar包提供的工具,结合java代码来获取XML文档Document树的某一些节点。
使用Jsoup的Xpath需要额外导入jar包。(注意使用前导入“JsoupXpath-0.3.2.jar”并add as library)
查询菜鸟教程,使用xpath的语法完成查询
代码示例:
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;
public class main {
public static void main(String[] args) throws IOException, XpathSyntaxErrorException {
//获取Document对象
String path = main.class.getClassLoader().getResource("stu.xml").getPath();
Document doc = Jsoup.parse(new File(path), "utf-8");
//3.根据document对象,创建JXDocument对象
JXDocument jxDoc = new JXDocument(doc);
//4.结合xpath语法查询
//4.1查询所有stu标签
List<JXNode> jxNodes1 = jxDoc.selN("//stu");//查询返回的是存储JXNode节点的List集合
//这个JXNode对象可以用来获取对应标签的各种成分
for(JXNode jxNode : jxNodes1 )//foreach快捷键:iter+回车
{
System.out.println(jxNode);
}
System.out.println("--------------------");
//4.2查询所有stu标签下的name标签
List<JXNode> jxNodes2 = jxDoc.selN("//stu/name");
for(JXNode jxNode : jxNodes2)
{
System.out.println(jxNode);
}
System.out.println("--------------------");
//4.3查询stu标签下带有id属性的name标签
List<JXNode> jxNodes3 = jxDoc.selN("//stud/name[@id]");
for(JXNode jxNode : jxNodes3)
{
System.out.println(jxNode);
}
System.out.println("--------------------");
//4.4查询student标签下带有id属性的name标签 并且id属性值为ly
List<JXNode> jxNodes4 = jxDoc.selN("//stu/name[@id='ly']");
for(JXNode jxNode : jxNodes4)
{
System.out.println(jxNode);
}
}
}