Java进阶学习第六天——DOM4J入门

文档版本 开发工具 测试平台 工程名字 日期 作者 备注
V1.0 2016.04.17 lutianfei none

XML约束——schema

  • XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性。
  • schema和DTD的对比(面试题):
    • Schema符合XML语法结构。
    • DOM、SAX等XML API很容易解析出XML Schema文档中的内容。
    • XML Schema对名称空间支持得非常好。
    • XML Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型。
    • XML Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。
    • XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD。

Schema一些概念

  • XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd
  • 和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为schema
  • 应用schema约束 开发xml 过程

  • 编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,这个URI地址叫namespace名称空间,以后XML文件就可以通过这个URI(即名称空间)引用绑定指定名称空间的元素。

Schema开发步骤

  • 开发schema约束文档

    • 引入W3C的名称

      • 根节点上,使用属性xmlns(xml namespace)

        • xmlns="http://www.w3.org/2001/XMLSchema"
    • 定义元素
      • <element name="书架"></element>
    • 判断是否是复杂还是简单的元素
      • 如果是简单 在element有属性 type="数据的类型"
      • 如果是复杂
        • 声明标签是复杂的元素 <complexType>
        • 子元素之间的关系 eg:有序 <sequence>
    • 起名:targetNamespace 目标名称空间
      • 值是任意的:http://www.itcast.cn/1110
    • elementFormDefault :
      • qualified(使用) :质量好的
      • unqualified :质量不好的
  • 在XML文档中引入自己编写的schema文档
    • 引入W3C名称空间,我是实例文档。

      • xmlns="http://www.w3.org/2001/XMLSchema-instance"
    • 引入自己编写的schema的文档
      • xmlns="http://www.itcast.cn/1110"
      • 问题:元素上不能有相同的属性名称
        • 解决:起别名 eg:aa
        • 技巧:在下面出现标签的概率小起别名
    • 引入自己编写的schema文档的地址
      • schemaLocation属性是W3C提供的,如果W3C名称空间要是有别名的话,先把别名写上。
      • xsi:schemaLocation="名称空间 schema文件的地址"
    • 编写属性
      • <attribute name="出版社" type="string" use="required" ></attribute>
      • name 属性名称
      • type 属性类型
      • user 属性约束


// schema 文件:
<?xml version="1.0" encoding="UTF-8"?>

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast.cn/1110" elementFormDefault="qualified">

    <!-- 复杂元素 -->
    <element name="书架">
        <!-- 复杂元素 -->
        <complexType>
            <!-- 有顺序的 -->
            <sequence maxOccurs="unbounded">
                <element name="书">
                    <!-- 复杂的元素 -->
                    <complexType>
                        <!-- 有顺序的 -->
                        <sequence>
                            <!-- 简单元素 -->
                            <element name="书名" type="string"></element>
                            <element name="作者" type="string"></element>
                            <element name="售价" type="double"></element>
                            <element name="简介" type="string"></element>
                        </sequence>

                        <!-- 书的属性 -->
                        <attribute name="出版社" type="string" use="required" ></attribute>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>
// xml 文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<书架 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.itcast.cn/1110"
        xsi:schemaLocation="http://www.itcast.cn/1110 book.xsd"
    >
    <书 出版社="清华出版社">
        <书名>javaweb开发大全</书名>
        <作者>班长</作者>
        <售价>99.8</售价>
        <简介>这是不错啊</简介>
    </书>
    <书 出版社="清华出版社">
        <书名>javaweb开发大全</书名>
        <作者>班长</作者>
        <售价>99.8</售价>
        <简介>这是不错啊</简介>
    </书>
    <书 出版社="清华出版社">
        <书名>javaweb开发大全</书名>
        <作者>班长</作者>
        <售价>99.8</售价>
        <简介>这是不错啊</简介>
    </书>
</书架>

名称空间的概念

  • 在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标识符)表示。
  • 在Xml文件中书写标签时,可以通过名称空间声明(xmlns),来声明当前编写的标签来自哪个Schema约束文档。如:
<itcast:书架 xmlns:itcast=“http://www.itcast.cn”>
    <itcast:书>……</itcast:书>
</itcast:书架>
  • 此处使用itcast来指向声明的名称,以便于后面对名称空间的引用。
  • 注意:名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL** 并不指向一个包含模式定义的文件**。事实上,这个 URL:http://www.itcast.cn 根本没有指向任何文件,只是一个分配的名字。

