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