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文檔時,會把文檔中的所有元素(document\element\attribute\character),按照其出現的層次關系,解析成一個個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文檔時,會把文檔中的所有元素(document\element\attribute\character),按照其出現的層次關系,
 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。 

 

 

 

 

 

 


  
  
  
  
  
  
  
  
  
 
 
 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM