目录
一、XML简介
XML全称为eXtensible Markup Language,是一种可扩展标记语言,
在XML中,所有的标签都是自定义的,常常用于存储数据,比如配置文件或者数据传输,
XML和之前学习的HTML都是标记语言,主要有以下几点区别:
- html语法松散,xml语法严格
- html用作页面展示,xml用作数据存储
- html所有标签都是预定义的,xml所有标签都是自定义的
二、XML基本语法
关于XML的基本语法,W3C(World Wide Web Consortium,万维网联盟)公布了XML1.0标准
- 文档声明
- 必须写在xml文档的第一行,写法为:<?xml version="1.0" ?>
- 属性
- version:版本号,固定值为1.0
- encoding:指定文档的码表,默认值为iso-8859-1
- standalone:指定文档是否独立,yes或no
- 元素
- 即xml文档中的标签,文档中必须有且只能有一个根元素
- 元素需要正确的闭合
- 元素需要正确的嵌套
- 元素名称要遵守
- 元素名称区分大小写
- 数字不能开头
- 文本
- 转义字符:例如>为">",<为“<”等
- CDATA:里面的数据会原样显示,<![CDATA[ 数据内容 ]]>
- 属性
- 属性值必须用引号括起来,单引号双引号都可以
- 注释
- <!--注释内容-->
- 处理指令
- <?xml-stylesheet type="text/css" href="1.css"?>,现在基本不使用
三、XML创建
根据XML的语法我们创建一个XML文件book.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<books>
<book>
<name>java</name>
<price>15</price>
</book>
<book>
<name>C++</name>
<price>20</price>
</book>
<book>
<name>python</name>
<price>15</price>
</book>
</books>
四、XML约束
约束就是xml的书写规则,我们一般分为dtd和schema两种。
4.1 dtd约束
dtd按照定义的方式又可以分为内部dtd和外部dtd:
- 内部dtd:在xml内部定义dtd
- 外部dtd:在外部文件中定义dtd
- 本地dtd文件:<!DOCTYPE students SYSTEM "student.dtd">
- 网络dtd文件:<!DOCTYPE students PUBLIC "名称空间" "student.dtd">
首先我们先定义好一个dtd文件
<!ELEMENT books (book*)> <!--定义根标签为books,根标签内部的标签为book,及book出现的次数为0次或多次-->
<!ELEMENT book (name,price)> <!--定义book标签内部标签为name标签或者price标签-->
<!ELEMENT name (#PCDATA)> <!--定义name标签内部为字符串-->
<!ELEMENT price (#PCDATA)> <!--定义price标签内部为字符串-->
<!ATTLIST book id ID #REQUIRED> <!--定义book标签体有必须的属性为id-->
然后通过本地dtd文件外部引入的方式,引入到book.xml中,
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE books SYSTEM "../book.dtd"> <!--添加同路径下的dtd约束文件-->
<books>
<book id="b100">
<name>java</name>
<price>15</price>
</book>
<book id="b101">
<name>C++</name>
<price>20</price>
</book>
<book id="b102">
<name>python</name>
<price>15</price>
</book>
</books>
这时xml文件就受到dtd文件的约束了,如果去掉id属性就会报错,或者添加别的没在dtd文件中定义的标签也会报错。
我们还可以直接将约束条件写在xml文件中,利用内部引入的方式对xml文件进行约束,
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE
<!ELEMENT books (book*)> <!--定义根标签为books,根标签内部的标签为book,及book出现的次数为0次或多次-->
<!ELEMENT book (name,price)> <!--定义book标签内部标签为name标签或者price标签-->
<!ELEMENT name (#PCDATA)> <!--定义name标签内部为字符串-->
<!ELEMENT price (#PCDATA)> <!--定义price标签内部为字符串-->
<!ATTLIST book id ID #REQUIRED> <!--定义book标签体有必须的属性为id-->
>
<books>
<book id="b100">
<name>java</name>
<price>15</price>
</book>
<book id="b101">
<name>C++</name>
<price>20</price>
</book>
<book id="b102">
<name>python</name>
<price>15</price>
</book>
</books>
4.2 schema约束
上述dtd约束有一个很大的问题,只能约束数据类型,但是对数据检查不严谨,
比如我们可以设置price的内容为abc,显然这个数据是没有实际意义的,所以就要用到schema约束,
而且schema相对于dtd有一个明显的好处就是,schema是基于XML编写的,自己本身也是一个XML文档(文件后缀名为.xsd),而不是像dtd有自成一套的语法,这也是schema能比dtd更被广泛应用的原因。
我们先创建一个xsd文件,建立好schema约束
<?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="books" type="booksType"/>
<xsd:complexType name="booksType">
<xsd:sequence>
<xsd:element name="book" type="bookType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="bookType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="price" type="priceType"/>
</xsd:sequence>
<xsd:attribute name="id" type="idType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="priceType">
<xsd:restriction base="xsd:double">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="10000"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="idType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="bookID_\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
然后导入xsd文件,引入实例名称空间,修改对应的xml文件,使其满足schema约束
<?xml version="1.0" encoding="UTF-8" ?>
<books
xmlns="http://www.itcast.cn/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn/xml book.xsd"
>
<book id="bookID_1000">
<name>java</name>
<price>30</price>
</book>
<book id="bookID_1001">
<name>C++</name>
<price>20</price>
</book>
<book id="bookID_1002">
<name>python</name>
<price>15</price>
</book>
</books>
五、xml解析
5.1xml解析作用
xml解析就是对xml文件进行分析,得到其中记录的数据信息,
- 如果将xml作为配置文件,可以通过读取配置信息
- 如果讲xml作为传输文件,可以通过读写传输数据
5.2xml解析思想
xml按照解析的思想分为DOM和SAX两种,
- DOM:将文档加载进内存,形成一颗DOM树(Document对象),将文档的各个组成部分封装为一些对象
- 优点:在内存中形成DOM树,可以进行增删改查
- 缺点:DOM树非常占用内存,解析速度比较慢
- Document、Element、Text、Attribute、Comment
- SAX:逐行读取文档,解析到某一个对象就将对象名称返回,基于事件驱动
- 优点:不占用内存,速度较快
- 缺点:只能读取,不能回写,无法实现增删改操作
六、xml常用解析器
DOM、SAX都是一组解析XML文档的规范,其实就是接口,这说明需要有实现者能使用,
而解析器就是对DOM、SAX的实现了,一般解析器都会实现DOM、SAX两个规范。
6.1JAXP
JAXP是由Java提供的,用于隐藏底层解析器的实现。
支持DOM和SAX两种解析,
6.2JDOM
JDOM是一种使用xml的独特java工具包,作用是新建xml文档以及读写xml数据。
6.3DOM4J
DOM4J是JDOM的升级版本,是这三种常用解析器中性能最好的一种,也是使用最多的一种。
DOM4J意为dom for java,支持DOM解析,其解析的步骤一般为:
- 导入jar包——dom4j.jar
- 创建解析器:SAXReader reader=new SAXReader();
- 解析xml获得document对象:Document document=reader.read(url);
下面我们读取一个xml文档的标签,
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class xmlParsing {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader=new SAXReader();//创建一个xml解析器
Document document=saxReader.read("src/book.xml");//把xml文档加载到document对象中
Element root=document.getRootElement();//获取DOM树的根节点
List list=root.elements();//获取根节点下的所有元素
treeWalk(root);//遍历DOM树所有节点
}
public static void treeWalk(Element element){
System.out.println(element.getName());//输出当前节点名字
int size=element.nodeCount();//获得当前节点孩子节点的数目
for (int i = 0; i < size; i++) {
Node node=element.node(i);//获得当前节点
if(node instanceof Element){//如果该节点存在
treeWalk((Element)node);//递归调用遍历节点函数
}
}
}
}
运行结果:
这里需要导入dom4j的jar包,需要的可以自取
链接:https://pan.baidu.com/s/1pw3n2Uz8ZaGgjWkmh-3xug
提取码:13vd
七、XPATH
XPATH是专门用于查询xml信息的语言,
常用到的查询方法为,
selectSingleNode();//查找单个节点
selectNodes();//查找多个节点
XPath语法类似于文件系统中的定位文件,具体语法如下:
- 如果路径以斜线 / 开始, 那么该路径就表示到一个元素的绝对路径。
- /AAA,查询根节点AAA
- /AAA/CCC,查询根节点AAA的所有CCC子元素
- 如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)。
- //BBB,查询标签为BBB的所有节点,无论是否为根节点
- //DDD/BBB,查询所有父元素为DDD的BBB元素
- 星号 * 表示选择所有由星号之前的路径所定位的元素。
- //*,查询所有层级的所有元素
- /*/*/*/BBB,查询有三个祖先节点的BBB元素
- 方块号里的表达式可以进一步的指定元素, 其中数字表示元素在选择集里的位置, 而last()函数则表示选择集中的最后一个元素。
- /AAA/BBB[1],查询根节点AAA中的第一个BBB子元素
- /AAA/BBB[last()],查询根节点AAA中最后一个BBB子元素
- @表示选择指定属性的元素
- //@id,查询所有的id属性
- //BBB[@id],查询有id属性的BBB元素
- 属性的值可以被用来作为选择的准则
- //BBB[@id='b1'],查询含有属性id且其值为'b1'的BBB元素
- count()函数可以计数所选元素的个数
- //*[count(BBB)=2],选择含有2个BBB子元素的元素
- 多个路径可以用分隔符 | 合并在一起
- //CCC | //BBB,选择所有的CCC和BBB元素
- ..表示当前节点的父节点
我们利用selectSingleNode方法查询book.xml中第三本书的价格,
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class xmlXPath {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader=new SAXReader();//创建一个xml解析器
Document document=saxReader.read("src/book.xml");//把xml文档加载到document对象中
Node node=document.selectSingleNode("/books/book[3]/price");//获取books标签下3号book标签的price标签节点
System.out.println(node.getText());//获取该书本的价格
}
}
查询结果:
我们还需要额外导入jaxen的jar包,需要的自取
链接:https://pan.baidu.com/s/1hQhX0QNvOY6rSVoUhNVdqg
提取码:whqo
我们再练习一下selectNodes方法获得所有节点进行遍历,
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.util.List;
public class xmlXPath {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader=new SAXReader();//创建一个xml解析器
Document document=saxReader.read("src/book.xml");//把xml文档加载到document对象中
List list=document.selectNodes("//*");//取出xml文件中的所有层级的标签节点
for (int i = 0; i < list.size(); i++) {
Node node=(Node)list.get(i);//依次获取节点
if("".equals(node.getText().trim()));else {
System.out.println(node.getText());
}
}
}
}
查询结果: