一、XML
1、XML概述
1.1 XML介绍
XML指可扩展标记语言(EXtensible Markup Language)【它是就一堆自定义的标签!】
XML是一种标记语言(标签),很类似 HTML,HTML文件也是XML文档
XML的设计宗旨是传输数据,而非显示数据(HTML:在浏览器中显示数据)
XML标签没有被预定义。您需要自行定义标签。
XML被设计为具有自我描述性(就是易于阅读)。【配置文件】
XML是 W3C 的推荐标准
W3C在1988年2月发布1.0版本,2004年2月又发布1.1版本,单因为1.1版本不能向下兼容1.0版本,所以1.1没有人用。同时,在2004年2月W3C又发布了1.0版本的第三版。我们要学习的还是1.0版本。
1.2 XML的作用
- XML可以存储数据 , 作为数据交换的载体(使用XML格式进行数据的传输)。
- XML也可以作为配置文件,例如后面框架阶段我们学习的Spring框架的配置(applicationContext.xml)都是通过XML进行配置的(企业开发中经常使用的)
xml文件可以充当配置文件,properties文件也可以充当配置文件!
properties配置文件:简单(键值对!),无法描述配置的层级关系!而xml文件可以!
1.3 XML与HTML的主要差异
XML不是HTML的替代品!XML和HTML为不同的目的而设计。
- XML被设计为传输和存储数据,其焦点是数据的内容(旨在传输信息)。【标签未被预定义】
- HTML被设计用来显示数据,其焦点是数据的外观(旨在显示信息)。【标签都被预定义好了】
2、XML入门案例
展示xml存储数据功能**
需求:编写xml文档,用于描述人员信息,person代表一个人员,id是人员的属性,代表人员编号。人员信息包括name姓名、age年龄、sex性别信息。
第一步:使用IDEA编写一个person.xml文件
第二步:编写person.xml文件内容
<?xml version="1.0" encoding="UTF-8" ?>
<!--
这是xml的注释!
编写xml文档,用于描述人员信息,person代表一个人员,id是人员的属性,代表人员编号。人员信息包括name姓名、age年龄、sex性别信息。
-->
<persons> <!--代表所有的人员信息-->
<person id="001">
<!--代表具体的某个人员信息: 刘乃静-->
<name>刘乃静</name>
<age>22</age>
<sex>男</sex>
</person>
<person id="002">
<!--代表具体的某个人员信息: 马继昌-->
<name>马继昌</name>
<age>25</age>
<sex>女</sex>
</person>
</persons>
第三步:查看
3、XML语法
3.1 XML组成部分
XML文件中常见的组成元素有:文档声明、元素、属性、注释、转义字符、字符区。
3.2 注释
XML的注释以 结束
<!-- 注释内容 -->
3.3 文档声明
文档声明:<?xml version="1.0" encoding="utf-8" ?>
- 使用IDE创建xml文件时就带有文档声明.
- 文档声明必须为<?xml开头,以?>结束
- 文档声明必须从文档的0行0列位置开始
- 文档声明中常见的两个属性:
- version:指定XML文档版本。必须属性,这里一般选择1.0;
- enconding:指定当前文档的编码,可选属性,默认值是utf-8;
3.4 元素
* 开始标签、元素体、结束标签组成。
例如:<name>张三</name>
解释:
开始标签:<name>
元素体:张三 【开始标签和结束标签中间夹着的内容】
结束标签:</name>
【元素体也可以包含标签 ===>>> <person><name>jack</name></person>】
* 空元素:空元素只有标签,而没有结束标签,但元素必须自己闭合,例如:<sex/> 【还有一个称呼:自闭标签】
* 格式化良好的XML文档,有且仅有一个根元素
<person id="001"> <!-- person就是一个根元素 -->
<name>刘乃静</name>
<age>22</age>
<sex>男</sex>
</person>
* 命名:
①严格区分大小写 <!-- <PERSON> 与<person> 都不是同一个! -->
②不建议使用以下标签 <!-- <XML> <xml> <Xml> -->
* 文本值:2个标签中间夹着的内容(里面没有字标签)!
3.5 属性
属性是为了描述当前元素(标签具有什么!)
<person id="001">
<name>刘乃静</name>
<age>22</age>
<sex>男</sex>
</person>
上面的代码中,id就是person元素的属性(代表这个人的编号)
* 属性的注意问题:
① 属性是元素的一部分,它必须出现在元素的开始标签中
<person id="001"> 这是正确的!
</person id="001"> 这是错误的!
②属性的定义格式:属性名=“属性值”,其中属性值必须使用单引或双引号括起来
<person id="001"> 这是正确的!
<person id='002'> 这是正确的!
③一个元素可以有0~N个属性,但一个元素中不能出现同名属性
<person> 这是正确的!
<person id="001"> 这是正确的!
<person id="001" num="10"> 这是正确的!
<person id="001" id="10"> 这是错误的!
④属性名不能使用空格 , 不要使用冒号等特殊字符,且必须以字母开头
3.6 转义字符
有的时候,需要在标签的文本值位置写上很多描述信息,里面包含了一些特殊的字符,xml是不支持(特殊字符会报错)!
3.7 CDATA区
一旦我们在xml文件中书写了很多实体字符,那么需要挨个给他使用转义符来转义,这样很麻烦,可以使用CDATA区一次性解决!
<![CDATA[书写在这个里面的内容就会原样输出,不会进行转义!]]>
4、XML约束
4.1 dtd约束
DTD是文档类型定义(Document Type Definition)。DTD 可以定义在 XML 文档中出现的元素、这些元素出现的次序、它们如何相互嵌套以及XML文档结构的其它详细信息。
4.2 schema约束
它是xml约束的一种,功能比dtd约束更强大,数据类型约束更完善!schema约束本身也是xml文档,为了与xml文件以示区别,将其扩展名定义为.xsd。
二、XML解析
当将数据存储在XML后,我们就希望通过程序获取XML的内容。如果我们使用Java基础所学的IO知识是可以完成的,不过你学要非常繁琐的操作才可以完成,且开发中会遇到不同问题(只读、读写)。人们为不同问题提供不同的解析方式,使用不同的解析器进行解析,方便开发人员操作XML。
2.1 解析方式
处理问题的思路!
1. DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象
a)优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
b)缺点:XML文档过大,可能出现内存溢出
2. SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都触发对应的事件。(了解)
a)优点:处理速度快,可以处理大文件
b)缺点:只能读,逐行后将释放资源,解析操作繁琐。
3. PULL:Android内置的XML解析方式,类似SAX。(了解)
基于DOM解析方式的原理图:
2.2 解析器
处理问题的工具
解析器,就是根据不同的解析方式提供具体实现。有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包
* 常见的解析开发包有:
JAXP:sun公司提供支持DOM和SAX开发包
Dom4j:比较简单的的解析开发包(常用) 【★★★★★】 解析xml文件!
JDom:与Dom4j类似
Jsoup:功能强大DOM方式的XML解析开发包,尤其对HTML解析更加方便(项目中讲解)
2.3 DOM4j的基本操作
2.3.1 导入dom4j开发的核心包
dom4j 必须使用核心类SaxReader加载xml文档获得Document,通过Document对象获得文档的根元素,然后就可以操作了。
2.3.2 dom4j核心API
* DOM4j通用的api:
// 获得核心解析器对象
new SAXReader() // 构造器
// 使用SaxReader对象来加载xml文件获得Document对象
Document read(String url) // 加载执行xml文档
// Document对象来获得xml文件的根元素
Element getRootElement() // 获得根元素
* Element对象的相关方法:
List elements([String ele] ) // 获得指定名称的所有子元素。可以不指定名称
Element element([String ele]) // 获得指定名称第一个子元素。可以不指定名称
String getName() // 获得当前元素的元素名
String attributeValue(String attrName) // 获得指定属性名的属性值
String elementText(Sting ele) // 获得指定名称子元素的文本值
String getText() // 获得当前元素的文本内容
2.3.3 dom4j解析books.xml文件
books.xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="0001">
<name>斗罗大陆</name>
<author>唐家三少</author>
<sale>88</sale>
</book>
<book id="0002">
<name>斗破苍穹 </name>
<author>乱</author>
<sale>68</sale>
</book>
</books>
测试类:
public class BookTest {
public static void main(String[] args) throws DocumentException {
// 获得核心解析器对象
SAXReader saxReader = new SAXReader();
// 使用核心解析器对象读取xml文件得到Document对象
Document document = saxReader.read("day15_xml/src/books.xml");
//System.out.println(document); // org.dom4j.tree.DefaultDocument@682a0b20 [Document: name day15_xml/src/books.xml]
// 使用document对象获得根元素节点
Element root = document.getRootElement();
//System.out.println(root.getName()); // books
// 获得根元素节点的所有子元素节点
List<Element> bookEles = root.elements("book");
// 调用方法,获得books.xml文件所有的数据(属性值,文本值)
//getData(bookEles);
// 获得id值为0002的书名!
getBookName(bookEles,"0002");
}
/*
获得id值为0002的书名!
*/
public static void getBookName(List<Element> bookEles,String id) {
// 非空判断
if(!bookEles.isEmpty()){
// 遍历
for (Element bookEle : bookEles) {
// 判断
if(bookEle.attributeValue("id").equals(id)){
System.out.println(bookEle.elementText("name"));
}
}
}
}
public static void getData(List<Element> bookEles) {
// 遍历
for (Element bookEle : bookEles) {
// 获得元素的名称
//System.out.println(bookEle.getName()); // book book
// 获得指定属性id的值
//System.out.println(bookEle.attributeValue("id")); // 001 002
// 获得指定元素的文本值
//System.out.println(bookEle.elementText("name"));
// 继续遍历获得book元素节点的子元素节点
List<Element> eles = bookEle.elements();
for (Element ele : eles) {
// 获得当前元素节点的文本值
System.out.println(ele.getName()+":"+ele.getText());
}
}
}
}
2.4 Dom4j结合Xpath解析xml文件
XPath 使用路径表达式来选取XML 文档中的元素节点或属性节点。节点是通过沿着路径 (path) 来选取的。XPath在解析HTML文档方面提供了一独树一帜的路径思想。
// Document对象的核心方法:
List selectNodes("表达式") //获取符合表达式的元素集合
Element selectSingleNode("表达式") // 获取符合表达式的唯一元素
关键点:表达式的路径如何写呢? ===>>>通过查阅API文档学习!
/AAA =====>>> 获得根元素AAA
/AAA/CCC =====>>> 获得根元素下面的所有CCC
//BBB =====>>> 获得所有的BBB元素
/AAA/BBB[1] =====>>>> 获得根元素下面的第一个BBB元素
//BBB[@id='b1'] =====>>>> 获得有id属性并且值为b1的BBB元素! 【开发常用!】
需求:获得id值为0002的书名!
/*
// Document对象的核心方法:
List selectNodes("表达式") //获取符合表达式的元素集合
Element selectSingleNode("表达式") // 获取符合表达式的唯一元素
需求:获得id值为0002的书名
*/
@Test
public void test() throws DocumentException {
// 创建SaxReader核心解析器对象
SAXReader saxReader = new SAXReader();
// 通过核心解析器对象加载xml文件获得Document对象
Document document = saxReader.read("src/books.xml");
/*
创建的是模块:
单元测试路径相对的是模块
main方法路径相对的是项目!
*/
// 获得id为0002的书book
Element book = (Element) document.selectSingleNode("//book[@id='0002']");
// 获得指定元素名称的文本值
System.out.println(book.elementText("name"));
}
三、扩展内容
面向接口编程(xml+反射实现解耦问题)
/*
接口
*/
public interface Animal {
void eat();
}
/*
Animal接口的实现类!
*/
public class Dog implements Animal{
@Override
public void eat() {
System.out.println("狗吃骨头!");
}
}
/*
Animal的实现类
*/
public class Cat implements Animal {
@Override
public void eat() {
System.out.println("猫吃鱼!");
}
}
/*
测试类
*/
public class Test {
public static void main(String[] args) {
// 创建动物类对象
/*Dog dog = new Dog();
dog.eat();*/
// 更换动物类对象!
/*Cat cat = new Cat();
cat.eat();*/
// 本身创建动物类对象
/* Animal animal = new Dog(); // 若要更换动物类对象,只需要修改new Dog()就好了!
animal.eat();*/
/*
上面的代码也不够优秀!违背了java的一个开闭原则(ocp)
对已经写好的代码,不建议修改,你可以添加新的代码!
我们可以使用配置文件+反射来处理!
*/
Animal animal = (Animal) BeanFactory.getBean("Animal");
animal.eat();
// 此时要更换动物类的对象!不用更改java源代码,只需要修改配置文件!
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<!--<bean id="Animal" class="com.itheima.demo05_interface.Dog"></bean>-->
<bean id="Animal" class="com.itheima.demo05_interface.Cat"></bean>
<bean id="Star" class="com.itheima.demo05_interface.ChunGe"></bean>
</beans>
/*
工具类:用于读取配置文件beans.xml,创建实例对象
*/
public class BeanFactory {
public static void main(String[] args) {
Object obj = getBean("Animal");
//System.out.println(obj); // com.itheima.demo05_interface.Dog@5e265ba4 【子类就是父类!】
Animal animal = (Animal) getBean("Animal");
System.out.println(animal);
}
public static Object getBean(String id){
try {
// 读取配置文件
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("day15_xml/src/beans.xml");
// 获得标签:<bean id="Animal" class="com.itheima.demo05_interface.Dog"></bean>
Element element = (Element) document.selectSingleNode("//bean[@id='"+id+"']");
// 获得Class属性的值
String className = element.attributeValue("class");
// 获得字节码对象
Class<?> clazz = Class.forName(className);
// 创建实例对象
Object obj = clazz.newInstance();
return obj;
} catch (Exception e) {
return null;
}
}
}