XML+DTD+SAX+DOM4j+Schema

来源:互联网 发布:淘宝开店一件代发经验 编辑:程序博客网 时间:2024/06/05 19:50

    1.XML概述

     

    • 为什么使用XML
    • 现实生活中存在着大量的数据,在这些数据之间往往存在一定的关系,我们希望能在计算机中保存和处理这些数据的同时能够保存和处理他们之间的关系。
    • XML就是为了解决这样的需求而产生的数据存储格式。

     

    1.1 XML:什么是XMLXML一种数据存储格式,这种数据存储格式在存储数据内容的同时,还能够保存数据之间的关系

     

    1.2 XML保存数据的方法:XML利用标签来保存数据的内容,利用标签之间的嵌套关系来保存数据之间的关系。

    XML每一个标签用于描述一段数据

    一个标签可以分为开始标签和结束标签,在开始标签和结束标签之间又可以嵌套其它标签,利用标签间的嵌套关系来保存数据之间的上下级关系;

    由于XML实质上是一段字符串,计算机可以十分方便的对他进行操作,开发人员也可以方便的阅读,因此可以说这是一种对人、对计算机都友好的数据存储格式

     

    1.3XML的应用场景

    1.3.1利用XML跨平台的特性,用来在不同的操作系统不同的开发语言之间传输数据。如果说java是一门跨平台的语言,那XML就是跨平台的数据。

    1.3.2利用XML可以保存具有关系的数据的特性,还常常被用来做为配置文件使用。

     

    1.4XML文件:把XML格式的数据保存到文件中,这样的文件通常起后缀名为.XML,这样的文件就叫做XML文件,XML文件是XML数据最常见的存在形式,但是,这不是XML的唯一存在形式(在内存中或在网络中也可以存在),不要把XML狭隘的理解成XML文件。

     

    1.5XML校验:浏览器除了内置html解析引擎外还内置了XML解析器,利用浏览器打开XML格式的数据,就可以进行XML校验。

    浏览器内用F12进入控制台,查看程序消息。

     

    2.XML语法

    2.1文档声明

    用来声明xml的基本属性,用来指挥解析引擎如何去解析当前xml

    通常一个xml都要包含并且只能包含一个文档声明

    xml的文档必须在整个xml的最前面,在文档声明之前不能有任何内容

     

    2.1.1最简单的写法:<?XML version="1.0" ?>其中的version代表当前XML所遵循的规范版本。version是必须存在的属性,目前位置都写1.0就可以了

    2.1.2使用encoding属性指定文档所使用的字符集编码:<?XML version="1.0" encoding="gb2312" ?>

    注意:encoding属性指定的编码集和XML真正使用的编码应该一致,如果不一致就会有乱码问题

    encoding属性默认值为老外喜欢的iso8859-1

    2.1.3使用standalone属性指定当前XML文档是否是一个独立文档:<?XML version="1.0" standalone="no" ?>,standalone默认值为yes表示是一个独立文档

    注意:很多的解析器会忽略这个属性,但是学习知识要按标准去学,所以这个属性也要掌握。

     

    Ex:

     (1) <?xml version="1.0" ?>--version是必须存在的属性,表明当前xml所遵循规范的版本,目前位置都写1.0就可以了

        (2)<?xml version="1.0" encoding="utf-8" ?>--encoding用来只会解析引擎在解析xml时使用的编码,一定要保证xml格式的数据在保存时使用的编码和解析时使用的编码必须一致,才不会有乱码问题

        (3)<?xml version="1.0" encoding="utf-8" standalone="yes" />--standalone属性用来指明当前xml是否是一个独立的xml,默认值是yes表明当前文档不需要依赖于其他文档,如果当前文档依赖其他文档而存在则需要将此值设置为no

     

    2.2元素

    一个xml标签就是一个元素

    2.2.1元素分为开始标签和结束标签;

    在开始标签和结束标签之间的文本称为标签体

    如果一个标签即不含标签体也不包含其他标签,那这样的标签可以把开始标签和结束标签进行合并,这样的标签叫自闭标签

    <a>xxxxx</a>    <a><a/>可写成:</a>

     

    2.2.2一个元素也可以包含若干子元素,即一个标签可以包含任意的子标签。但是要注意所有的标签都要进行合理嵌套

    Ex:

    <a>welcome to <b>www.it315.org</a></b>  

     

    <a>welcome to ww.it315.org</b></a> 

     

    <a>welcome to ww.it315.org<b/></a> 

     

    <a>welcome to ww.it315<b/>.org</a> 

     

    2.2.3一个格式良好的XML文档应该具有并且只能有一个标签,其他标签都应该是这个标签的子孙标签。

     

    2.2.4元素的命名规范:

    区分大小写,例如,<P>和<p>是两个不同的标记。

    不能以数字或标点符号或"_"开头。

    不能以XML(或XML、或Xml 等)开头。

    不能包含空格。

    名称中间不能包含冒号(:)

     

    2.3属性

    一个元素可以包含多个属性,属性的值要用单引号或双引号括起来。如果属性的之中包含双引号,就要用单引号了。

    属性的命名规范,参照元素的命名规范。

     

    2.4注释

    <!--这是一段注释-->

    注意:注释不能出现在文档声明之前。实验:把注释写到文档声明之前,用ie打开是没问题,但是用chrome打开是报错的。这就看出来了不同的解析器有不同的处理,我们学习的时候还是按标准去学。

    注释不能嵌套注释

     

    2.5CDATA区、转义字符

    都可以用来转义特殊字符。

     

    2.5.1CDATA区

    当XML中一段内容不希望被解析器解析时可以使用CDATA区将其包住

    当解析器遇到CDATA区时会将其内容当作文本对待,不会进行解析

     

    <![CDATA[这是要转义的内容]]>

    被CDATA区扩起来的内容,将会被浏览器当作文本来处理。

    2.5.2转义字符

    & --> &amp;

    < --> &lt;

    >  --> &gt;

    " --> &quot;

    ' --> &apos;        

    不要忘了分号!

                    

    2.5.3CDATA区和转义字符的区别

    (1)CDATA区可以成段的进行转义,而转义字符一次只能转义一个字符

    (2)CDATA区转义的字符可以保存数据本来的格式只是通知解析器按文本去处理。转义字符改变了数据本身的内容,利用其他字符替代了转义字符。请思考,如果要转义的内容是一段js程序的话,如果用转义字符合适不合适?

     

    2.6处理指令:一段指令通知解析器以何种方式解析XML

    语法格式:<?XML-stylesheet type="text/css" href="1.css" ?>

    意即指定解析器使用1.css去渲染当前的XML数据

    其实文档声明就是一个最常见的处理指令。

     

    3.DTD技术(了解语法,看懂即可)

    3.1DTD是一门XML约束技术,用来约束XML写法。DTD(Document Type Definition),全称为文档类型定义

     

    3.2如何在XML中引入一个DTD

    3.2.1外部引入:dtd约束文件存在在一个外部文件中,我们在XML中引入该约束。

    (1)本地文件引入:该dtd文件存在在本地硬盘中

    可以将dtd的约束内容写在外置的dtd文件中,这个文件后缀必须为.dtd而文件保存时必须用utf-8编码保存再在xml文件中使用

    <!DOCTYPE 根元素的名称 SYSTEM "文件所在的路径">

    (2)公共位置文件引入:dtd约束文件存在在一个公共网络上,我们在XML引入该约束

    <!DOCTYPE 根元素的名称 PUBLIC "dtd名称" "dtd所在的URL">

    3.2.2内部引入

    在XML内部写dtd约束在文档声明下

    <!DOCTYPE 根元素名称 [

    dtd约束的内容

    ]>

     

    3.3dtd语法利用dtd约束XML中的元素

    <!ELEMENT 元素名称 元素约束>

    3.3.1元素约束

    (1)存放类型

    ANY:当前声明的元素可以包含任意子元素

    EMPTY:当前声明的元素不能包含任何元素

    (2)存放内容:利用小括号括起来的元素的名称,用来表示该元素中可以存放哪些内容

    <!ELEMENT "元素名" (可以包含的元素的名称)>

    小括号中的内容,可以有多个子元素的名称

    如果用“,”分割这些子元素就表明这些子元素必须按指定的顺序出现

    如果用“|”分割这些内容就表明这些子元素只能出现其中之一

    使用“+”来表明内容可以出现一次或多次

    使用“*”来表明内容可以出现零次或多次

    使用“?”来表明内容可以出现零次或一次

     

    #PCDATA表明该元素可以包含标签体

     

    可以利用()进行组操作:

    <!ELEMENT MYFILE ((TITLE*, AUTHOR?, EMAIL)* | COMMENT)>

     

    3.4利用dtd约束XML中的属性

    <!ATTLIST 元素名

    属性名 属性类型 属性约束

    。。。。

    >

    3.4.1属性类型

    (1)CDATA:表明该属性的值是一个普通的文本值。

    (2)ENUMERATED:表明该属性的值只能取指定范围内的其中之一

    (3)ID:表明该属性值在整个文档中必须唯一,注意ID类型的属性的值必须以字母下划线开头,并且不能以数字开头,不能包含空白字符

     

    3.4.2属性约束

    (1)#REQUIRED 来表明当前这个属性是必须存在的属性,如果这样的属性不存在则在校验时会报错

    (2)#IMPLIED 来表明当前这个属性是可选的属性,如果这样的属性不存在则在校验时会报错

    (3)#FIXED "固定值" 来表明当前这个属性具有一个默认的值,可以不明确指定该属性,解析器会帮你加上,如果你硬是指定了一个其他的值,会出错。

    (4)"默认值" 来表明当前属性具有一个默认的值,如果给这个属性指定一个值就用指定的值,如果不指定呢,就使用默认值。

     

    举例:

          <!ATTLIST 页面作者

         姓名 CDATA #IMPLIED

         年龄 CDATA #IMPLIED

         联系信息 CDATA #REQUIRED

         网站职务 CDATA #FIXED "页面作者"

         个人爱好 CDATA "上网"

           >

     

    3.5实体

    可以理解为对一段内容的引用,如果有一段内容到处在被使用,可以将其设计为一个实体

    好处:可以简化代码的复用

    3.5.1引用实体用在XML中的实体

    声明实体:<!ENTITY 实体名称 "实体内容">

    引用引用实体:&实体名称;

    举例:<!ENTITY copyright “I am a programmer">

     ……

     &copyright;

     

     

    3.5.2参数实体用在DTD文件中的实体

    声明实体:<!ENTITY % 实体名称 "实体内容">

    引用参数实体: %实体名称;

     

     

     

    4.XML编程:利用java程序去增删改查(CRUD)xml中的数据

     

    解析思想:

    dom解析

    sax解析

     

     

    5.sax解析入门

    1ex:一个XML文件:book.xml

    <?xml version="1.0" encoding="gb2312"?>

    <书架>

    <书>

    <书名>Java就业培训教程</书名>

    <作者>张孝祥</作者>

    <售价>39.00元</售价>

    <书名>JavaScript网页开发</书名>

    <作者>张孝祥</作者>

    <售价>28.00元</售价>

    </书>

    </书架>

     

     

    2Ex:

    package sax;

    import javax.xml.parsers.SAXParser;

    import javax.xml.parsers.SAXParserFactory;

    import jdk.internal.org.xml.sax.helpers.DefaultHandler;

    import org.xml.sax.Attributes;

    import org.xml.sax.ContentHandler;

    import org.xml.sax.Locator;

    import org.xml.sax.SAXException;

    import org.xml.sax.XMLReader;

     

    public class SaxDemo1 {

    public static void main(String[] args) throws Exception{

    //1.获取解析器工厂

    SAXParserFactory factory = SAXParserFactory.newInstance();

    //2.通过工厂获取sax解析器

    SAXParser parser = factory.newSAXParser();

    //3.获取读取器

    XMLReader reader = parser.getXMLReader();

    //4.注册事件处理器

    reader.setContentHandler(new MyContentHandler());

    //5.解析XML

    reader.parse("book.xml");

    }

    }

     

    class MyContentHandler2 extends DefaultHandler{

    //因为DefaultHandler实现了ContentHandler接口,所以MyContentHandler2继承DefaultHandler方法,即能实现ContentHandler接口的方法,又可以不写不必要的方法。

    //DefaultHandler方法的作用就是方便实现。这种思想就是适配器设计模式

     

    private String eleName = null;

    private int count = 0;

    @Override

    public void startElement(String url, String localName, String name,

    jdk.internal.org.xml.sax.Attributes attributes)throws jdk.internal.org.xml.sax.SAXException {

    this.eleName = name;

    }

     

    @Override

    public void characters(char[] ch, int start, int length)throws jdk.internal.org.xml.sax.SAXException {

    if("书名".equals(eleName) && ++count==2){

    System.out.println(new String(ch,start,length));

    }

    }

     

    @Override

    public void endElement(String url, String localName, String name)throws jdk.internal.org.xml.sax.SAXException {

    eleName = null;

    }

    }

     

    class MyContentHandler implements ContentHandler{

    public void startDocument() throws SAXException {

    System.out.println("文档解析开始了。。");                

    }

     

    public void startElement(String uri, String localName, String name,

    Attributes atts) throws SAXException {

    System.out.println("发现了开始标签"+name);                

    }

     

    public void characters(char[] ch, int start, int length)

    throws SAXException {

    System.out.println(new String(ch,start,length));                

    }

     

    public void endElement(String uri, String localName, String name)

    throws SAXException {

    System.out.println("发现了结束标签"+name);        

    }

     

    public void endDocument() throws SAXException {

    System.out.println("文档解析结束了。。");                

    }

    public void endPrefixMapping(String prefix) throws SAXException {

    // TODO Auto-generated method stub                

    }

     

    public void ignorableWhitespace(char[] ch, int start, int length)

    throws SAXException {

    // TODO Auto-generated method stub                

    }

     

    public void processingInstruction(String target, String data)

    throws SAXException {

    // TODO Auto-generated method stub        

    }

     

    public void setDocumentLocator(Locator locator) {

    // TODO Auto-generated method stub                

    }

     

    public void skippedEntity(String name) throws SAXException {

    // TODO Auto-generated method stub                

    }

     

    public void startPrefixMapping(String prefix, String uri)

    throws SAXException {

    // TODO Auto-generated method stub

    }

    }

     

    注意sax解析并没有导入第三方的包。

     

    基于这两种解析思想市面上就有了很多的解析api

    sun jaxp既有dom方式也有sax方式,并且这套解析api已经加入到j2se的规范中,意味这不需要导入任何第三方开发包就可以直接使用这种解析方式.但是这种解析方式效率低下,没什么人用.

    dom4j 可以使用dom方式高效的解析xml.

    pull

     

    1. dom4j解析方式

    !!dom4j

    导入开发包,通常只需要导入核心包就可以了,如果在使用的过程中提示少什么包到lib目录下在导入缺少的包即可

     

    接口继承结构:

    Node     ---

    Branch

    --Document

    --Element

    ----

    Attribute

     

    1)入门例子,Ex

    package dom4j;

    import org.dom4j.Document;

    import org.dom4j.Element;

    import org.dom4j.io.SAXReader;

     

    public class dmo4jdemo1 {

    public static void main(String[] args) throws Exception{

    //1.获取解析器

    SAXReader reader = new SAXReader();

    //2.解析XML,获取代表整个文档的dom对象.

    Document dom =reader.read("book.xml");

    //3.获取根节点

    Element root =dom.getRootElement();

    //4.获取书名,进行打印

    String bookName =root.element("书").element("书名").getText(); //getText()方法代表获取节点之间的文本内容。如果是元素则返回标签体,如果是属性则返回属性值。

    System.out.println(bookName);

    }

    }

     

    2)用dom4j方式进行增删改查

    package dom4j;

    import java.io.FileOutputStream;

    import java.io.FileWriter;

    import java.util.List;

    import org.dom4j.Document;

    import org.dom4j.DocumentHelper;

    import org.dom4j.Element;

    import org.dom4j.io.SAXReader;

    import org.dom4j.io.XMLWriter;

    import org.junit.Test;

     

    public class dmo4jdemo1 {

    @Test

    public void atr() throws Exception{ //对属性进行操作

    //1.获取解析器

    SAXReader reader = new SAXReader();

    //2.解析XML,获取代表整个文档的dom对象.

    Document dom = reader.read("book.xml");

    //3.获取根节点

    Element root = dom.getRootElement();

     

    Element bookEle = root.element("书");//element(String name)方法代表获取指定名称的子元素,如果有多个该名称的子元素,则返回第一个。

    bookEle.addAttribute("出版社", "黑马出版社");//addAttribute(String name, String value)方法指为元素添加属性。

     

    //获取指定的属性名称

    String str = bookEle.attributeValue("出版社");

    System.out.println(str);

     

    XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"));//将对节点或属性的操作方法回写到XML文件中去。

    writer.write(dom);

    writer.close();

    }

     

    public void del() throws Exception{

    //1.获取解析器

    SAXReader reader = new SAXReader();

    //2.解析XML,获取代表整个文档的dom对象.

    Document dom = reader.read("book.xml");

    //3.获取根节点

    Element root = dom.getRootElement();

     

    Element price2Ele =root.element("书").element("特价");

    price2Ele.getParent().remove(price2Ele);//删子元素就是在父元素中删掉自己的孩子。

     

    XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"));

    writer.write(dom);

    writer.close();

    }

     

    public void update() throws Exception{

    //1.获取解析器

    SAXReader reader = new SAXReader();

    //2.解析XML,获取代表整个文档的dom对象.

    Document dom = reader.read("book.xml");

    //3.获取根节点

    Element root = dom.getRootElement();

     

    root.element("书").element("特价").setText("4.0元");//通过setText方法修改标签里的内容。如果是元素则设置标签体,如果是属性则设置属性的值。

    XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"));

    writer.write(dom);

    writer.close();

    }

     

    public void add() throws Exception{

    //1.获取解析器

    SAXReader reader = new SAXReader();

    //2.解析XML,获取代表整个文档的dom对象.

    Document dom = reader.read("book.xml");

    //3.获取根节点

    Element root = dom.getRootElement();

     

    /*凭空创建<特价>节点,设置标签体

     * 要想凭空创建一个节点,就使用到DocumentHelper类

     */

    Element price2Ele = DocumentHelper.createElement("特价");

    price2Ele.setText("40.00元");//对标签体的内容进行设置,还是要用到setText方法

     

    //但是还要获取父标签<书>,将特价节点挂载上去才行。

    Element bookEle = root.element("书");

    bookEle.add(price2Ele);

     

    /*将内存中的dom树回写到XML文件中,从而使XML中的数据进行更新。

     * 这一步一定要注意,通过read方法获取到dom文档对象之后,所有的工作就是在内存中进行的。要想使修改生效,还要返回到硬盘中的book.xml文件中去

     * */

    FileWriter writer = new FileWriter("book.xml");

    dom.write(writer);

    writer.flush();

    writer.close();        

    }

     

    public void find() throws Exception{

    //1.获取解析器

    SAXReader reader = new SAXReader();

    //2.解析XML,获取代表整个文档的dom对象.

    Document dom = reader.read("book.xml");

    //3.获取根节点

    Element root = dom.getRootElement();

     

    List<Element> list = root.elements();//Element接口中的elements()方法,是获取调用它的对象中的所有子元素,并用一个list返回。

    Element book2Ele = list.get(1);//这里指的是获取第二个书名,因为是get(1)而不是get(0)

    System.out.println(book2Ele.element("书名").getText());                

    }

    }

     

     

     

    5.Schema -- xml的约束技术 

    --- 需要掌握名称空间的概念,会读简单的Schema就可以了,不需要大家自己会写

     

    1)一些说明

    Schema是xml的约束技术,出现的目的是为了替代dtd

    本身也是一个xml,非常方便使用xml的解析引擎进行解析

    对名称空间有非常好的支持

    支持更多的数据类型,并且支持用户自定义数据类型

    可以进行语义级别的限定,限定能力大大强于dtd

    相对于dtd不支持实体

    相对于dtd复杂的多,学习成本比较的高

     

    2)名称空间

     

    如何在xml中引入Schema --- !!!!!名称空间的概念:全世界独一无二的名字,用来唯一的标识某个资源,通常是公司的域名,只是名字而已并不真的表示资源的位置。访问这个地址并不能真的访问到这个资源。

     

       

        ~~~ Schema的语法---参照Schema的文档,了解即可

     

     

原创粉丝点击