- 通过Dom4j解析XML文档
- xml基本使用
-
- XML简介 (*****了解*****)
XML全称为Extensible Markup Language,意思是可扩展的标记语言。
标记 -> 用标记来修饰文本信息.
可扩展 -> 标记可随意定义.
XML技术 : 与数据相关技术, 在企业中xml技术常用来存储数据和传输数据, xml之所以流行的原因在于xml语言与任何编程语言无关, xml可用于 php, java, .net任何编程语言.
xml 语言就是使用标签来标记数据.
XML 技术主要企业应用 :
- 存储和传输数据.
- 作为框架的配置文件.
1.2 如何去写一个XML (*****重点*****)
XML的编写 : 根据实际的业务场景自行编写`有意义`的标签和属性,创建一个以.xml为后缀名的文件,编写描述一个网上商城的商品信息的xml.
xml编写时也要符合一定的规则:
- xml文件的后缀名是.xml
- xml有且只有一个根标签
- xml的标签是尖括号包裹关键字成对出现的,有开始标签有结束标签,关键字是自定义的, xml也可以有空标签/自关闭标签
- xml允许有属性,属性也是根据需要自定义的,属性格式:属性名=“属性值”,多个属性之间使用空格隔开
- xml是区分大小写的
product.xml
- <?xml version="1.0" encoding="UTF-8" ?>
- <store>
- <product category="手机数码">
- <pid>100</pid>
- <pname>华为手机</pname>
- <price>300</price>
- </product>
- <product category="电脑办公">
- <pid>200</pid>
- <pname>三星笔记本</pname>
- <price>5000</price>
- </product>
- <product category="大型家电">
- <pid>300</pid>
- <pname>海尔洗衣机</pname>
- <price>4000</price>
- </product>
- </store>
xml的组成:
- 文档声明:
- 根标签,例如:<store>
- 其他标签,例如:<pname>
- 属性,例如:
- 文本,例如:
- 注释,例如:
1.3 转义字符 (*****了解*****)
- 转义字符 (语法规则)
因为很多符号已经被XML文档结构所使用,所以在元素体或属性值中想使用这些符号就必须使用转义字符,例如:“<”、“>”、“’”、“””、“&”。
exam.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <exams>
- <exam>
- <subject>测试Java基础</subject>
- <category>判断题</category>
- <question><活着>书籍是否为Java高级程序员必读书籍?</question>
- </exam>
- </exams>
1.4 CDATA区 (*****了解*****)
所有 XML 文档中的文本均会被解析器解析,只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。
- CDATA区 Character Data 字符数据
<![CDATA[
任意内容
]]>
在编写XML文件时, 有些内容可能不想让解析引擎解析执行, 而是当做原始内容处理.
遇到这种情况, 可以把这些内容放在CDATA 区里, 对于CDATA区域内的内容, XML解析程序不会处理, 而是直接原封不动的输出.
当元素内容包含大量转义字符时,可读性下降。可以使用CDATA区原样存储,提高可读性。
char c = 'a';
if( c >= '0' && c <= '9'){
System.out.println("找到:" + c);
}else{
System.out.println("没找到:" + c);
}
转义字符 :
char c = 'a';
if( c >= '0' && c <= '9'){
System.out.println("找到:" + c);
}else{
System.out.println("没找到:" + c);
}
- <?xml version="1.0" encoding="UTF-8" ?>
- <exams>
- <exam>
- <subject>测试Java基础</subject>
- <category>判断题</category>
- <question><活着>书籍是否为Java高级程序员必读书籍?</question>
- </exam>
- <exam>
- <subject>测试Java基础</subject>
- <category>判断题</category>
- <question>
- char c = 'a';
- if( c >= '0' && c <= '9'){
- System.out.println("找到:" + c);
- }else{
- System.out.println("没找到:" + c);
- }
- </question>
- </exam><exam>
- <subject>测试Java基础</subject>
- <category>判断题</category>
- <question><![CDATA[
- char c = 'a';
- if( c >= '0' && c <= '9'){
- System.out.println("找到:" + c);
- }else{
- System.out.println("没找到:" + c);
- }
- ]]></question>
- </exam>
- </exams>
-
- 如何去约束一个XML - DTD (*****了解*****)
提到约束一个XML,必须要理解为什么对XML要进行约束?
因为XML的标签都是自定义的,xml在作为框架配置时不能很好的规范开发者书写,所以要使用约束告知开发者怎去配置一个xml.
XML的约束有两种:
- DTD约束
文档类型定义(Document Type Definition)是一套为了进行程序间的数据交换而建立的关于标记符的语法规则。它是标准通用标记语言和[1] 可扩展标记语言1.0版规格的一部分,文档可根据某种DTD语法规则验证格式是否符合此规则。
- Schema约束
可扩展标记语言架构是以可扩展标记语言为基础的,它用于可替代文档类型定义(外语缩写: DTD);一份XML schema文件描述了可扩展标记语言文档的结构。
-
-
- xml文件内部引用DTD约束 :
-
(DTD简介)
说明 : 开发中,我们很少自己编写DTD约束文档,通常情况我们都是通过框架提供的DTD约束文档,编写对应的XML文档。
- 内部DTD,在XML文档内部嵌入DTD,只对当前XML有效。
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE 根元素名 [
... //具体的语法
]>
CDATA -> Character Date 文本 / 字符数据 属性
PCDATA -> Parse Character Date 解析文本 / 字符数据 元素
books.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- 内部 DTD 约束 -->
- <!DOCTYPE books[
- <!ELEMENT books (book+)>
- <!ELEMENT book (name, price)>
- <!ELEMENT name (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!ATTLIST book author CDATA #REQUIRED> <!-- #IMPLIED 可选 -->
- ]>
- <books>
- <book author="张三丰">
- <name>Java从入门到放弃</name>
- <price>998</price>
- </book>
- <book author="灭绝师太">
- <name>Java编程思想</name>
- <price>99</price>
- </book>
- </books>
-
-
- xml文件引用外部DTD约束 :
-
(DTD简介)
- 外部DTD—本地DTD,DTD文档在本地系统上,公司内部自己项目使用。
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE 根元素名 SYSTEM "文件名.dtd">
books.dtd
- <?xml version="1.0" encoding="UTF-8"?>
- <!ELEMENT books (book+)>
- <!ELEMENT book (name, price)>
- <!ELEMENT name (#PCDATA)>
- <!ELEMENT price (#PCDATA)>
- <!ATTLIST book author CDATA #REQUIRED> <!-- #IMPLIED 可选 -->
books.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- 引入外部 DTD 约束 -->
- <!DOCTYPE books SYSTEM "books.dtd">
- <books>
- <book author="张三丰">
- <name>Java从入门到放弃</name>
- <price>998</price>
- </book>
- <book author="灭绝师太">
- <name>Java编程思想</name>
- <price>99</price>
- </book>
- </books>
1.5.3 xml文件引用公共DTD约束 :
- 外部DTD—公共DTD,DTD文档在网络上,一般都由框架提供。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 根元素名 PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
-
-
- 课堂练习 : 针对给出的DTD约束,写出相应的xml文件
-
servlet.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT servlets (servlet*, servlet-mapping*)>
<!ELEMENT servlet (servlet-name, servlet-class)>
<!ELEMENT servlet-name (#PCDATA)>
<!ELEMENT servlet-class (#PCDATA)>
<!ELEMENT servlet-mapping (servlet-name, url-pattern)>
<!ELEMENT url-pattern (#PCDATA)>
servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE servlets SYSTEM "servlet.dtd">
<servlets>
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>cn.itcast.MyServlet1</servlet-class>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>cn.itcast.MyServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet2</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
</servlets>
1.6 如何去约束一个XML - Schema (*****了解*****)
与DTD一样,可以通过schema约束xml文档的编写规范。常见框架使用schema的有:Spring等
通过提供“bean-schema.xsd”编写xml文档
XML Schema 简介 :
如何使用 XSD ? (XML Schema Difinition)
XSD - <schema> 元素
例如:我们要约束上述编写的books.xml,相应 的Schema约束如下
Schema中分为简单元素和复杂元素
简单元素和复杂元素指 的是xml中的标签是简单标签还是复杂标签
简单元素:标签仅仅包含文本标签体的元素
复杂元素:标签包括子标签或属性的元素
books.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/book"
xmlns:tns="http://www.example.org/book"
elementFormDefault="qualified">
<!-- 每一个元素对应一个element标签 -->
<element name="books">
<!-- 包含子元素或属性的元素被称为 `复杂元素` -->
<complexType>
<!-- 强调子元素出现的顺序 -->
<sequence>
<element name="book" minOccurs="1" maxOccurs="unbounded">
<complexType>
<sequence>
<!-- 对于拥有内容的元素, 需要编写 type 属性 -->
<element name="name" type="string"></element>
<element name="price" type="string"></element>
</sequence>
<!-- book 标签有 author 属性, 类型是字符串, 该属性必须填写 -->
<attribute name="author" type="string" use="required"></attribute>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
books.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <books xmlns="http://www.example.org/books"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.example.org/books books.xsd">
- <book author="张三丰">
- <name>Java从入门到放弃</name>
- <price>998</price>
- </book>
- <book author="灭绝师太">
- <name>Java编程思想</name>
- <price>99</price>
- </book>
- </books>
1.6.2 练习 : 根据Schema约束编写xml文档
bean-schema.xsd
<?xml version="1.0" encoding="UTF-8"?>
<!--
传智播客 Schema 教学实例文档 :
模拟 spring 框架规范 : 如果开发人员需要在 xml 使用当前 schema 约束, 必须包含指定命名空间.
格式如下 :
<beans xmlns="http://www.example.org/bean-schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/bean-schema bean-schema.xsd">
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/bean-schema"
xmlns:tns="http://www.example.org/bean-schema"
elementFormDefault="qualified">
<!-- 声明根标签 -->
<element name="beans">
<complexType>
<sequence>
<element name="bean" minOccurs="0" maxOccurs="unbounded">
<complexType>
<sequence>
<element name="property" minOccurs="0" maxOccurs="unbounded">
<complexType>
<attribute name="name" type="string" use="required"></attribute>
<attribute name="value" type="string" use="required"></attribute>
</complexType>
</element>
</sequence>
<attribute name="id" type="string" use="required"></attribute>
<attribute name="className" type="string" use="required"></attribute>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
bean.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.itcast.cn/bean"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.itcast.cn/bean bean-schema.xsd"
- >
- <bean id="001" className="cn.itcast.User">
- <property name="userName" value="Jack"></property>
- <property name="password" value="123456"></property>
- </bean>
- <bean id="002" className="cn.itcast.User">
- <property name="userName" value="Peter"></property>
- <property name="password" value="654321"></property>
- </bean>
- </beans>
1.7 XML解析概述 (*****了解*****)
XML的实际应用场景
实际开发中,我们一般会使用各种各样的框架进行企业开发,而这些框架一般都会将某些公共的功能都已经写好,我们需要做的只需要按照框架提供的约束进行框架的配置就可以了,当我们使用XML配置好框架后,再运行时,框架底层会解析我们配置XML文档获取有用的信息,从而根据我们的需求实现某些功能。
所以,实际开发中我们很少会自己编写XML约束和解析XML.
1.7.1 解析方式和解析器
- 开发中比较常见的解析方式 (仅仅是思想) 有三种,如下:
- DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。
- 优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
- 缺点:XML文档过大,可能出现内存溢出现象。
- SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件。
- 优点:处理速度快,可以处理大文件
- 缺点:只能读,逐行后将释放资源。
- PULL:Android内置的XML解析方式,类似SAX。
- 解析器:就是根据不同的解析方式的思想提供的具体实现代码。有的解析器操作过于繁琐,为了方便开发人员,又提供易于操作的解析开发包。
- 常见的解析开发包:
- JAXP DOM:sun公司提供支持DOM和SAX开发包
- dom4j:比较常用的解析开发包,hibernate底层采用。 4 for 2 to
- 其它开发包 : Jdom, Jsoup …
1.7.2 dom4j解析 (*****练习*****)
如果需要使用dom4j,必须导入jar包。
dom4j 必须使用核心类SaxReader加载xml文档获得Document,通过Document对象获得文档的根元素,然后就可以操作了。
常用API如下:
- SaxReader对象
- read(…) 加载执行xml文档
- Document对象
- getRootElement() 获得根元素
- Element对象
- elements(…) 获得指定名称的所有子元素。可以不指定名称
- attributeValue(…) 获得指定属性名的属性值
- package cn.itcast.dom4j;
- import java.util.List;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- public class XMLDom4jDemo {
- public static void main(String[] args) throws Exception {
- /*
- * dom4j 工具类的使用 :
- * 核心类 :
- * SAXReader 读取指定的 xml 文档, 生成一个 Document(接口) 对象.
- * 方法 : Document read("文档名称");
- *
- * Document 文档对象, 解析 xml
- * 方法 : Element(标签元素对象) getRootElement() 获取根标签元素, 返回 Element 接口对象
- *
- * Element 标签元素对象
- * 方法 : List<Element> elements() 获取标签中的所有子标签
- */
- // 1. 创建一个 saxReader 对象
- SAXReader saxReader = new SAXReader();
- // 2. 将数据读取到 document 对象中
- Document document = saxReader.read("bean.xml");
- // 3. 使用 document 对象调用 getRootElement 方法获取根标签, 返回 Element 接口实现类对象
- Element rootElement = document.getRootElement();
- // 4. 在根据根标签对象调用 elements 方法获取子标签数组对象
- List<Element> beanElements = rootElement.elements();
- // 5. 遍历, 获取子标签
- for (Element beanElement : beanElements) {
- // 5.2 获取 bean 标签中的两个属性值
- String id = beanElement.attributeValue("id");
- String className = beanElement.attributeValue("className");
- System.out.println(id + " : " + className);
- // 5.3 再获取 bean 标签下的 property 标签
- List<Element> propElements = beanElement.elements();
- // 5.4 遍历, 获取子标签
- for (Element propElement : propElements) {
- String name = propElement.attributeValue("name");
- String value = propElement.attributeValue("value");
- System.out.println("\t" + name + " = " + value);
- }
- }
- }
- }
1.7.3 课堂练习 (解析xml数据)
servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE servlets SYSTEM "servlet.dtd">
<servlets>
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>cn.itcast.MyServlet1</servlet-class>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>cn.itcast.MyServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet2</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
</servlets>
- package cn.itcast.xml;
- import java.util.List;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- public class ParseXMLDemo01 {
- public static void main(String[] args) throws Exception {
- // 1. 创建一个 saxReader 对象
- SAXReader saxReader = new SAXReader();
- // 2. 将数据读取到 document 对象中
- Document document = saxReader.read("servlet.xml");
- // 3. 使用 document 对象调用 getRootElement 方法获取根标签, 返回 Element 接口实现类对象
- Element rootElement = document.getRootElement();
- // 4. 使用 rootElement 根标签对象调用 elements 方法, 传入 servlet, 获取servlet标签对象
- List<Element> servletElements = rootElement.elements("servlet");
- // 5. 遍历, 并获取该标签下的子标签数据内容, 使用父标签对象调用elementText方法, 传入子标签名称获取数据
- for (Element servlet : servletElements) {
- String name = servlet.elementText("servlet-name");
- String cls = servlet.elementText("servlet-class");
- System.out.println(name + " : " + cls);
- }
- // 使用 rootElement 根标签对象调用 elements 方法, 传入 servlet-mapping, 获取servlet-mapping标签对象
- List<Element> mappingElements = rootElement.elements("servlet-mapping");
- for (Element mapping : mappingElements) {
- String name = mapping.elementText("servlet-name");
- String url = mapping.elementText("url-pattern");
- System.out.println(name + " = " + url);
- }
- }
- }