XML基本介绍
XML -- Extensible Markup Language,即可扩展标记语言。
XML 特点:可扩展的,标签都是自定义的;语法十分严格。
XML的作用
存储数据:通常,我们在数据库中存储数据。不过,如果希望数据的可移植性更强,我们可以把数据存储 XML 文件中。
配置文件:更多是作为各种技术框架的配置文件使用。
在网络中传输:客户端可以使用 XML 格式向服务器端发送数据,服务器接对 XML 格式数据进行解析。
XML的语法
XML 文档声明格式
文档声明必须为结束且必须写在第一行。
versioin:指定 XML 文档版本,是必需属性,因为不会选择 1.1,只会选择 1.0。
encoding:指定当前文档的编码,是可选属性,默认值是 utf-8。
<?xml version="1.0" encoding="UTF-8"?>
元素
Element 元素:是 XML 文档中最重要的组成部分。
命名规则:
- 不能使用空格,不能使用冒号
- XML 标签名称区分大小写
- XML 必须有且只有一个根元素
- XML 必须有且只有一个根元素,它是所有其他元素的父元素,比如以下 users 就是根元素。
<?xml version="1.0" encoding="utf-8" ?>
<users>
</users>
普通元素的结构开始标签、元素体、结束标签组成。
<hello>大家好</hello>
元素体:元素体可以是元素,也可以是文本。
<hello>
<a>您好</a>
</hello>
空元素:空元素只有开始标签,而没有结束标签,但元素必须自己闭合。
<close/>
属性
- 属性是元素的一部分,它必须出现在元素的开始标签中。
- 属性的定义格式:属性名 = "属性值",其中属性值必须使用单引或双引。
- 一个元素可以有 0 ~ N 个属性,但一个元素中不能出现同名属性。
- 属性名不能使用空格、冒号等特殊字符,且必须以字母开头。
<bean id="1" class="x"></bean>
注释
XML 的注释:
以 <!-- 开始,以 --> 结束
注释内容会被XML解析器忽略。
使用 XML 描述数据
<?xml version="1.0" encoding="UTF-8" ?>
<employees>
<employee eid="2">
<ename>林黛玉</ename>
<age>20</age>
<sex>女</sex>
<salary>5000</salary>
<empdate>2019-03-14</empdate>
</employee>
<employee eid="3">
<ename>杜甫</ename>
<age>40</age>
<sex>男</sex>
<salary>15000</salary>
<empdate>2010-01-01</empdate>
</employee>
</employees>
XML约束
在 XML 技术里,可以编写一个文档来约束一个 XML 文档的书写规范,这称之为 XML 约束。
常见的 XML 约束:DTD,Schema。
“用户程序员”阅读 XML 约束文档,编写 XML 文档;
软件框架编写 XML 约束文档,解析 XML 文档;
XML 约束文档规定了 XML 文档的书写规则。
-
DTD约束
DTD - Document Type Definition,文档类型定义,用来约束 XML 文档。规定 XML 文档中元素的名称,子元素的名称及顺序,元素的属性等。
通过框架提供的 DTD 约束文档,编写对应的 XML 文档。常见框架使用 DTD 约束有:Struts2、hibernate 等。
引入 DTD 文档到 XML 文档中有两种方式:
- 内部 DTD -- 将约束规则定义在 XML 文档中。
- 外部 DTD -- 将约束的规则定义在外部的 DTD 文件中。
创建约束文件 student.dtd
<!ELEMENT students (student+) >
<!ELEMENT student (name,age,sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student number ID #REQUIRED>
<!--
ELEMENT: 用来定义元素
students (student+) : 代表根元素 必须是 <students>
student+ : 根标签中至少有一个 student子元素, + 代表至少一个
student (name,age,sex): student 标签中包含的子元素,按顺序出现
#PCDATA: 是普通文本内容
ATTLIST: 用来定义属性
student number ID #REQUIRED
student子元素中 有一个ID属性叫做 number,是必须填写的
ID: 唯一 值只能是字母或者下划线开头
-->
引入约束文档到 student.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE students SYSTEM "student.dtd">
<students>
<student number="s1">
<name>布莱尔</name>
<age>22</age>
<sex>男</sex>
</student>
<student number="s2">
<name>张三</name>
<age>55</age>
<sex>男</sex>
</student>
</students>
-
Schema约束
Schema 是新的 XML 文档约束,比 DTD 强大很多,是 DTD 替代品。
Schema 本身也是 XML 文档,但 Schema 文档的扩展名为 xsd,而不是 xml。
Schema 功能更强大,内置多种简单和复杂的数据类型。
Schema 支持命名空间(一个 XML 中可以引入多个约束文档)。
命名空间:指的是一个环境,所用的标签来自于哪个环境定义的。
创建 student.xsd
xmlns -- 表示此文档默认的命名空间是什么
xmlns:xsd -- 表示数据类型等定义的来源
targetNamespace -- 表示文档中要定义的元素来自哪个命名空间
elementFormDefault -- 表示要求 XML 文件的每一个元素都要有命名空间指定
<?xml version="1.0"?>
<xsd:schema xmlns="http://www.xxx.com/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.xxx.com/xml"
elementFormDefault="qualified">
<xsd:element name="students" type="studentsType"/>
<xsd:complexType name="studentsType">
<xsd:sequence>
<xsd:element name="student" type="studentType" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="studentType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="sex" type="sexType" />
</xsd:sequence>
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="sexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male"/>
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="200"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="xxx_\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
XML 引入 Schema 约束
首先,查看 Schema 文档,找到根元素,在 student.xml 中写出来。
使用 xmlns 指令来声明根元素来自哪个命名空间。
在 xmlns:xsi 引入 W3C 的标准命名空间,复制即可。
使用 schemaLocation 来指定引入的命名空间跟哪个 XSD 文件对应,有两个取值:第一个为命名空间,第二个为 XSD 文件的路径。
<?xml version="1.0" encoding="UTF-8" ?>
<students xmlns="http://www.xxx.com/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xxx.com/xml student.xsd">
<student number="xxx_1234">
<name>张小红</name>
<age>25</age>
<sex>female</sex>
</student>
<student number="xxx_0000">
<name>李大兵</name>
<age>20</age>
<sex>male</sex>
</student>
</students>
XML解析
当将数据存储在 XML 后,希望通过程序获得 XML 的内容。如果使用 Java 的 IO 流是可以完成的,不过需要非常繁琐的操作,且开发中会遇到不同问题(只读、读写)。所以,为了方便了开发人员操作 XML,需要给不同问题提供不同的解析方式及对应的解析器。
解析器:就是根据不同的解析方式提供的具体实现。有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包。
XML 解析方式
DOM -- Document Object Model:属于文档驱动。要求解析器把整个 XML 文档装载到内存,并解析成一个 Document 对象并建立 DOM 树,生成 DOM 树上的每个 Node 对象。
- 优点:元素与元素之间保留结构关系,故可以进行增删改查操作。可以读取以及修改DOM 树任何部分。
- 缺点:XML 文档过大,可能出现内存溢出显现。
SAX -- Simple API for XML:属于事件驱动,是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件。
- 优点:占用内存少且处理速度快,可以处理大文件。
- 缺点:只能顺序访问读取,不能修改。需要建立自己的 XML 对象模型,增加了开发难度。
XML 常见的解析
JAXP:Sun 公司提供的解析器,支持 DOM 和 SAX 两种思想。
DOM4J:一款非常优秀的解析器,Dom4j 是一个易用的、开源的库,用于 XML,XPath 和 XSLT。它应用于 Java 平台,采用了 Java 集合框架并完全支持 DOM,SAX 和 JAXP。
Jsoup:Jsoup 是一款 Java 的 HTML 解析器,也可以解析 XML。
PULL:Android 内置的 XML 解析方式,类似 SAX。
Dom4j 的使用
首先导入 dom4j JAR 包。
使用核心类 SaxReader 加载 XML 文档获得 Document,通过 Document 对象获得文档的根元素,然后就可以操作了。
SaxReader 对象:read(…) 加载执行 XML 文档
Document 对象:getRootElement() 获得根元素
Element 对象:
- elements(…) 获得指定名称的所有子元素。可以不指定名称
- element(…) 获得指定名称的第一个子元素。可以不指定名称
- getName() 获得当前元素的元素名
- attributeValue(…) 获得指定属性名的属性值
- elementText(…) 获得指定名称子元素的文本值
- getText() 获得当前元素的文本内容
1. 使用 schema 约束编写 user.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.xxx.com/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.xxx.com/xml"
elementFormDefault="qualified">
<xsd:element name="users" type="usersType"/>
<xsd:complexType name="usersType">
<xsd:sequence>
<xsd:element name="user" type="userType" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="userType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="hobby" type="hobbyType" />
</xsd:sequence>
<xsd:attribute name="id" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="100"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="hobbyType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="跑步"/>
<xsd:enumeration value="游泳"/>
<xsd:enumeration value="看书"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
2. 引入约束编写 user.xml
<?xml version="1.0" encoding="UTF-8" ?>
<users xmlns="http://www.xxx.com/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xxx.com/xml user.xsd">
<user id="1">
<name>张三</name>
<age>20</age>
<hobby>跑步</hobby>
</user>
<user id="2">
<name>布莱尔</name>
<age>10</age>
<hobby>游泳</hobby>
</user>
<user id="3">
<name>何小明</name>
<age>40</age>
<hobby>看书</hobby>
</user>
</users>
3. 读取 XML
public class TestDOM4j {
// 获取 XML 文件中的所有的元素名称(标签)
@Test
public void test1() throws DocumentException {
// 获取 XML 解析对象
SAXReader reader = new SAXReader();
// 解析 XML 获取文档对象 document
Document document = reader.read("user.xml");
// 获取根元素
Element rootElement = document.getRootElement();
// 获取根元素名称
System.out.println(rootElement.getName());
// 获取根元素下的标签
List<Element> elements = rootElement.elements();
for (Element element : elements) {
System.out.println("根标签下的子节点: " + element.getName());
List<Element> eList = element.elements();
for (Element e : eList) {
System.out.println("user 标签下的子节点" + e.getName());
}
break;
}
}
/**
* 获取具体的节点内容
*/
@Test
public void test2() throws DocumentException {
// 创建 XML 文档解析对象
SAXReader sr = new SAXReader();
// 读取 XML 获取到 document 对象
Document document = sr.read("src\\user.xml");
// 获取根节点
Element rootElement = document.getRootElement();
// 得到当前节点的所有子节点
List<Element> elements = rootElement.elements();
// 获取第一个子节点
Element user = elements.get(0);
// 获取所有信息
String id = user.attributeValue("id");
String name = user.elementText("name");
String age = user.elementText("age");
// 使用 getText 获取当前元素的文本内容
String hobby = user.element("hobby").getText();
System.out.println(id+" "+name+" "+age+" "+hobby);
}
}
XPath 方式读取 XML
XPath 是一门在 XML 文档中查找信息的语言,可以是使用 XPath 查找 XML 中的内容。
由于 DOM4J 在解析 XML 时只能一层一层解析,所以当 XML 文件层数过多时使用会很不方便,结合 XPath 就可以直接获取到某个元素。
基于已经导入的 DOM4J 的 JAR 包,需要额外导入 jaxen JAR 包。
XPath 基本语法介绍
使用 Dom4j 支持 XPath 的操作的几种主要形式:
- /AAA/DDD/BBB 选择 AAA 的子元素 DDD 的所有子元素
- //BBB 选择所有 BBB 元素
- //* 选择所有元素
- BBB[1] 选择 BBB 第一个子元素, BBB[last()] 表示选择 BBB 最后一个子元素
- //BBB[@id] 选择有 id 属性的 BBB 元素
- //BBB[@id='b1'] 选择含有属性 id 且其值为 'b1' 的 BBB 元素
API 介绍:
selectSingleNode(query): 查找和 XPath 查询匹配的一个节点,参数是 XPath 查询串。
selectNodes(query) :得到的是 XML 根节点下的所有满足 XPath 的节点,参数是 XPath 查询串。
Node :节点对象。
XPath 读取 XML:
<?xml version="1.0" encoding="UTF-8" ?>
<bookstore>
<book id="book1">
<name>西游记</name>
<author>吴承恩</author>
<price>99</price>
</book>
<book id="book2">
<name>红楼梦</name>
<author>曹雪芹</author>
<price>69</price>
</book>
<book id="book3">
<name>Java编程思想</name>
<author>埃克尔</author>
<price>59</price>
</book>
</bookstore>
/*
* 使用 selectSingleNode 方法查询指定节点中的内容
**/
@Test
public void test1() throws DocumentException {
// 创建解析器对象
SAXReader sr = new SAXReader();
// 获取文档对象
Document document = sr.read("book.xml");
// 调用 selectSingleNode() 方法获取 name 节点对象
Node node1 = document.selectSingleNode("/bookstore/book/name");
System.out.println("节点: " + node1.getName());
System.out.println("书名: " + node1.getText());
// 获取第二本书的名称
Node node2 = document.selectSingleNode("/bookstore/book[2]/name");
System.out.println("第二本书的书名为: " + node2.getText());
}
/*
* 使用 selectSingleNode 方法获取属性值或者属性值对应的节点
**/
@Test
public void test2() throws DocumentException {
// 创建解析器对象
SAXReader sr = new SAXReader();
// 获取文档对象
Document document = sr.read("book.xml");
// 获取第一个 book 节点的 id 属性的值
Node node1 = document.selectSingleNode("/bookstore/book/attribute::id");
System.out.println("第一个 book 的 id 值为: " + node1.getText());
// 获取最后一个 book 节点的 id 属性的值
Node node2 = document.selectSingleNode("/bookstore/book[last()]/attribute::id");
System.out.println("最后一个 book 节点的 id 值为: " + node2.getText());
// 获取 id 属性值为 book2 的书名
Node node3 = document.selectSingleNode("/bookstore/book[@id='book2']");
String name = node3.selectSingleNode("name").getText();
System.out.println("id 为 book2 的书名是: " + name);
}
/*
* 使用 selectNodes() 方法获取对应名称的所有节点
**/
@Test
public void test3() throws DocumentException {
// 创建解析器对象
SAXReader sr = new SAXReader();
// 获取文档对象
Document document = sr.read("book.xml");
// 打印获取所有节点
List<Node> list = document.selectNodes("//*");
for (Node node : list) {
System.out.println("节点名: " + node.getName());
}
// 获取所有的书名
List<Node> names = document.selectNodes("//name");
for (Node name : names) {
System.out.println(name.getText());
}
// 获取指定 id 值为 book1 的节点的所有内容
List<Node> book1 = document.selectNodes("/bookstore/book[@id='book1']//*");
for (Node node : book1) {
System.out.println(node.getName() + " = " + node.getText());
}
}
JDBC 自定义 XML
定义 XML 配置文件
创建自定义 XML 文件 jdbc-config.xml,保存数据库连接信息
<?xml version="1.0" encoding="UTF-8" ?>
<jdbc>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db5?characterEncoding=UTF-8</property>
<property name="user">root</property>
<property name="password">root</property>
</jdbc>
使用 XPath 编写工具类
public class JDBCUtils {
// 定义字符串变量, 记录获取连接所需要的信息
public static String DRIVERNAME;
public static String URL;
public static String USER;
public static String PASSWORD;
// 静态代码块
static {
try {
// 使用 XPath 读取 XML 中的配置信息
SAXReader sr = new SAXReader();
Document document = sr.read("jdbc-config.xml");
DRIVERNAME = document.selectSingleNode("/jdbc/property[@name='driverClass']").getText();
URL = document.selectSingleNode("/jdbc/property[@name='jdbcUrl']").getText();
USER = document.selectSingleNode("/jdbc/property[@name='user']").getText();
PASSWORD = document.selectSingleNode("/jdbc/property[@name='password']").getText();
// 注册驱动
Class.forName(DRIVERNAME);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接的静态方法
public static Connection getConnection(){
try {
// 获取连接对象
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
// 返回连接对象
return connection;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
测试工具类
// 获取所有员工的姓名
public static void main(String[] args) {
try {
// 获取连接
Connection connection = JDBCUtils.getConnection();
// 获取 statement 和执行 SQL
Statement statement = connection.createStatement();
String sql = "select * from employee";
// 处理结果集
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
String ename = resultSet.getString("ename");
System.out.println(ename);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
网友评论