使用名称空间引入Schema

  • 为了在一个XML文档中声明它所遵循的Schema文件的具体位置,通常需要在Xml文档中的根结点中使用schemaLocation属性来指定,例如:
    <itcast:书架 xmlns:itcast="http://www.itcast.cn"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation=“http://www.itcast.cn book.xsd">
  • schemaLocation此属性有两个值。

    • 第一个值是需要使用的命名空间。
    • 第二个值是供命名空间使用的 XML schema 的位置,两者之间用空格分隔。
  • 注意,在使用schemaLocation属性时,也需要指定该属性来自哪里。

XML的编程

  • 在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
  • SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

JAXP的SAX解析

  • 只能做查询,不能做增删改。
  • SAX解析过程
    • 解析器

      • 获取解析器的工厂
      • 获取解析器对象
      • 解析XML(XML的文件的地址,事件处理器)
    • 事件处理器
      • 自己编写的类,需要继承DefalutHandler类,重写三个方法。
      • startElement()
      • characters()
      • endElement()
  • SAX的解析原理:
    • 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
    • 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理

  • JAXP 的SAX解析案例
package cn.itcast.jaxp.sax;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * SAX的入门
 * @author Administrator
 *
 */
public class JaxpSaxTest {

    public static void main(String[] args) {
        try {
            run1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取所有的解析的内容
     * @throws Exception
     * @throws ParserConfigurationException
     */
    public static void run1() throws Exception{
        // 获取SAX的解析器工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 获取解析器
        SAXParser parser =  factory.newSAXParser();
        // 解析
        parser.parse("src/book2.xml", new MyHandler2());
    }
}

/**
 * 获取作者标签的文本内容
 *
 */
class MyHandler2 extends DefaultHandler{
    // 如果解析到作者标签的时候,flag设置成true
    private boolean flag = false;
    private int count = 0;

    /**
     * 默认解析开始标签,默认调用该方法
     */
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        // 如果要是作者标签,flag设置成true
        if("作者".equals(qName)){
            flag = true;
            count++;
        }
    }

    /**
     * 能控制characters的输出,我只在解析作者标签的时候,才打印
     */
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // 如果flag是true,就打印
        // 每一次都打印
        if(flag && count == 1){
            String str = new String(ch,start,length);
            System.out.println(str);
        }
    }

    /**
     *
     */
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        // flag恢复成false
        flag = false;
    }
}

/**
 * 自己事件处理器
 * 重写三方法
 * @author Administrator
 *
 */
class MyHandler extends DefaultHandler{

    /**
     * 只要一解析到开始标签的时候,默认调用该方法,把解析的内容赋值给参数。
     */
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        System.out.println("开始标签:"+qName);
    }

    /**
     * 只要解析到文本的内容,默认调用该方法
     */
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        String str = new String(ch,start,length);
        System.out.println(str);
    }

    /**
     * 解析到结束标签的时候,默认调用方法,把解析的内容赋值给参数。
     */
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        System.out.println("结束标签:"+qName);
    }

}

DOM4J的解析

  • Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。
  • Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
  • 使用Dom4j开发,需下载dom4j相应的jar文件。
  • dom4j-1.6.1.jar导入到工程中。
  • WEB项目:复制dom4j-1.6.1.jar到 WebRoot – WEB-INF – lib里面。就ok。
  • 非WEB项目 导入后如果未出现奶瓶标志,点中jar包右键选择:Build path –> Add to Build Path。

查找标签文本

  • 想要查找内容,需要一层一层去查找内容,通过根节点去查找字节点,再查找子节点的子节点)
  • 具体实现
    • 创建解析器 new SAXReader()
    • 解析xml read()
    • 获取根节点 getRootElement()
    • 获取所有的指定标签的集合 root.elements(标签名)
    • 返回List集合,可以遍历集合或者getIndex()获取Element对象
    • 获取文本 getText()

添加子节点

  • 在指定的节点中新增节点
  • 具体实现
    • 创建解析器 new SAXReader()
    • 解析xml read()
    • 获取根节点 getRootElement()
    • 获取所有的指定标签的集合 root.elements(标签名)
    • 直接调用addElement()设置子节点
    • 使用setText()设置文本
    • 回写xml文件

