zoukankan      html  css  js  c++  java
  • XML 基础

    XML语言

      

    一、XML是什么?作用是什么?

    l  XML ( eXtensible Markup Language )语言是一种可扩展的标记语言。其中的可扩展是相对HTML来说的。因为XML标签没有被预定义,需要用户自行定义标签

    l  XML 被设计的宗旨是:是表示数据,而非显示数据

    作用:

    l  Java开发中,传统的配置文件是*.properties属性文件(key=value),而XML表示的数据更为丰富。

    l  XML技术除用于描述有关系的数据外,还经常用作软件配置文件,以描述程序模块之间的关系。如:


                   
      
      

    这样的关系数据该如何处理?

    用XML语言处理:

                  
          

        总结:在XML语言中,它允许用户自定义标签,一个标签用于描述一段数据,一个标签分为开始标签和结束标签,在这两者之间又可以使用其它标签描述其他数据,以此来实现数据关系的描述。

    二、XML的基本语法

    1、文档声明

      文档的声明必须出现在第一行,之前连空行和注释都不能有.

      文档声明, 最简单的语法: <?xml version="1.0"?>

      encoding="UTF-8", 如果不添加,默认的采用的是UTF-8编码,保存在磁盘上的编码要与声明的编码一样!

      standalone属性,用来说明文档是否独立,即文档是否依赖其他文档。

    <?xml version="1.0" encoding="utf-8"?>

    2、元素

      1)       xml 元素是指xml中的标签。一个标签分为开始标签和结束标签:

        a)         包含标签主体:<mytag>some content</mytag>

        b)         不含标签主体:<mytag/>

      2)       一个XML文档必须有且仅有一个根标签,其他标签都是这个根标签的子标签或孙标签。

      3)       一个标签中可以嵌套若干子标签,但所有标签必须合理的嵌套,不允许有交叉嵌套。

      4)       xml 中的空格与换行不会被忽略,会当做原始内容被处理.

      5)       一个XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范:

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

        b)         不能以数字或"_" (下划线)开头。

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

        d)         不能包含空格。

        e)         名称中间不能包含冒号(:) (有特殊用途)。

    3、属性

      1)       一个标签可以有多个属性,每个属性都有它自己的名称和取值,例如:  <mytag name="value"/>

      2)       属性值一定要用双引号(")或单引号(')引起来

      3)       定义属性必须遵循与标签相同的命名规范

      4)    在XML技术中,标签属性所代表的信息,也可以被改成用子元素的形式来描述。

    4.注释 

      注释的语法: <!--这是注释哦.-->

      注释不能写在第一行.

      注释不能够嵌套. 

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!-- 注释 -->
     3 <书架> 
     4   <书 出版社="中国上海"> 
     5     <名字>诛仙</名字>  
     6     <作者>萧鼎</作者>  
     7     <价格>32.00</价格>  
     8     <出版日期>2007年</出版日期> 
     9   </>  
    10   <书 出版社="中国北京"> 
    11     <名字>笑傲江湖</名字>  
    12     <作者>金庸</作者>  
    13     <价格>50.00</价格> 
    14   </> 
    15 </书架>

    5.CDATA区

      用于将一段内容当做普通文本.

      语法:<![CDATA[

                       文本内容

             ]]>

    6.特殊字符

        &     &amp;    ampersand

        <      &lt;          less than

        >      &gt;         great than

        "      &;quot;   quotation

        '        &apos;    apostrophe

    7.处理指令(processing instruction) (PI)

        作用:用来指挥软件如何解析XML文档

        语法: <?xml  ?>

        如:常用的PI指令:

        XML声明:<?xml version=“1.0” encoding=“GB2312”?>

        xml-stylesheet指令:<?xml-stylesheet type = “text/css” herf=”test.css”>

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 这里用处理命令加入css样式 -->
    <?xml-stylesheet type="text/css" href = "PITest.css" ?>
    <中国>
        <北京>北京</北京>
        <上海>上海</上海>
        <深圳>深圳</深圳>
    </中国>

      PITest.css 文档如下:

     1 @CHARSET "UTF-8";
     2 北京{
     3         font-size: 100px ;
     4         color: red; 
     5     }
     6 上海{
     7         font-size: 110px ; 
     8         color: green  ;
     9     }
    10 深圳{
    11         font-size:100px ;
    12         color: yellow ; 
    13     }

      

    三、XML的约束

             1、在XML 技术中可以编写一个文档来约束XML 文档里面的书写规范,这称为XML约束。

             2、XML 约束技术:

             常用的有:XML DTD 和 XML Schema

             3、XML 约束的必要性:

         a) XML都是用户自定义的标签,若出现小小的错误,软件程序将不能正确地获取文件中的内容而报错.

             总结:

             格式良好的XML 文档,遵循语法规则的XML 文档。

             有效的XML 文档,遵循约束文档的 XML 文档。

             约束文档定义了在XML中允许出现的元素名称、属性及元素出现的顺序等等。

    四、DTD的基本语法

       1.DTD 约束的两种方式:

             DTD 约束可以作为一个单独的文档编写,也可以编写在XML 文档内。(编写XML内部的DTD代码),当作为单独文件时,要用utf-8格式存储。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!--  在XML 写入DTD 约束 -->
     3 <!DOCTYPE 世界[
     4     <!ELEMENT 世界 (国家+) >
     5     <!ELEMENT 国家 (名字)>
     6     <!ELEMENT 名字 (#PCDATA) >
     7     <!ATTLIST 名字
     8         所属洲  CDATA #IMPLIED 
     9     >
    10     <!ATTLIST 国家 所属洲 (亚洲|欧洲|南美洲|南极洲|澳洲|非洲|北美洲) "亚洲">
    11     ]>
    12     
    13 <世界>
    14      <国家 所属洲 = "亚洲">
    15          <名字>中国</名字>
    16      </国家>
    17      <国家>
    18          <名字 所属洲 = "美洲">美国</名字>
    19      </国家>
    20 </世界>

             XML 引用 DTD 约束文件时:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!DOCTYPE 书架 SYSTEM "book.dtd" >
     3 <书架> 
     4   <> 
     5     <名字>诛仙</名字>  
     6     <作者>萧鼎</作者>  
     7     <价格>32.00</价格>   
     8   </>  
     9   <> 
    10     <名字>笑傲江湖</名字>  
    11     <作者>金庸</作者>  
    12     <价格>50.00</价格> 
    13   </> 
    14 </书架>

             a)本地的 : <!DOCTYPE 根元素 SYSTEM “DTD文档路径”>

             b)互联网上的:  <!DOCTYPE 根元素 PUBLIC “DTD文档路径” "dtd的URL地址">

    如:<!DOCTYPE web-app PUBLIC  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

        "http://java.sun.com/dtd/web-app_2_3.dtd">

      注意book.dtd文档如下:

    <!ELEMENT 书架 (书+)>
        <!ELEMENT 书 (名字,作者,价格)>
            <!ELEMENT 名字 (#PCDATA)>
            <!ELEMENT 作者 (#PCDATA)>
            <!ELEMENT 价格 (#PCDATA)>
            

      DTD 编写细节:

      1、 元素定义

      在DTD 文件中用ELEMENT 声明一个 XML元素,语法:

      <!ELEMENT 元素名称 元素类型>

      元素类型可以是元素内容。

      元素内容,则需要用() 括起来,

               <!ELEMENT 世界 (国家+) >

               <!ELEMENT 国家 (名字,所属洲)>

               <!ELEMENT 名字 (#PCDATA)>

      元素类型的组成遵循正则表达式的格式:

        1、用逗号分隔,表示内容的出现顺序必须与声明时一致。

          <!ELEMENT MYFILE (TITLE,AUTHOR,EMAIL)>

        2、用|分隔,表示任选其一,即多个只能出现一个

                 <!ELEMENT MYFILE (TITLE|AUTHOR|EMAIL)>

        3、在元素内容中也可以使用+、*、?等符号表示元素出现的次数:

                        +: 一次或多次 (书+)      regex

                       ?: 0次或一次 (书?)

                        *: 0次或多次  (书*)

        4、也可使用圆括号( )批量设置,例

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

       元素类型,则直接书写,DTD规范定义了如下几种类型:

        EMPTY:用于定义空元素,例如<br/> <hr/>

        ANY:表示元素内容为任意类型。

    2、 属性定义

      xml文档中的标签属性需通过ATTLIST为其设置属性

      语法格式:

      <!ATTLIST 元素名

                 属性名1 属性值类型 设置说明

                 属性名2 属性值类型 设置说明

                 ……

      >

      设置说明:

      #REQUIRED:必须设置该属性

      #IMPLIED:可以设置也可以不设置

      #FIXED:说明该属性的取值固定为一个值,在 XML 文件中不能为该属性设置其它值。但需要为该属性提供这个值

      直接使用默认值:在 XML 中可以设置该值也可以不设置该属性值。若没设置则使用默认值。但需要为该属性提供这个值

      常用属性值类型

      l  CDATA:表示属性值为普通文本字符串

      l  ENUMERATED

      l  ID  indentity

      l  ENTITY(实体)

    1 <!ELEMENT 国家 (名字)>
    2 <!ATTLIST 国家
    3     所属洲 CDATA #REQUEIRED >

      

    3、 实体定义

      实体用于为一段内容创建一个别名,以后在XML  文档中就可以使用别名引用这段内容。

      实体可分为两种类型:引用实体和参数实体。

      引用实体主要在XML 文档中被使用:

      语法格式:<!ENTITY 实体名称 “实体内容” >: 直接转变成实体内容。

      引用方式:&实体名称;

      参数实体则是在DTD 文档中自身使用

      语法格式:<!ELEMENT % 实体名称 “实体内容” >

      引用方式 :%实体名称

    <!ENTITY % TAG_NAMES "姓名 | EMAIL | 电话 | 地址">
        
        <!ELEMENT 个人信息 (% TAG_NAMES; | 生日)>
         <!ELEMENT 客户信息 (% TAG_NAMES; | 公司名)>

    五、JUnit 测试类

      JUnit 作为测试工具,可以通过注释的方法来代替写main方法,同时来测试相应的方法:再用JUbit 之前 先导入junit.jar 包。
       @Test :用来注释需要被测试的方法。

       @Before : 用来注释在运行@Test方法之前需要被运行的方法。 注意:如果有多个方法被@Before 注释,则从最后一个开始运行。

       @After : 则注释在运行@Test方法之后需要被运行的方法。 注意:如果有多个方法被@After 注释,则从第一个开始运行。

       @AfterClass :注释的方法在类释放时运行。

       @BeforeClass : 注释的方法在类加载时运行。

     1 import org.junit.After;
     2 import org.junit.AfterClass;
     3 import org.junit.Before;
     4 import org.junit.BeforeClass;
     5 import org.junit.Test;
     6 
     7  
     8 public class JUnitDemo {
     9     @Test
    10     public void test_1() {
    11         System.out.println("Hello JUnit!");
    12     }
    13     @Before
    14     public void before(){
    15         System.out.println("Before");
    16     } 
    17     @AfterClass
    18     public static void afterClass(){
    19         System.out.println("AfterClass");
    20     } 
    21     @After
    22     public void after(){
    23         System.out.println("After");
    24     } 
    25     @BeforeClass
    26     public static void beforeClass(){
    27         System.out.println("BeforeClass");
    28     }
    29 }

      

    六、JAXP进行DOM解析

             XML 的两种解析方式:DOM 解析和SAX 解析。

             DOM (Document  Object  Model ,文档对象模式 ) 解析,原理DOM解析器在解析XML文档时,会把文档中的所有元素(documentelementattributecharacter),按照其出现的层次关系,解析成一个个Node对象(节点)

       在dom中,节点之间关系如下:

        1、  位于一个节点之上的节点是该节点的父节点(parent)

        2、    一个节点之下的节点是该节点的子节点(children)

        3、  同一层次,具有相同父节点的节点是兄弟节点(sibling)

        4、    一个节点的下一个层次的节点集合是节点后代(descendant)

        5、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)

        Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后, 就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。

        Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了。

        练习:

         1.读取节点的文本内容
         2.读取属性值
         3.添加节点
         4.删除节点
         5.更新节点
         6.打印所有元素节点的名称.

      1 package cn.itheima.xml.day01;
      2 
      3 import javax.xml.parsers.DocumentBuilderFactory;
      4 import javax.xml.transform.TransformerFactory;
      5 import javax.xml.transform.dom.DOMSource;
      6 import javax.xml.transform.stream.StreamResult;
      7 
      8 import org.junit.After;
      9 import org.junit.Before;
     10 import org.junit.Test;
     11 import org.w3c.dom.Document;
     12 import org.w3c.dom.Element;
     13 import org.w3c.dom.NamedNodeMap;
     14 import org.w3c.dom.Node;
     15 import org.w3c.dom.NodeList;
     16 
     17 public class DOMTest {
     18 /*     
     19     1.读取节点的文本内容
     20     2.读取属性值
     21     3.添加节点
     22     4.删除节点
     23     5.更新节点
     24     6.打印所有元素节点的名称. 
     25  */
     26     /*
     27      * DOM解析器在解析XML文档时,会把文档中的所有元素(documentelementattributecharacter),按照其出现的层次关系,
     28      * 解析成一个个Node对象(节点)。 
     29      * 
     30      * Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,
     31      * 就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。
     32      */
     33     
     34     //1、读取节点的文本内容
     35     private Document doc = null ;  
     36     @Test
     37     public void readContent() {
     38         //获得标签名为"名字" 的 NodeList ;
     39         NodeList lists = doc.getElementsByTagName("名字") ; 
     40         //获得节点的文本类容
     41         for (int i = 0; i < lists.getLength(); i++) {
     42             System.out.println(lists.item(i).getTextContent());
     43         }
     44     }
     45     //2、读取属性值 
     46     @Test 
     47     public void getAttr() {
     48         //获取元素“书”的NodeList 
     49         NodeList lists = doc.getElementsByTagName("书") ;  
     50         //通过遍历lists ,获取每个节点中的属性值
     51         for (int i = 0; i < lists.getLength(); i++) { 
     52              NamedNodeMap attributes = lists.item(i).getAttributes();
     53              for (int j = 0; j < attributes.getLength(); j++) {
     54                  System.out.println(attributes.item(j).getTextContent());                
     55             }
     56         }
     57     }
     58     //3.添加节点
     59     //在“书”标签下添加一个<出版日期>的元素
     60     @Test
     61     public void addNode() throws Exception{
     62         //创建一个<出版日期> 添加到内存中
     63         Element element = doc.createElement("出版日期") ;
     64         //设置该标签的的文本值
     65         element.setTextContent("2007年");
     66         //通过Node 类中的 appendChild 方法将<出版日期>添加到节点的子节点列表的末尾
     67         NodeList lists = doc.getElementsByTagName("书");
     68         
     69         //问题:为什么只在第二个"书" 标签添加了该子节点。
     70         //而且如果存在<出版日期> 子节点,为什么添加之后有两个该节点。
     71         /*
     72             Node appendChild(Node newChild) throws DOMException
     73                          将节点 newChild 添加到此节点的子节点列表的末尾。如果 newChild 已经存在于树中,则首先移除它。
     74          */
     75         for (int i = 0 ; i < lists.getLength() ; i ++) {
     76             System.out.println(lists.item(i).getNodeName());
     77             lists.item(i).appendChild(element) ;  
     78         }
     79         updateXML() ; 
     80     }
     81     
     82     //如何将修改后的DOC写到XML中?
     83     public void updateXML() throws Exception {
     84         /*
     85          * javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出
     86          * Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
     87          * > javax.xml.transform.dom.DOMSource 类来关联要转换的document对象, 
     88          * > javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。 
     89          */
     90         
     91         //创建TransformFactory 对象:
     92         TransformerFactory.newInstance()
     93         .newTransformer()
     94         .transform(new DOMSource(doc), new StreamResult("src/cn/itheima/xml/day01/book.xml")); 
     95     }
     96     
     97     //4.删除节点
     98     //删除“出版日期”节点。
     99     @Test
    100     public void removeNode() throws Exception {
    101         //获取 "出版日期" 的节点
    102         Node node = doc.getElementsByTagName("出版日期").item(0) ;
    103         
    104         //获取 node 节点的父节点。
    105         //通过父节点删除"出版日期"节点
    106         node.getParentNode().removeChild(node) ; 
    107         updateXML() ;
    108     }
    109     
    110     //5.更新节点
    111     //将 "笑傲江湖" 的“价格”修改为 50.00  
    112     /*
    113      * 1、获取“名字”的NodeList , 然后遍历 值为“笑傲江湖” 的节点。
    114      * 2、获取“笑傲江湖”节点的兄弟节点。
    115      */
    116     @Test
    117     public void updateNode() throws Exception{
    118         //获取“笑傲江湖”的节点
    119         NodeList nodeList = doc.getElementsByTagName("名字"); 
    120         for (int i = 0; i < nodeList.getLength(); i++) {
    121 //            System.out.println(nodeList.item(i).getTextContent());
    122             if ( nodeList.item(i).getTextContent().equals("笑傲江湖")) {
    123                 NodeList childNodes = nodeList.item(i).getParentNode().getChildNodes(); 
    124                 for (int j = 0; j < childNodes.getLength(); j++) {
    125                     if (childNodes.item(j).getNodeName().equals("价格")) {
    126                         childNodes.item(j).setTextContent("50.00") ; 
    127                         break ;
    128                     }
    129                 } 
    130             }
    131         }
    132         //通过获取 其父节点然后通过父节点获取到“价格”节点,修改其节点的值
    133         /*NodeList lists = node.getParentNode().getChildNodes() ;
    134         for(int i = 0 ; i < lists.getLength() ; i++) {
    135             if( lists.item(i).getNodeName().equals("价格") ) {
    136                 lists.item(i).setTextContent("50.00"); 
    137                 break ;
    138             }
    139         }*/
    140         updateXML() ;
    141     }
    142     //6.打印所有元素节点的名称. 
    143     @Test
    144     public void printNode(){
    145         treeWeek(doc) ;
    146     }
    147     public void treeWeek(Node node) { 
    148         if(Node.ELEMENT_NODE == node.getNodeType()){ 
    149             System.out.println(node.getNodeName()); 
    150         } 
    151         NodeList nl = node.getChildNodes();
    152         for (int i = 0; i < nl.getLength(); i++) {
    153             Node item = nl.item(i);
    154             treeWeek(item);
    155         }
    156     }
    157     @Before 
    158     public void getDOM() throws Exception{
    159         /*
    160          * 1、获得DocumentBuilderFactory 对象。
    161          * 2、通过DocumentBuilderFactory 对象创建 DocumentBuilder 对象(DOM 解析器对象)。
    162          * 3、通过DocumentBuilder 对象解析XML文件,进而可以利用DOM特性对整个XML文档进行操作了。
    163          */
    164         doc = DocumentBuilderFactory.newInstance()
    165                                     .newDocumentBuilder()
    166                                     .parse("src/cn/itheima/xml/day01/book.xml") ;
    167     } 
    168     @After
    169     public void setDOM() {
    170         doc = null ;
    171     }
    172 }

       总结:

             DOM 解析 的优点是增删改方便,

             缺点,如果要解析的XML 文档过大,就会导致内存溢出(Out Of Memory , OOM),因为DOM解析需要将XML 文档内容全部加载到内存中再解析。

       

      

    七、JAXP进行SAX解析

    l  SAX (Simple API for XML ) 解析:SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才对文档进行操作。

    l  SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:

    l  解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。

    l  解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。

    l  事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。

    SAX解析步骤:

    1、使用SAXParserFactory创建SAX解析工厂

    2、通过SAX解析工厂得到解析器对象                  

    3、通过解析器对象得到一个XML的读取器

    4、设置读取器的事件处理器               

    5、解析xml文件

    package cn.itheima.xml.day01;
    
    import java.io.IOException;
    
    import javax.xml.parsers.SAXParserFactory;
    
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.XMLReader;
    import org.xml.sax.helpers.DefaultHandler;
    
    /*
     * SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才对文档进行操作。
     * 
     * SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
     * 解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
     * 
     * 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分(startDocument,startElement,character,endElement,endDocument),
     * 都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,
     * 会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
     * 
     * 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,
     * 就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
     * javax.xml.parsers.SAXParserFactory 
     * 
     */
    
    /*
    SAX 解析练习.
    1.读取节点的文本内容
    2.读取属性值
    3.添加节点
    4.删除节点
    5.更新节点
    6.打印所有元素节点的名称.
    
    思路:
    1、使用SAXParserFactory创建SAX解析工厂
    2、通过SAX解析工厂得到解析器对象        
    3、通过解析器对象得到一个XML的读取器
    4、设置读取器的事件处理器        
    5、解析xml文件
     */
    public class SAXTest {
        private XMLReader reader = null ;
        //打印出解析出的XML所有内容
        @Test
        public void printTest() throws IOException, SAXException {
            //设置读取器的事件处理器:
            reader.setContentHandler(new MyHandler()) ; 
            reader.parse("src/cn/itheima/xml/day01/book.xml") ;
        }
        
        //1.读取节点的文本内容
        /*
         * 读取节点名字为“名字”的文本内容
         */
        @Test 
        public void getTextContent() throws IOException, SAXException {
            reader.setContentHandler(new getTestContent()) ; 
            reader.parse("src/cn/itheima/xml/day01/book.xml") ;
        }
        //2.读取属性值
        /*
         * 读取节点名字为"书" 的属性值
         */
        @Test
        public void getAttributeName() throws IOException, SAXException {
            reader.setContentHandler(new getAttribute()) ; 
            reader.parse("src/cn/itheima/xml/day01/book.xml") ;
        }
        
        // 在测试之前获得一个XML读取器:
        @Before
        public void getReader() throws Exception {
    /*        
              1、使用SAXParserFactory创建SAX解析工厂
            2、通过SAX解析工厂得到解析器对象        
            3、通过解析器对象得到一个XML的读取器
    */        
            reader = SAXParserFactory.newInstance()
                                      .newSAXParser()
                                      .getXMLReader() ; 
        }
        //测试完重置reader = null
        @After
        public void setReader() {
            reader = null ;
        }
    }
    class getAttribute extends DefaultHandler { 
        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
            if ("书".equals(qName)) { 
                for (int i = 0; i < attributes.getLength(); i++) {
                    System.out.println(attributes.getValue(i)); 
                }
            }
        }
        
    }
    class getTestContent extends DefaultHandler{
        private boolean flag = false ; 
        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
            if ("名字".equals(qName)) {
                flag = true ; 
            }
        }
        
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            if (flag){
                System.out.println("文本类容:"+new String(ch,start,length));
                flag = false ; 
            }
        }
        
    }
    //编写事件处理器:
    /*    继承org.xml.sax.helpers.DefaultHandler
     *     DefaultHandler 类:
     *     SAX2 事件处理程序的默认基类。应用程序编写者可以在他们仅需实现部分接口时扩展此类;
     *  类似于ContentHandler 接口的适配器(adapter) ;
     */
    class MyHandler extends DefaultHandler {
    
        //在此类中重写我们需要的几个方法:
        @Override
        public void startDocument() throws SAXException {
            System.out.println("XML文件开始解析:");
        }
    
        @Override
        public void endDocument() throws SAXException {
            System.out.println("XML文件解析结束:");
        }
    
        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
            System.out.println("元素标签开始:"+ qName);
        }
    
        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            System.out.println("元素标签结束:" + qName);
        }
    
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            System.out.println("文本类容:"+new String(ch,start,length));
        }
        
    }

      

      总结:优点查找非常快,但是没DOM 解析 方法那样直观明白。  

      

    八、Dom4J简介、进行解析

      Dom4J 则是一层一层的解析XML文件,而且直观。

      1 package cn.itheima.xml.day01;
      2 
      3 import java.io.FileNotFoundException;
      4 import java.io.FileOutputStream;
      5 import java.io.UnsupportedEncodingException;
      6 import java.util.Iterator;
      7 import java.util.List;
      8 
      9 import org.dom4j.Attribute;
     10 import org.dom4j.Document;
     11 import org.dom4j.DocumentException;
     12 import org.dom4j.Element;
     13 import org.dom4j.io.OutputFormat;
     14 import org.dom4j.io.SAXReader;
     15 import org.dom4j.io.XMLWriter;
     16 import org.junit.After;
     17 import org.junit.Before;
     18 import org.junit.Test;
     19 
     20 /*
     21  * Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。
     22  */
     23 public class DOM4JTest {
     24     /*     
     25     1.读取节点的文本内容
     26     2.读取属性值
     27     3.添加节点
     28     4.删除节点
     29     5.更新节点
     30     6.打印所有元素节点的名称. 
     31  */
     32     private Document doc = null ;
     33     //1.读取节点的文本内容
     34     /*
     35      * 读取"书"节点下,“名字”节点的文本内容
     36      * DOM4J 思路:
     37      *     1.获取文档的根节点.
     38           Element root = document.getRootElement();
     39 
     40         2.取得某个节点的子节点.
     41         Element element=node.element(“书名");
     42 
     43         3.取得节点的文字
     44           String text=node.getText();
     45 
     46      */
     47     @Test 
     48     public void getNodeText() {
     49         //获得跟节点
     50         Element root = doc.getRootElement() ; 
     51         //通过跟节点获取到子节点 
     52         List<Element> lists = root.elements() ;
     53         for (Element ele : lists) {
     54             List<Element> elements = ele.elements() ;
     55             for (Element element : elements) {
     56                 if (element.getName().equals("名字"))
     57                     System.out.println(element.getText());
     58             }
     59         }
     60     } 
     61     //2.读取属性值
     62     @Test
     63     public void getAttribute () {
     64         Element root = doc.getRootElement() ; 
     65         //通过跟节点获取到子节点 
     66         List<Element> lists = root.elements() ;
     67         for(Element ele : lists) {
     68             List<Attribute> attributes = ele.attributes();
     69             for (Attribute attribute : attributes) {
     70                 System.out.println(attribute.getText());                
     71             }
     72         }
     73     }
     74     //3.添加节点
     75     /*
     76      * 在“书”节点下添加“出版日期”节点。
     77      */
     78     @Test
     79     public void addNode() throws Exception {
     80         Element root = doc.getRootElement() ;
     81         for (Iterator<Element> it = root.elementIterator(); it.hasNext() ;) {
     82             it.next().addElement("出版日期")
     83                      .setText("2007年") ;
     84         }
     85         //写到XML文件中去。
     86         writeToXML() ;
     87     }
     88     //4.删除节点
     89     /*
     90      * 删除“书”节点下,“名字”为“笑傲江湖”的“出版日期”的节点。
     91      * 思路:
     92      * 1、获取根元素。
     93      * 2、通过根元素获取其子元素,。
     94      * 3、遍历其子元素,获取子元素的"名字"元素。
     95      * 4、如果"名字"元素的值符合条件。
     96      * 5、则删除其兄弟元素"出版日期" 。
     97      */
     98     @Test
     99     public void removeNode() throws Exception{
    100         Element root = doc.getRootElement() ;
    101         //
    102         for (Iterator<Element> it = root.elementIterator(); it.hasNext() ;) {
    103             Element element = it.next() ;
    104             if (element.element("名字").getText().equals("笑傲江湖"))
    105                 element.remove(element.element("出版日期")) ;
    106         }
    107         writeToXML() ;
    108     }
    109     public void writeToXML() throws Exception{
    110         
    111         //在写入XML文件时,要设置写入的编码格式:utf-8
    112         OutputFormat format = OutputFormat.createPrettyPrint();
    113         format.setEncoding("utf-8") ;
    114         //最好不要用 FileWriter 写入,因为,FileWriter 写入时默认为系统设定的编码!
    115         XMLWriter writer = new XMLWriter(
    116                 new FileOutputStream("src/cn/itheima/xml/day01/book.xml"),format );
    117         writer.write( doc );
    118         writer.close();
    119     }
    120     @Before
    121     public void getDoc() throws Exception {
    122         doc = new SAXReader().read( "src/cn/itheima/xml/day01/book.xml");
    123     }
    124     @After
    125     public void setDoc() {
    126         doc = null ;
    127     }
    128 }

    九、XML约束之schema

    l  XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd。

    l  一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档

    l  和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为Schema。

    l  编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档中编写的元素来自哪里,被谁约束。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!-- 
     3     在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,
     4     名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标识符)表示
     5     
     6     名称空间:
     7     targetNamespace="http://jbelial.cnblogs.com"
     8     URL:http://jbelial.cnblogs.com 根本没有指向任何文件,只是一个分配的名字。
     9     
    10     elementFormDefault="qualified"
    11     
    12     elementFormDefault元素用于指定,
    13     该schema文档中声明的根元素及其所有子元素都属于targetNamespace所指定的名称空间。
    14     
    15     -->
    16 <schema  xmlns="http://www.w3.org/2001/XMLSchema" 
    17         targetNamespace="http://jbelial.cnblogs.com"
    18         xmlns:tns="http://www.example.org/NewXMLSchema" 
    19         elementFormDefault="qualified">
    20     <!-- 规定根元素 -->
    21     <element name='书架'>
    22         <!-- 根元素下存放复杂数据类型 --> 
    23         <complexType>
    24             <!-- 根元素下的元素的排列方式,和数目为"未绑定" -->
    25             <sequence maxOccurs='unbounded'>
    26                 <element name='书'>
    27                     <complexType>
    28                         <sequence>
    29                         <!-- 约束:元素的名字,和接收类型: -->
    30                             <element name="名字" type="string" /> 
    31                             <element name="作者" type="string" /> 
    32                             <element name="价格" type="string" /> 
    33                         </sequence>
    34                     </complexType>
    35                 </element>
    36             </sequence>
    37         </complexType>
    38     </element> 
    39  </schema>

    在用Schema 约束XML 文档时,要注意一下问题:

        a)你要创建的xml文档中的根标签是什么?

         第一个出现的 <xs:element name='书架' > 就是根标签 

        b) 思考: 你使用这个根标签它来自哪个名称空间.

          在schema约束文档中的 targetNamespace="http://jbelial.cnblogs.com" 就是用来说明所有跟标签绑定在哪个目标名称空间上. 

        c) 思考: 你要引用 schema文档它与目前名称空间的对应关系?

            需要在xml文档中添加  xsi:schemaLocation="{namespace} {location}"

            {namespace} 就是 : http://jbelial.cnblogs.com

            {location}  : 引用的schema文档在哪里

        d) 固定的写法:

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      

    <?xml version="1.0" encoding="UTF-8"?>
            
    <p:书架 xmlns:p = "http://jbelial.cnblogs.com"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://jbelial.cnblogs.com 
                                NewXMLSchema.xsd">
        <p:>
            <p:名字>射雕英雄传</p:名字>
            <p:作者>金庸</p:作者>
            <p:价格>100.00</p:价格>
        </p:书> 
    </p:书架>
    
        

      总结:

      XML Schema VS DTD

      •XML 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。 


      
      
      
      
      
      
      
      
      
     
     
     

     

      

  • 相关阅读:
    C++11多线程
    C++单例模式
    从五大结构体,带你掌握鸿蒙轻内核动态内存Dynamic Memory
    云小课 | 云硬盘不用了如何处理?
    Kafka 源码解析:Server 端的运行过程
    带你掌握4种Python 排序算法
    面试官问我:如何减少客户对交付成果的质疑
    如何基于MindSpore实现万亿级参数模型算法?
    Go 接口类型
    Go 结构体
  • 原文地址:https://www.cnblogs.com/jbelial/p/3159127.html
Copyright © 2011-2022 走看看