XML
一,概念
Extensible Markup language (可扩展标记语言)
-
可扩展:标签都是自定义的
-
功能
1.存储数据
(1)配置文件
(2)在网络中传输
-
-
xml和html的区别
1.xml标签都是自定义的,html的标签是预定义的
2.xml语法严格,html的语法松散
3.xml是存储数据的,html是展示数据的
- w3c(万维网联盟)
二,语法
-
基本语法:
(1)xml文档后缀为xml
(2)xml第一行必须写文档声明
<?xml version>='1.0' ?>
(3)有且仅有一个根标签,属性值必须使用引号引起来(单引号双引号都可以)
(4)标签必须正确关闭,也就是标签必须成对出现
(5)xml标签区分大小写
-
快速入门(举例):
<?xml version='1.0' ?> <users> <user id='1'> <name>zhangsan</name> <age>22</age> </user> <user id='2'> <name>lisi</name> <age>24</age> </user> </users>
-
组成部分:
1.文档声明
(1)格式<?xml 属性列表 ?>
(2)属性列表:
- version:版本号(主流版本1.0,且version是必须写的)
- encoding:编码方式,告知解析引擎当前文档使用的字符集,浏览器默认解码方式是ISO-8859-1
- standalone:是否独立
2.指令
3.标签
4.属性
id属性值唯一
5.文本
三,约束
1.概念:规定xml文档的书写规则
-
作为框架的使用者(程序员):
(1)能在xml中引入约束文档
(2)能够简单的读懂约束文档
-
分类
(1)DTD:一种简单的约束技术
(2)Schema:一种复杂的约束技术
2.DTD
-
引入dtd文档到xml中
(1)外部dtd:将约束的规则定义在外部的dtd文件中
本地:
网络:
如下是一段dtd代码,定义了teachers的配置文件规则
<!ELEMENT teachers (teacher+) > <!--这里teacher后面的条件可以设置成星号*(意思是teacher可以有任意个),设置成加号的意思是至少要有一个teacher--> <!ELEMENT teacher (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ATTLIST teacher number ID #REQUIRED><!--ATTLIST是定义属性值规则的,这里定义了teacher可以有一个名为number的属性值,且number必须有且唯一-->
下面是一个teacher.xml文件的代码,引入这个dtd文件的代码如下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE teachers SYSTEM "teachers.dtd"> <teachers> <teacher number="zzz"> <name>zhangsan</name> <age>22</age> <sex>male</sex> </teacher> <teacher number="lll"> <name>lisi</name> <age>25</age> <sex>male</sex> </teacher> </teachers>
(2)内部dtd:将约束规则定义在xml文档中(由于缺乏复用性,用的少)
举例(用的不多可以跳过)
<?xml version="1.0" encoding="UTF-8" ?> <!--<!DOCTYPE teachers SYSTEM "teachers.dtd">--> <!DOCTYPE teachers [ <!ELEMENT teachers (teacher+) > <!--这里teacher后面的条件可以设置成星号*(意思是teacher可以有任意个),设置成加号的意思是至少要有一个teacher--> <!ELEMENT teacher (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ATTLIST teacher number ID #REQUIRED><!--ATTLIST是定义属性值规则的,这里定义了teacher可以有一个名为number的属性值,且number必须有且唯一-->]> <teachers> <teacher number="zzz"> <name>zhangsan</name> <age>22</age> <sex>male</sex> </teacher> <teacher number="lll"> <name>lisi</name> <age>25</age> <sex>male</sex> </teacher> </teachers>
(3)dtd的缺陷–>不能限制标签中值的类型
例如标签中,显然age应该是数字,但如果我在其中填入其他的内容仍然不会报错,下面的Schema就很好的解决了这个问题
3.Shema(略)
四,xml解析
1.操作xml文档
(1)解析(读取):将文档中的数据读取到内存中
(2)写入:将内存中的数据保存到xml文档中,持久化存储。
2.解析xml的方式
- DOM:将标记语言文档一次性加载进内存,在内存中形成一颗dom树(如下图,就是一个简单的dom树)
(1)优点:操作方便,可以对文档进行CRUD的所有操作
(2)缺点:由于dom是一次性将文档记载进内存,并且将文件转成dom树的形式会比原来的格式占用的内存大上1000甚至10000倍,因此加载比较大的文件时候会非常占内存
- SAX:逐行读取,基于事件驱动的(每次读取一行的标记语言,读取下一行的时候会释放掉上一行内容,因此不占内存)
(1)优点:不占内存
(2)缺点:只能用来读取,不能增删改
基于两种解析xml(标记语言的优缺点),常在服务器端用DOM思想,在安卓等移动端使用SAX思想
- xml常见的解析器(工具包)
(1)JAXP:sun公司提供的解析器,支持dom和sax两种思想
(2)DOM4J:一款非常优秀的解析器
(3)Jsoup:一款Java的html的解析器,可以直接解析url地址,html内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。这里xml也是标记语言,所以同样可以用Jsoup解析
(4)PULL:android操作系统内置的解析器,是sax方式的
-
Jsoup
-
快速入门
(1)导入jar包
(2)获取Document对象
(3)获取对应的标签(Element对象)
(4)获取数据
-
public class jsoup_01 {
public static void main(String[] args) throws IOException {
//获取Document对象,依据xml文档获取,需要先获取xml的文档路径
String path = jsoup_01.class.getClassLoader().getResource("xml/teacher.xml").getPath();
Document document = Jsoup.parse(new File(path), "utf-8");
//获取元素对象Element
Elements elements = document.getElementsByTag("name");
//这个elements中包含了所有的name标签,在我所建立的这个xml文件中就是zhangsan和lisi,值得注意的是这个elements是其实是一个ArrayList集合,具体可以看下图
System.out.println(elements.size());//这个验证一下,输出结果确实是2,也就是有两个name,分别是zhangsan和lisi
//获取第一个name的Element对象
Element element = elements.get(0);
//获取其中的数据并输出验证一下
String name = element.text();
System.out.println(name);
}
}
输出的结果如下
3.Jsoup对象
-
Jsoup:工具类,可以解析xml和html文档,返回Document对象
-
parse:解析html或xml文档,返回Document对象
static Document
parse(File in, String charsetName)
Parse the contents of a file as HTML. static Document
parse(String html)
Parse HTML into a Document. static Document
parse(URL url, int timeoutMillis)
Fetch a URL, and parse it as HTML. 上面三种较为常用的parse方法,其中第一种和第三种最为常用,第一种常用于解析本地文件中的xml或html文档,返回一个Document对象,第三种常用于解析网络上的html文档,可以批量从网络上爬取html文档获取内容
三种parse的实例代码如下
(1)parse(File in, String charsetName)
public static void main(String[] args) throws IOException { //获取Document对象,依据xml文档获取,需要先获取xml的文档路径 String path = jsoup_02.class.getClassLoader().getResource("xml/teacher.xml").getPath(); Document document = Jsoup.parse(new File(path), "utf-8"); System.out.println(document); }
-
这里可以看到Documnet实则是一个字符串,打印出来就是xml文档的内容
(2)**`parse(String html)`**(不常用)
~~~java
public static void main(String[] args) throws IOException {
Document document = Jsoup.parse("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
"<!DOCTYPE teachers SYSTEM \"teachers.dtd\">\n" +
"\n" +
"<teachers>\n" +
" <teacher number=\"zzz\">\n" +
" <name>zhangsan</name>\n" +
" <age>22</age>\n" +
" <sex>male</sex>\n" +
" </teacher>\n" +
" <teacher number=\"lll\">\n" +
" <name>lisi</name>\n" +
" <age>25</age>\n" +
" <sex>male</sex>\n" +
" </teacher>\n" +
"</teachers>");
System.out.println(document);
}
~~~
结果和(1)一样,这里的String其实就是一个xml文档或者html文档的内容
(3)parse(URL url, int timeoutMillis)
------(获取在线的html文档)
public static void main(String[] args) throws IOException {
URL url = new URL("https://baike.baidu.com/item/jsoup/9012509?fr=aladdin");
Document document = Jsoup.parse(url,10000);
System.out.println(document);
}
这里的url我用的是Jsoup百度百科的网址,可以看到已经把这个网址的html文档内容给爬了出来
-
Document:文档对象,代表内存中的dom树
-
public class Document extends Element
-
用来获取Element对象(获取Element对象的方法继承自org.jsoup.nodes.Element类)
返回值类型 方法 描述 Element
getElementById(String id)
根据id属性值获取唯一的Element对象 Elements
getElementsByTag(String tagName)
根据标签名称获取元素对象集合 Elements
getElementsByAttribute(String key)
根据属性名称获取元素对象集合 Elements
getElementsByAttributeValue(String key, String value)
根据对应的属性名和属性值获取元素对象集合 -
-
Elements:元素Element对象的集合,可以当作ArryList来使用
-
Element:元素对象
-
获取子元素对象
返回值类型 方法 描述 Element
getElementById(String id)
根据id属性值获取唯一的Element对象 Elements
getElementsByTag(String tagName)
根据标签名称获取元素对象集合 Elements
getElementsByAttribute(String key)
根据属性名称获取元素对象集合 Elements
getElementsByAttributeValue(String key, String value)
根据对应的属性名和属性值获取元素对象集合 这些方法都是Element类本来就有的方法
-
获取属性值(根据属性名称获取属性值)
public String attr(String attributeKey)
-
获取文本内容
返回值类型 方法 描述 String
text()
获取所有子标签的纯文本内容 String html()
获取标签体的所有内容(包括子标签的标签和文本内)
-
-
Node:节点对象
- 是document和element的父类
-
Jsoup中快捷查询方式:
1.selector:选择器
-
使用的方法:ELements select(String cssQuery)
-
语法:参考Selector类中定义的语法
public static void main(String[] args) throws IOException { //获取xml的path String path = jsoup_01.class.getClassLoader().getResource("xml/teacher1.xml").getPath(); //根据这个path生成document对象 Document document = Jsoup.parse(new File(path), "utf-8");//这里parse方法会存在一个io异常,这里不做处理直接抛出 //1.查询name标签,使用select选择器,返回一个name标签的字符串 Elements elements = document.select("name"); System.out.println(elements); System.out.println("-------------------"); //2.根据id查询,这里需要注意id查询需要使用#+id Elements elements1 = document.select("#sss"); System.out.println(elements1); System.out.println("-------------------"); //3.获取teacher标签中number等于lll的子标签age Elements elements2 = document.select("teacher[number=\"lll\"]"); System.out.println(elements2); //这里已经成功获取了number等于lll的teacher标签 //继续获取它的子标签 Elements age = elements2.select("age"); System.out.println(age); //获取到age标签后我们获取其中的内容 String text = age.text(); System.out.println(text); //测试后是没有问题的 System.out.println("-------------------"); //换个更简单的语法,直接,如下 Elements select = document.select("teacher[number=\"lll\"] > age"); System.out.println(select.text()); }
-
-
运行结果:
<name id="sss">
zhangSan
</name>
<name id="ddd">
<xing>
zhang
</xing>
<ming>
san
</ming>
</name>
-------------------
<name id="sss">
zhangSan
</name>
-------------------
<teacher number="lll">
<name id="ddd">
<xing>
zhang
</xing>
<ming>
san
</ming>
</name>
<age>
25
</age>
<sex>
male
</sex>
</teacher>
<age>
25
</age>
25
-------------------
25
Process finished with exit code 0
2.XPath:W3C提供的一种快捷查询的语法
-
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初XPath的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是XPath很快地被开发者采用来当作小型查询语言。
-
shiyongJsoup的XPath需要额外导入jar包。
-
查询w3cshool参考手册,使用xpath的语法完成查询
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
路径表达式 | 结果 |
---|---|
bookstore | 选取 bookstore 元素的所有子节点。 |
/bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang | 选取名为 lang 的所有属性。 |
这是部分语法内容,参考可用
例:
public static void main(String[] args) throws Exception {
//获取xml的path
String path = jsoup_01.class.getClassLoader().getResource("xml/teacher1.xml").getPath();
//根据这个path生成document对象
Document document = Jsoup.parse(new File(path), "utf-8");//这里parse方法会存在一个io异常,这里不做处理直接抛出
//创建JXDocument对象,JXDocument支持XPath语法,因此它是刚导入的jar包中的内容
JXDocument jxDocument = new JXDocument(document);
//结合Xpath的语法查询
List<JXNode> jxNodes = jxDocument.selN("//teacher");//selN是selectNode,返回值是一个list集合,直接遍历出结果
for (JXNode jxNode : jxNodes) {
System.out.println(jxNode);
}
System.out.println("-------------------");
//查询所有teacher下的name标签
List<JXNode> jxNodes1 = jxDocument.selN("//teacher/name");//selN是selectNode,返回值是一个list集合,直接遍历出结果
for (JXNode jxNode : jxNodes1) {
System.out.println(jxNode);
}
System.out.println("-------------------");
//查询所有teacher下id为ddd的name标签
List<JXNode> jxNodes2 = jxDocument.selN("//teacher/name[@id='ddd']");//selN是selectNode,返回值是一个list集合,直接遍历出结果
for (JXNode jxNode : jxNodes2) {
System.out.println(jxNode);
}
System.out.println("-------------------");
}
运行结果:
<teacher number="zzz">
<name id="sss">
zhangSan
</name>
<age>
22
</age>
<sex>
male
</sex>
</teacher>
<teacher number="lll">
<name id="ddd">
<xing>
zhang
</xing>
<ming>
san
</ming>
</name>
<age>
25
</age>
<sex>
male
</sex>
</teacher>
-------------------
<name id="sss">
zhangSan
</name>
<name id="ddd">
<xing>
zhang
</xing>
<ming>
san
</ming>
</name>
-------------------
<name id="ddd">
<xing>
zhang
</xing>
<ming>
san
</ming>
</name>
-------------------
Process finished with exit code 0