XML与XML解析

一、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;
        }

    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值