在指定位置添加子节点

  • 创建元素标签节点 DocumentHelper.createElement()
  • 设置文本 setText()
  • 获取某个标签下的所有子节点 elements(),返回list集合
  • 通过 list.add(index, element)方法在内存中加入子元素
  • 回写xml文件

修改节点文本和删除节点

  • 修改指定节点的文本内容

    • 找到指定的节点 elements()
    • 修改文本内容 setText()
  • 删除节点
    • 找到要删除的节点
    • 通过父节点调用 remove()方法删除

DOM4J对XPATH的支持

  • 导入包jaxen-1.1-beta-6.jar
  • 使用方式:
    • selectNodes("/AAA") 返回集合
    • selectSingleNode() 一个Node对象
    • 参数就是xpath的语法
      • /AAA/BBB 获取BBB的节点
      • //BBB 无论层级关系,找到BBB的节点
      • * 代表是所有
      • /AAA/BBB[1] 找到BBB的第一个
      • /AAA/BBB[last()] 最后一个
      • @ 属性
  • DOM4J练习
package cn.itcast.dom4j;

import java.io.FileOutputStream;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * DOM4J的解析XML
 * @author Administrator
 *
 */
public class Dom4jTest {

    public static void main(String[] args) {
        try {
            run6();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 对XPATH的支持
     * @throws Exception
     */
    public static void run6() throws Exception{
        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 解析XML
        Document document = reader.read("src/book2.xml");
        // List<Node> list = document.selectNodes("/书架/书/作者");
        List<Node> list = document.selectNodes("//作者");
        Node author2 = list.get(1);
        System.out.println(author2.getText());
    }

    /**
     * 修改文本内容
     * @throws Exception
     */
    public static void run5() throws Exception{
        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 解析XML
        Document document = reader.read("src/book2.xml");
        // 获取根节点
        Element root = document.getRootElement();
        // 获取狗的节点
        Element book2 = (Element) root.elements("书").get(1);
        Element dog = book2.element("狗");
        dog.setText("小狗");
        // 回写
        // 回写
        OutputFormat format = OutputFormat.createPrettyPrint();
        // 回写
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
        writer.write(document);
        writer.close();
    }

    /**
     * 删除子节点
     *  删除第二本书下的猫节点
     */
    public static void run4() throws Exception{
        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 解析XML
        Document document = reader.read("src/book2.xml");
        // 获取根节点
        Element root = document.getRootElement();
        // 获取猫
        Element book2 = (Element) root.elements("书").get(1);
        Element cat = book2.element("猫");
        // 通过猫获取猫的父节点
        // cat.getParent();
        // 通过父节点删除猫
        book2.remove(cat);
        // 回写
        OutputFormat format = OutputFormat.createPrettyPrint();
        // 回写
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
        writer.write(document);
        writer.close();
    }

    /**
     * 在第二本书的作者标签之前添加团购价的标签
     * @throws Exception
     */
    public static void run3() throws Exception{
        // List
        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 解析XML
        Document document = reader.read("src/book2.xml");
        // 获取根节点
        Element root = document.getRootElement();
        // 获取第二本书
        Element book2 = (Element) root.elements("书").get(1);
        // 获取书下的所有子节点,返回List集合
        List<Element> list = book2.elements();
        // 创建元素对象   DocumentHelper.createElement("狗")
        Element dog = DocumentHelper.createElement("狗");
        dog.setText("大狗");
        // list.add(index,Element);
        list.add(1, dog);

        OutputFormat format = OutputFormat.createPrettyPrint();
        // 回写
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
        writer.write(document);
        writer.close();
    }

    /**
     * 在第二本书下添加子节点
     */
    public static void run2() throws Exception{
        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 解析XML,返回Document对象
        Document document = reader.read("src/book2.xml");
        // 获取根节点
        Element root = document.getRootElement();
        // 获取第二本书
        Element book2 = (Element) root.elements("书").get(1);
        // 可以直接在第二本书下添加子节点,设置文本内容
        book2.addElement("猫").setText("我是猫");
        // 回写

        // 创建漂亮的格式
        OutputFormat format = OutputFormat.createPrettyPrint();
        //OutputFormat format = OutputFormat.createCompactFormat();

        // 设置编码
        format.setEncoding("UTF-8");

        // 回写类
        XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
        // 回写了文档对象
        writer.write(document);
        // 关闭流
        writer.close();
    }

    /**
     * 获取第二本书作者的文本内容
     * @throws Exception
     */
    public static void run1() throws Exception{
        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 解析XML,返回Document对象
        Document document = reader.read("src/book2.xml");
        // 获取根节点(书架标签)
        Element root = document.getRootElement();
        // 获取书的节点,获取第二本书
        List<Element> books = root.elements("书");
        Element book2 = books.get(1);
        // 获取作者的标签
        Element author2 = book2.element("作者");
        // 获取文本内容
        System.out.println(author2.getText());
    }

}

扩展练习

  • 通过XML管理学生的信息
时间: 2024-10-03 09:37:45

Java进阶学习第六天——DOM4J入门的相关文章

Java进阶学习(2)——log4j的学习和使用

Java进阶学习(2)--log4j的学习和使用 简介Loj4j Log4j的组成 Log4j主要由三大组组件构成: Logger: 负责生成日志,并能够对日志信息进行分类筛选,通俗的讲就是决定什么日志信息应该被输出,什么日志信息应该被忽略. Appender: 定义了日志信息输出的目的地,指定日志信息应该被输出到什么地方,这些地方可以是控制台.文件或网络设备等. Layout: 指定日志信息的输出格式. 说明: 一个Logger可以有多个Appender,这意味着日志信息可以被输出到多个设备上

java进阶学习计划

断断续续使用java也已经有两年了,算是最熟悉的开发工具了.但写的代码都是以项目为导向,追求work around,还需要打好基础才能长远发展. 大致的进阶学习计划, 阶段1:深究java语法,阅读常用库的jdk源码,了解jvm机制; 阶段2:阅读基于java的开源框架源码,各种framework,container. 希望可以坚持下来,经常更新技术博客. java进阶学习计划

Java:进阶学习(1)——网络编程

Java:进阶学习(1)--网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket方法 getInetAddress();    远程服务端的IP地址 getPort();    远程服务端的端口 getLocalAddress()    本地客户端的IP地址 getLocalPort()    本地客户端的端口 getInputStream();   

Java工程师学习指南(入门篇)

Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都是站在Java后端的全局上进行思考和总结的,忽略了很多小白们的感受,而很多朋友都需要更加基础,更加详细的学习路线. 所以,今天我们重新开一个新的专题,分别按照四篇文章讲述Java的学习路线(分别是入门篇,初级篇,中级篇,高级篇),笔者也打算趁此机会,回忆一下自己的Java学习历程.今天我们要讲的是,

Java进阶学习第五天——XML入门

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.04.14 lutianfei none onsubmit事件 控制表单提交 需要把onsubmit作用在表单上 <form onsubmit=""> 值的写法:onsubmit="return run()" run()必须要有返回值,必须返回true或者false. 如果返回是true,表单可以提交,如果返回false,表单不能提交.如果没有返回值,默认是表单提交. run(

Java进阶学习第九天——Servlet入门

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.04.21 lutianfei none Servlet开发 Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想要开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤: 编写一个Java类,实现servlet接口. 把开发好的Java类部署到web服务器中. Servlet快速入门 用se

Java进阶学习第十七天——JDBC入门学习

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.05.11 lutianfei none JDBC JDBC介绍 JDBC是什么? JDBC(Java Data Base Connectivity,java数据库连接) SUN公司为了简化.统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC. 简单说,就是可以直接通过java语言去操作数据库. jdbc是一套标准,它是由一些接口与类组成的. 组成JDBC的类和接口 java.sql 类:Drive

Java进阶学习第十一天——cookie&amp;session入门

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.05.04 lutianfei none JSP.EL表达式的入门(重点) Servlet/JSP 是两种动态的WEB资源的两种技术. * Servlet的缺点* 开发人员要十分熟悉JAVA 不便于页面调试和维护 修改.重新编译 很难利用网页设计工具进行页面设计 HTML内容导入到servlet中 用PrintWriter的对象进行输出 JSP简介 JSP( JavaServer Pages )是由Sun公司倡导.许多

Java进阶学习第四天——DOM入门

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.04.14 lutianfei none DOM 文档对象模型 文档:标记型文档 (HTML/XML) 对象:封装了属性和行为的实例,可以直接被调用. 模型:所有的标记型文档都具有一些共性特征的一个体现. DOM解析HTML 通过DOM的方法,把HTML全部元素(标签.文本.属性)都封装成了对象. <span id="spanId">文本</span> span 标签 id 属性 文本