XML
概念
XML(Extensible Markup Language):可扩展标记语言
可扩展:标签都是自定义的。
发展历程
HTML和XML都是W3C(万维网联盟)制定的标准,最开始HTML的语法过于松散,于是W3C制定了更严格的XML语法标准,希望能取代HTML。但是程序员和浏览器厂商并不喜欢使用XML,于是现在的XML更多的用于配置文件及传输数据等功能。
是谁造成的HTML语法松散?
浏览器厂商。最开始W3C制定HTML的时候语法还是比较严格的。但浏览器厂商为了抢占市场,语法错误也可以解析成功HTML,最后“内卷”到HTML即使语法非常混乱也是可以被浏览器解析。
tips:归根到底是语法的制定者和使用者不一致造成了HTML语法混乱,JAVA语法严格就是因为java语言的运行工具java虚拟机也是sun公司(现在是oracle)出品的,语法不通过不让运行。
XML的功能
-
配置文件:在今后的开发过程当中我们会频繁使用框架(框架:半成品软件),使用框架时,需要写配置文件配置相关的参数,让框架满足我们的开发需求。而我们写的配置文件中就有一种文件类型是XML。
-
传输数据:在网络中传输数据时并不能传输java对象,所以我们需要将JAVA对象转成字符串传输,其中一种方式就是将对象转为XML类型的字符串。
XML基本语法
- 文件后缀名是.xml
- 第一行必须是文档声明
- 有且仅有一个根标签
- 标签必须正确关闭
- 标签名区分大小写
- 属性值必须用引号(单双都可)引起来
XML命名规则
XML 元素必须遵循以下命名规则:
1、名称可以包含字母、数字以及其他的字符。
2、名称不能以数字或者标点符号开始。
3、名称不能以字母 xml(或者 XML、Xml 等等)开始。
4、名称不能包含空格。
5、可使用任何名称,没有保留的字词。
最佳命名习惯
- 使名称具有描述性。使用下划线的名称也很不错:<first_name>、<last_name>。
- 名称应简短和简单,比如:<book_title>,而不是:<the_title_of_the_book>。
- 避免 “-” 字符。如果您按照这样的方式进行命名:“first-name”,一些软件会认为您想要从 first 里边减去 name。
- 避免 “.” 字符。如果您按照这样的方式进行命名:“first.name”,一些软件会认为 “name” 是对象 “first” 的属性。
- 避免 “:” 字符。冒号会被转换为命名空间来使用(稍后介绍)。
- XML 文档经常有一个对应的数据库,其中的字段会对应 XML 文档中的元素。有一个实用的经验,即使用数据库的命名规则来命名 XML 文档中的元素。
- 在 XML 中,éòá 等非英语字母是完全合法的,不过需要留意,您的软件供应商不支持这些字符时可能出现的问题。
<?xml version="1.0" encoding="UTF-8"?>
<teachers>
<teacher></teacher>
<teacher></teacher>
</teachers>
XML组成部分
文档声明
文档声明必须放在第一行,格式为:
<?xml 属性列表 ?>
属性列表:
version:版本号(必须)
encoding:编码方式
标签
XML中标签名是自定义的,标签名有以下要求:
- 包含数字、字母、其他字符
- 不能以数字和标点符号开头,可以以_开头
- 不能包含空格
指令(了解)
指令是结合css使用的,但现在XML一般不结合CSS,语法为:
<?xml-stylesheet type="text/css" href="a.css" ?>
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/css" href="cd_catalog.css"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
</CATALOG>
属性
属性值必须用引号(单双都可)引起来
文本
如果想原样展示文本,需要设置CDATA区,格式为:
<![CDATA[文本]]>
CDATA区:可以输出特殊字符:原样的显示书写在CDATA的内容。会原封不动的显示出去。
我们可以使用预定义的实体,去替代一些特殊字符的输出。
注意实体的写法:&实体的名字;
< | < | 小于 |
---|---|---|
> | > | 大于 |
& | & | 和号 |
&apos ; | ’ | 单引 |
" ; | " " | 双引 |
约束
DTD约束
虽然XML标签是自定义的。但是作为配置文件时,也需要遵循一定的规则。就比如在主板上硬盘口只能插硬盘,不能插入其他硬件。约束就是定义XML书写规则的文件,约束我们按照框架的要求编写配置文件。
我们作为框架的使用者,不需要会写约束文件,只要能够在xml中引入约束文档,简单的读懂约束文档即可。XML有两种约束文件类型:DTD和Schema。
DTD是一种较简单的约束技术,引入方式如下:
本地引入:
<!DOCTYPE 根标签名 SYSTEM "dtd文件的位置">
student.dtd
<!--在父标签students下可以有多个student标签-->
<!ELEMENT students(student*)>
<!--在标签student下有name,age,sex标签-->
<!ELEMENT student(name,age,sex)>
<!--在标签name,age,sex需要赋值文本-->
<!ELEMENT name(#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex(#PCDATA)>
<!--在student标签内必须带有number属性并且不能重复-->
<!ATTLIST student number ID #REQUIRED>
<?xml version="1.0"?>
<!DOCTYPE students SYSTEM "student.dtd"><students>
<student number="001">
<name>jjy</name>
<age>10</age>
<sex>男</sex>
</student>
<student number="002">
<name>lxm</name>
<age>11</age>
<sex>女</sex>
</student>
</students>
网络引入:
<!DOCTYPE 根标签名 PUBLIC "dtd文件的位置" "dtd文件路径">
Schema约束
Schema比DTD对XML的约束更加详细,引入方式如下:
-
写xml文档的根标签
-
引入xsi前缀:确定Schema文件的版本。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 引入Schema文件
xsi:schemaLocation="Schema文件定义的命名空间 Schema文件的具体路径"
- 为Schema约束的标签声明前缀
xmlns:前缀="Schema文件定义的命名空间"
例如:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.org/bookSchema"
targetNamespace="http://www.example.org/bookSchema"
elementFormDefault="qualified">
<!--
xmlns:xs="http://www.w3.org/2001/XMLSchema" 约束XML里使用xs:作前缀的元素、属性、类型等名称的变量是属于
xmlns="http://www.example.org/bookSchema" 表示默认的命名空间是,也就是指定未使用任何前缀的元素、数据的命名空间为它.
targetNamespace="http://www.example.org/bookSchema" 显示被此 schema 定义的元素来自命名空间
elementFormDefault="qualified" 所有全局元素的子元素将被以缺省方式放到无名命名空间
-->
<xs:element name='books'>
<xs:complexType>
<!-- minOccurs/maxOccurs:指定元素出现的次数-->
<!-- minOccurs:限制最小出现次数,0表示不限制 -->
<!-- maxOccurs:限制最大出现次数,unbounded表示无限制 -->
<xs:sequence maxOccurs='unbounded '>
<xs:element name='book'>
<xs:complexType>
<xs:sequence>
<!--定义name标签-->
<xs:element name='name' type="xs:string"/>
<!--定义author标签-->
<xs:element name="author" >
<!--定义author标签的属性-->
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!--定义price标签-->
<xs:element name='price' type="xs:double"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
引入xsd约束
<?xml version="1.0" encoding="UTF-8" ?>
<books xmlns="http://www.example.org/bookSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/bookSchema book.xsd">
<book>
<name>红楼梦</name>
<author>曹雪芹</author>
<price>29.9</price>
</book>
<book>
<name>三国演义</name>
<author>罗贯中</author>
<price>39.9</price>
</book>
</books>
Jsoup解析器
XML解析即读写XML文档中的数据。框架的开发者通过XML解析读取框架使用者配置的参数信息,开发者也可以通过XML解析读取网络传来的数据。XML有如下解析思想:
DOM
将标记语言文档一次性加载进内存,在内存中形成一颗dom树
优点:操作方便,可以对文档进行CRUD的所有操作
缺点:占内存
<?xml version="1.0"?>
<!DOCTYPE students SYSTEM "student.dtd"><students>
<student number="001">
<name>jjy</name>
<age>10</age>
<sex>男</sex>
</student>
<student number="002">
<name>lxm</name>
<age>11</age>
<sex>女</sex>
</student>
</students>
SAX
逐行读取,基于事件驱动的。
优点:不占内存,一般用于手机APP开发中读取XML
缺点:只能读取,不能增删改
XML常见解析器
- JAXP:SUN公司提供的解析器,支持DOM和SAX两种思想
- DOM4J:一款非常优秀的解析器
- Jsoup:Jsoup是一款Java的HTML解析器,支持DOM思想。可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过CSS以及类似于jQuery的操作方法来取出和操作数据
- PULL:Android操作系统内置的解析器,支持SAX思想
DOM4J
dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。性能优异功能强大简单易用开放源代码。
优点
①大量使用了Java集合类,方便Java开发人员,同时提供一些提高性能的替代方法。 ②支持XPath。 ③有很好的性能。
缺点
大量使用了接口,API较为复杂
接下来我就演示一下使用DOM4J读取一下xml文件里的内容输出到控制台。
首先我们需要在目录下创建一个lib包,把下面的链接地址中的jar包放到lib包内,并手动添加到模块。
DOM4J的jar包
DOM4J
引入jar包
Student.xml
<?xml version="1.0"?>
<!DOCTYPE students SYSTEM "student.dtd">
<students>
<student number="001">
<name>jjy</name>
<age>10</age>
<sex>男</sex>
</student>
<student number="002">
<name>lxm</name>
<age>11</age>
<sex>女</sex>
</student>
</students>
测试类
public class DOMTest {
public static void main(String[] args) throws DocumentException {
SAXReader reader=new SAXReader();
Document document = reader.read("Student.xml");
//获取根目录元素对象
Element dom = document.getRootElement();
//获取所有根目录下的子节点
List<Element> elements = dom.elements();
for (Element element : elements) {
//输出子节点的属性id值
System.out.println(element.attributeValue("number"));
//输出name值
System.out.println(element.elementText("name"));
//输出author值
System.out.println(element.elementText("sex"));
//输出price值
System.out.println(element.elementText("age"));
System.out.println("----------------");
}
}
}
Jsoup
- 导入jar包
- 加载XML文档进内存,获取DOM树对象Document
- 获取对应的标签Element对象
- 获取数据
public class Demo1 {
// 获取XML中所有学生的姓名
public static void main(String[] args) throws IOException {
// 2.加载XML文档进内存。获取DOM树对象Document
// 2.1 获取类加载器
ClassLoader classLoader = Demo1.class.getClassLoader();
// 2.2使用类加载器,找到XML文档的路径
String path = classLoader.getResource("com/jjy/xsd/student.xml").getPath();
// 2.3加载XML文档进内存,并转成Document对象
Document document = Jsoup.parse(new File(path), "utf-8");
// 3.获取对应的标签Element对象
Elements name = document.getElementsByTag("name");
// 4.获取数据
for (Element element : name) {
String text = element.text();
System.out.println(text);
}
}
}
Jsoup:可以解析xml或html,形成dom树对象。
常用方法:
- static Document parse(File in, String charsetName):解析本地文件
- static Document parse(String html):解析html或xml字符串
- static Document parse(URL url, int timeoutMillis):解析网页源文件
public class Demo2 {
// Jsoup
public static void main(String[] args) throws IOException {
// 解析本地XML
String path = Demo2.class.getClassLoader().getResource("com/jjy/xsd/student.xml").getPath();
Document document = Jsoup.parse(new File(path), "utf-8");
System.out.println(document);
System.out.println("------------------");
// 解析字符串
Document document1 = Jsoup.parse("<?xml version=\"1.0\" ?>\n" +
"<students>\n" +
" <student number=\"baizhan_0001\">\n" +
" <name>baizhan</name>\n" +
" <age>10</age>\n" +
" <sex>male</sex>\n" +
" </student>\n" +
" <student number=\"baizhan_0002\">\n" +
" <name>sxt</name>\n" +
" <age>11</age>\n" +
" <sex>female</sex>\n" +
" </student>\n" +
"</students>");
System.out.println(document1);
System.out.println("---------------------------------");
// 解析网络资源
Document document2 = Jsoup.parse(new URL("https://www.baidu.com"), 2000);
System.out.println(document2);
}
}
Document
Document:xml的dom树对象
常用方法:
- Element getElementById(String id):根据id获取元素
- Elements getElementsByTag(String tagName):根据标签名获取元素
- Elements getElementsByAttribute(String key):根据属性获取元素
- Elements getElementsByAttributeValue(String key,String value):根据属性名=属性值获取元素。
- Elements select(Sting cssQuery):根据选择器选取元素。
Student.xml
<?xml version="1.0"?>
<students>
<student id="001">
<name english="bz">jjy</name>
<age class="aa">10</age>
<sex>男</sex>
</student>
<student id="002">
<name english="sx">lxm</name>
<age>11</age>
<sex>女</sex>
</student>
</students>
public class Demo3 {
// Document
public static void main(String[] args) throws IOException {
String path = Demo3.class.getClassLoader().getResource("com/jjy/jsoup/student.xml").getPath();
Document document = Jsoup.parse(new File(path), "utf-8");
// 根据id获取元素
Element baizhan_0001 = document.getElementById("001");
System.out.println(baizhan_0001);
System.out.println("----------------------");
// 根据标签获取元素
Elements age = document.getElementsByTag("age");
for (Element element : age) {
System.out.println(element);
}
System.out.println("----------------------");
// 根据属性获取元素
Elements english = document.getElementsByAttribute("english");
for (Element element : english) {
System.out.println(element);
}
System.out.println("----------------------");
// 根据属性名=属性值获取元素
Elements elementsByAttributeValue = document.getElementsByAttributeValue("english", "bz");
for (Element element : elementsByAttributeValue) {
System.out.println(element);
}
System.out.println("----------------------");
// 使用CSS选择器获取元素
Elements select = document.select("#001");
System.out.println(select);
System.out.println("----------------------");
Elements sex = document.select("sex");
System.out.println(sex);
System.out.println("----------------------");
Elements select1 = document.select(".aa");
System.out.println(select1);
}
}
Element: 元素对象
常用方法:
- String text():获取元素包含的纯文本。
- String html():获取元素包含的带标签的文本。
- String attr(String attributeKey):获取元素的属性值。
public class Demo4 {
// Document
public static void main(String[] args) throws IOException {
String path = Demo4.class.getClassLoader().getResource("com/jjy/jsoup/student.xml").getPath();
Document document = Jsoup.parse(new File(path), "utf-8");
// 使用CSS选择器获取元素
Elements elements = document.select("#001");
Element element = elements.get(0);
System.out.println(element.text());
System.out.println("-----------------------");
System.out.println(element.html());
System.out.println("-----------------------");
System.out.println(element.attr("id"));
}
}
XPath解析
使用方法:
- 导入Xpath的jar包
- 获取Document对象
- 将Document对象转为JXDocument对象
- JXDocument调用selN(String xpath),获取List对象。
- 遍历List,调用JXNode的getElement(),转为Element对象。
- 处理Element对象。
public class Demo5 {
// Document
public static void main(String[] args) throws IOException, XpathSyntaxErrorException {
String path = Demo5.class.getClassLoader().getResource("com/jjy/jsoup/student.xml").getPath();
// 1. 获取`Document`对象
Document document = Jsoup.parse(new File(path), "utf-8");
//2. 将`Document`对象转为`JXDocument`对象
JXDocument jxDocument = new JXDocument(document);
//3. `JXDocument`调用`selN(String xpath)`,获取`List<JXNode>`对象。
// List<JXNode> jxNodes = jxDocument.selN("//name");
// 想拿到baizhan_0001的年龄
List<JXNode> jxNodes = jxDocument.selN("//student[@id=' 001']/age");
//4. 遍历`List<JXNode>`,调用`JXNode`的`getElement()`,转为`Element`对象。
for (JXNode jxNode : jxNodes) {
Element element = jxNode.getElement();
//5. 处理`Element`对象。
System.out.println(element);
}
}
}
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力