XML解析的深度解讀


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

 

XML是指可擴展標記語言(eXtensible MarkupLanguage),它是一種標記語言。它被設計的宗旨是描述數據(XML),而非顯示數據(HTML)。

 

目前遵循的是W3C組織於2000年發布的XML1.0規范

 

應用場景:

1、描述數據

2、作為配置文件存在

二、XML的基本語法

 

 

1、文檔聲明:很重要

 

在編寫XML文檔時,需要先使用文檔聲明來聲明XML文檔。且必須出現在文檔的第一行。

作用:告知解析器,我是一個XML文檔。

 

最簡單的聲明語法:

<?xml version="1.0"?>     中間不要加空格,后面加?號

當我們寫好的一個xml文件寫入內存的時候會轉換為二進制保存,這個時候會查碼表,記事本保存的時候是gbk,而保存的時候默認查碼表時用的是utf-8,

這個時候我們就可以用encoding屬性:默認是UTF-8    <?xml version="1.0" encoding="GBK"?>,這樣就可以解決亂碼等問題。

standlone屬性:該xml文件是否獨立存在。

2、元素(標簽)

XML語法非常嚴格。不能夠省略結束標簽。

一個XML文檔必須有且僅有一個根標簽

XML中不會忽略主體內容中出現的空格和換行

元素(標簽)的名稱可以包含字母、數字、減號、下划線和英文句點,但必須遵守下面的一些規范:

l  嚴格區分大小寫;<P> <p>

l  只能以字母或下划線開頭;abc _abc

l  不能以xml(或XML、Xml等)開頭----W3C保留日后使用;

l  名稱字符之間不能有空格或制表符;ab

l  名稱字符之間不能使用冒號; (有特殊用途)   

 

3、元素的屬性

屬性值一定要用引號(單引號或雙引號)引起來

 元素中屬性不允許重復

4、注釋

XML中的注釋語法為:<!--這是注釋-->

XML聲明之前不能有注釋       不允許第一行寫注釋(不同於java)

5、CDATA區

Character Data:字符數據。

語法:

<![CDATA[

內容

]]>

作用:

被CDATA包圍的內容,都是普通的文本字符串。

 

6、特殊字符

特殊字符       替代符號

&                    &amp

<                  &lt

>                  &gt

"                    &quot

'                     &apos

7、處理指令(PI:ProcessingInstruction)(了解)

XML聲明就是一種處理指令

處理指令:<?指令名稱 屬性?>

[java]  view plain  copy
 
  1. <?xml version="1.0" encoding="GBK"?>  
  2. <?xml-stylesheet type="text/css" href="main.css"?>  
  3. <world>  
  4.     <chinese>中國</chinese>  
  5.     <america>美國</america>  
  6.     <japan>小日本</japan>  
  7. </world>  

 

 

三、XML的約束

 

XML可以自定義。如果作為配置文件。

 

格式良好的XML文檔:遵循XML語法的。

有效的XML文檔:遵守約束的XML文檔。

有效的XML文檔必定是格式良好的,但良好的不一定是有效的。

 

1、DTD約束:(能看懂DTD即可)

a、DTD(Document Type Definition):文檔類型定義

作用:約束XML的書寫規范

 

注意:dtd可以寫在單獨的文件中,擴展名是dtd,且必須使用UTF-8編碼進行保存。

 

b、XML文檔中如何導入DTD約束文檔(XML外部)

l  dtd文檔在本地:

<!DOCTYPE 根元素 SYSTEM "dtd文件的路徑">

l  dtd文檔在網絡上:

<!DOCTYPE 根元素 PUBLIC "dtd名稱" "DTD文檔的URL鏈接地址">

 

c、了解:也可以把DTD的內容直接寫在XML文檔內部。

寫在XML文檔內部,dtd沒有編碼要求。(了解)

 

 

[java]  view plain  copy
 
  1. <?xml version="1.0" encoding="GBK"?>  
  2. <!DOCTYPE 書架 [  
  3.     <!ELEMENT 書架 (書+)>  
  4.     <!ELEMENT 書 (書名,作者,售價)>                
  5.     <!ELEMENT 書名 (#PCDATA)>  
  6.     <!ELEMENT 作者 (#PCDATA)>  
  7.     <!ELEMENT 售價 (#PCDATA)>  
  8.     <!ATTLIST 書  
  9.         ISBN ID #REQUIRED  
  10.         COMMENT CDATA #IMPLIED   
  11.         出版社 CDATA "指令匯公司"  
  12.         >  
  13.     <!ENTITY copyright "指令匯公司">  
  14. ]>  
  15. <書架>  
  16.     <書 ISBN="a" COMMENT="ddd" 出版社="指令匯公司">  
  17.         <書名>Java就業培訓教程</書名>  
  18.         <作者>&copyright;</作者>  
  19.         <售價>39.00元</售價>  
  20.     </書>    
  21.     <書  ISBN="b">  
  22.         <書名>JavaScript網頁開發</書名>  
  23.         <作者>張孝祥</作者>  
  24.         <售價>28.00元</售價>  
  25.     </書>  
  26. </書架>  


練習:

 

 

[java]  view plain  copy
 
  1. <?xml version="1.0" encoding="GBK"?>  
  2. <!DOCTYPE TVSCHEDULE [  
  3.     <!ELEMENT TVSCHEDULE (CHANNEL+)>  
  4.     <!ELEMENT CHANNEL (BANNER,DAY+)>  
  5.     <!ELEMENT BANNER (#PCDATA)>  
  6.     <!ELEMENT DAY (DATE,(HOLIDAY|PROGRAMSLOT+)+)>  
  7.     <!ELEMENT HOLIDAY (#PCDATA)>  
  8.     <!ELEMENT DATE (#PCDATA)>  
  9.     <!ELEMENT PROGRAMSLOT (TIME,TITLE,DESCRIPTION?)>  
  10.     <!ELEMENT TIME (#PCDATA)>  
  11.     <!ELEMENT TITLE (#PCDATA)>   
  12.     <!ELEMENT DESCRIPTION (#PCDATA)>  
  13.       
  14.     <!ATTLIST TVSCHEDULE NAME CDATA #REQUIRED>  
  15.     <!ATTLIST CHANNEL CHAN CDATA #REQUIRED>  
  16.     <!ATTLIST PROGRAMSLOT VTR CDATA #IMPLIED>  
  17.     <!ATTLIST TITLE RATING CDATA #IMPLIED>  
  18.     <!ATTLIST TITLE LANGUAGE CDATA #IMPLIED>  
  19. ]>  
  20.   
  21. <TVSCHEDULE NAME="NN">  
  22.      <CHANNEL  CHAN="CC">  
  23.          <BANNER>AAA</BANNER>  
  24.          <DAY>  
  25.             <DATE>2015</DATE>  
  26.             <PROGRAMSLOT>  
  27.                 <TIME>ee</TIME>  
  28.                 <TITLE>bb</TITLE>  
  29.                 <DESCRIPTION>cc</DESCRIPTION>  
  30.             </PROGRAMSLOT>      
  31.          </DAY>  
  32.     </CHANNEL>       
  33. </TVSCHEDULE>  



 

 

2、Schema約束(新,有替換DTD的趨勢)

 

四、利用Java代碼解析XML文檔

1、解析方式

l  DOM:Document Object Model,文檔對象模型。這種方式是W3C推薦的處理XML的一種標准方式。

缺點:必須讀取整個XML文檔,才能構建DOM模型,如果XML文檔過大,造成資源的浪費。

優點:適合對XML中的數據進行操作(CRUD)。

l  SAX:Simple API for XML。這種方式不是官方標准,屬於開源社區XML-DEV,幾乎所有的XML解析器都支持它。

 

2、解析工具

JAXP:

DOM或SAX方式進行解析XML。API在JDK之中。

Dom4J:(推薦)

是開源組織推出的解析開發包。(牛,大家都在用,包括SUN公司的一些技術的實現都在用)

五、JAXP進行DOM方式解析XML基本練習

1、JAXP簡介:

開發包:(JDK中)

DOM:W3C。org.w3c.dom.*   DOM規范。(接口/抽象類)

SAX:開源組織。org.xml.sax.*  SAX規范。(接口/抽象類)

JAXP:javax.xml.* 

2、利用JAXP進行DOM方式解析

[java]  view plain  copy
 
  1. //JAXP進行DOM方式解析的基本操作  
  2. public class JaxpDemo1 {  
  3.   
  4.     public static void main(String[] args) throws Exception {  
  5.         //得到解析器  
  6.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  7.         DocumentBuilder builder = factory.newDocumentBuilder();  
  8.         //通過解析器就可以得到代表整個內存中XML的Document對象  
  9.         Document document = builder.parse("src/book.xml");  
  10.         test8(document);  
  11.     }  
  12. //  1、得到某個具體的節點內容:  劉豐  
  13.     private static void test1(Document document){  
  14.         NodeList nl = document.getElementsByTagName("作者");  
  15.         Node authorNode = nl.item(0);  
  16.         System.out.println(authorNode.getTextContent());  
  17.     }  
  18. //  2、遍歷所有元素節點:打印元素的名稱  
  19.     private static void test2(Node node){  
  20.         //確定node的類型  
  21.         //方式一  
  22. //      if(node.getNodeType()==Node.ELEMENT_NODE){  
  23. //          //是元素  
  24. //      }  
  25.         //方式二  
  26.         if(node instanceof Element){  
  27.             //是元素  
  28.             Element e = (Element)node;  
  29.             System.out.println(e.getNodeName());//打印元素名稱  
  30.         }  
  31.         //判斷有沒有子節點  
  32.         NodeList nl = node.getChildNodes();  
  33.         for(int i=0;i<nl.getLength();i++){  
  34.             Node n = nl.item(i);  
  35.             test2(n);  
  36.         }  
  37.     }  
  38. //  3、修改某個元素節點的主體內容:<售價>39.00元</售價>--->10元  
  39.     private static void test3(Document document) throws Exception{  
  40.         //得到售價  
  41.         Node priceNode = document.getElementsByTagName("售價").item(0);  
  42.         priceNode.setTextContent("10元");  
  43.         //更新XML文件  
  44.         TransformerFactory tf = TransformerFactory.newInstance();  
  45.         Transformer t = tf.newTransformer();  
  46.         //構建輸入源:  
  47.         Source source = new DOMSource(document);  
  48.         //構建目標:  
  49.         Result result = new StreamResult("src/book.xml");  
  50.           
  51.         t.transform(source, result);  
  52.     }  
  53.       
  54. //  4、向指定元素節點中增加子元素節點:第一本書添加子元素 <出版社>黑馬程序員</出版社>  
  55.     private static void test4(Document document) throws Exception{  
  56.         //創建:<出版社>黑馬程序員</出版社>  
  57.         Element e = document.createElement("出版社");  
  58.         e.setTextContent("黑馬程序員");  
  59.         //得到書,把新節點掛上去  
  60.         Node bookNode = document.getElementsByTagName("書").item(0);  
  61.         bookNode.appendChild(e);  
  62.         //更新XML文件  
  63.         TransformerFactory tf = TransformerFactory.newInstance();  
  64.         Transformer t = tf.newTransformer();  
  65.         //構建輸入源:  
  66.         Source source = new DOMSource(document);  
  67.         //構建目標:  
  68.         Result result = new StreamResult("src/book.xml");  
  69.           
  70.         t.transform(source, result);  
  71.     }  
  72. //  5、向指定元素節點上增加同級元素節點:第一本書<售價>前面添加<批發價>30</批發價>  
  73.     private static void test5(Document document) throws Exception{  
  74.         //創建新節點  
  75.         Element e = document.createElement("批發價");  
  76.         e.setTextContent("30元");  
  77.         //找到<售價>  
  78.         Node priceNode = document.getElementsByTagName("售價").item(0);  
  79.         //父標簽:調用insertBefore(新節點,參考節點);  
  80.           
  81.         Node bookNode = priceNode.getParentNode();  
  82.         bookNode.insertBefore(e, priceNode);  
  83.         //更新XML文件  
  84.         TransformerFactory tf = TransformerFactory.newInstance();  
  85.         Transformer t = tf.newTransformer();  
  86.         //構建輸入源:  
  87.         Source source = new DOMSource(document);  
  88.         //構建目標:  
  89.         Result result = new StreamResult("src/book.xml");  
  90.           
  91.         t.transform(source, result);  
  92.     }  
  93. //  6、刪除指定元素節點:刪除批發價  
  94.     private static void test6(Document document) throws Exception{  
  95.         Node priceNode = document.getElementsByTagName("批發價").item(0);  
  96.         priceNode.getParentNode().removeChild(priceNode);  
  97.         //更新XML文件  
  98.         TransformerFactory tf = TransformerFactory.newInstance();  
  99.         Transformer t = tf.newTransformer();  
  100.         //構建輸入源:  
  101.         Source source = new DOMSource(document);  
  102.         //構建目標:  
  103.         Result result = new StreamResult("src/book.xml");  
  104.           
  105.         t.transform(source, result);  
  106.     }  
  107. //  7、操作XML文件屬性:書籍添加一個屬性:ISBN=“ABC”  
  108.     private static void test7(Document document) throws Exception{  
  109.         Node bookNode = document.getElementsByTagName("書").item(0);  
  110.         if(bookNode instanceof Element){  
  111.             Element e = (Element)bookNode;  
  112.             e.setAttribute("ISBN", "ABC");  
  113.         }  
  114.         //更新XML文件  
  115.         TransformerFactory tf = TransformerFactory.newInstance();  
  116.         Transformer t = tf.newTransformer();  
  117.         //構建輸入源:  
  118.         Source source = new DOMSource(document);  
  119.         //構建目標:  
  120.         Result result = new StreamResult("src/book.xml");  
  121.           
  122.         t.transform(source, result);  
  123.     }  
  124. //  8、操作XML文件屬性:獲取ISBN=“ABC”  
  125.     private static void test8(Document document) throws Exception{  
  126.         Node bookNode = document.getElementsByTagName("書").item(0);  
  127.         if(bookNode instanceof Element){  
  128.             Element e = (Element)bookNode;  
  129.             System.out.println(e.getAttribute("ISBN"));  
  130.         }  
  131.     }  
  132. }  


3、DOM小案例

a、建立xml文件

 

[java]  view plain  copy
 
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?><exam>  
  2.     <student examid="222" idcard="111">  
  3.         <name>劉豐</name>  
  4.         <location>湖北</location>  
  5.         <grade>100</grade>  
  6.     </student>  
  7. <student examid="dsf" idcard="2342"><name>dsf</name><location>435</location><grade>654.0</grade></student></exam>  



 

b、代碼要精細。要分層。

 

DAO:com.zhilinghui.dao

VIEW:com.zhilinghui.view

JavaBean:com.zhilinghui.domain(領域)

 

c、設計JavaBean

 

[java]  view plain  copy
 
  1. public class Student {  
  2.     private String idcard;  
  3.     private String examid;  
  4.     private String name;  
  5.     private String location;  
  6.     private float grade;  
  7.       
  8.     public Student(){}  
  9.       
  10.     public Student(String idcard, String examid, String name, String location,  
  11.             float grade) {  
  12.         super();  
  13.         this.idcard = idcard;  
  14.         this.examid = examid;  
  15.         this.name = name;  
  16.         this.location = location;  
  17.         this.grade = grade;  
  18.     }  
  19.     public String getIdcard() {  
  20.         return idcard;  
  21.     }  
  22.     public void setIdcard(String idcard) {  
  23.         this.idcard = idcard;  
  24.     }  
  25.     public String getExamid() {  
  26.         return examid;  
  27.     }  
  28.     public void setExamid(String examid) {  
  29.         this.examid = examid;  
  30.     }  
  31.     public String getName() {  
  32.         return name;  
  33.     }  
  34.     public void setName(String name) {  
  35.         this.name = name;  
  36.     }  
  37.     public String getLocation() {  
  38.         return location;  
  39.     }  
  40.     public void setLocation(String location) {  
  41.         this.location = location;  
  42.     }  
  43.     public float getGrade() {  
  44.         return grade;  
  45.     }  
  46.     public void setGrade(float grade) {  
  47.         this.grade = grade;  
  48.     }  
  49.     @Override  
  50.     public String toString() {  
  51.         return "Student [idcard=" + idcard + ", examid=" + examid + ", name="  
  52.                 + name + ", location=" + location + ", grade=" + grade + "]";  
  53.     }  
  54.       
  55. }  



 

 

d、開發DAO

數據訪問對象

 

[java]  view plain  copy
 
  1. public class StudentDao {  
  2.     /** 
  3.      * 保存學生信息到XML文件中 
  4.      * @param student 封裝要保存的信息 
  5.      * @return 成功返回true,否則false 
  6.      * @throws Exception  
  7.      */  
  8.     public boolean save(Student student) throws Exception{  
  9.           
  10.         if(student==null)  
  11.             throw new IllegalArgumentException("學生參數不能為null");  
  12.           
  13.         boolean result = false;  
  14.         /* 
  15.          * <student idcard="111" examid="222"> 
  16.                 <name>劉豐</name> 
  17.                 <location>湖北</location> 
  18.                 <grade>100</grade> 
  19.             </student> 
  20.          */  
  21.           
  22.             //得到Document  
  23.             Document document = JaxpUtil.getDocument();  
  24.             //創建一個student元素:設置屬性  
  25.             Element studentE = document.createElement("student");//<student></student>  
  26.             studentE.setAttribute("idcard", student.getIdcard());  
  27.             studentE.setAttribute("examid", student.getExamid());//<student idcard="111" examid="222"></student>  
  28.             //創建name,location,grade元素,掛到student上  
  29.             Element nameE = document.createElement("name");  
  30.             nameE.setTextContent(student.getName());//<name>劉豐</name>  
  31.             Element locationE = document.createElement("location");  
  32.             locationE.setTextContent(student.getLocation());//<location>湖北</location>  
  33.             Element gradeE = document.createElement("grade");  
  34.             gradeE.setTextContent(student.getGrade()+"");//<grade>100</grade>  
  35.             studentE.appendChild(nameE);  
  36.             studentE.appendChild(locationE);  
  37.             studentE.appendChild(gradeE);  
  38.             //把student掛接到exam上  
  39.             Node examNode = document.getElementsByTagName("exam").item(0);  
  40.             examNode.appendChild(studentE);  
  41.             //寫到xml中  
  42.             JaxpUtil.wirte2xml(document);  
  43.             //更改result的取值為true  
  44.             result = true;  
  45.           
  46.         return result;  
  47.     }  
  48.     /** 
  49.      * 根據姓名刪除信息 
  50.      * @param name 
  51.      * @return  成功返回true,否則false 
  52.      */  
  53.     public boolean delete(String name){  
  54.         boolean result = false;  
  55.         try {  
  56.             Document document = JaxpUtil.getDocument();  
  57.             //得到所有的name元素  
  58.             NodeList nl = document.getElementsByTagName("name");  
  59.             //遍歷:比對文本內容是否和參數一樣  
  60.             for(int i=0;i<nl.getLength();i++){  
  61.                 if(nl.item(i).getTextContent().equals(name)){  
  62.                     //如果找到了一樣的:爺爺干掉爸爸  
  63.                     nl.item(i).getParentNode().getParentNode().removeChild(nl.item(i).getParentNode());  
  64.                     //寫回xml  
  65.                     JaxpUtil.wirte2xml(document);  
  66.                     break;  
  67.                 }  
  68.                   
  69.             }  
  70.             result = true;  
  71.         } catch (Exception e) {  
  72.             throw new RuntimeException(e);//異常轉譯  
  73.         }  
  74.         return result;  
  75.     }  
  76.     /** 
  77.      * 根據准考證號查詢學生信息 
  78.      * @param examid 
  79.      * @return 沒有返回null 
  80.      */  
  81.     public Student findByExamId(String examid){  
  82.         Student student = null;  
  83.         try {  
  84.             Document document = JaxpUtil.getDocument();  
  85.             //得到所有的student元素  
  86.             NodeList nl = document.getElementsByTagName("student");  
  87.             //遍歷:比對examid屬性  
  88.             for(int i=0;i<nl.getLength();i++){  
  89.                 Element e = (Element) nl.item(i);  
  90.                 if(e.getAttribute("examid").equals(examid)){  
  91.                     // 找到了:創建student對象,並設置相應的值  
  92.                     student = new Student();  
  93.                     student.setIdcard(e.getAttribute("idcard"));  
  94.                     student.setExamid(examid);  
  95.                     student.setName(e.getElementsByTagName("name").item(0).getTextContent());  
  96.                     student.setLocation(e.getElementsByTagName("location").item(0).getTextContent());  
  97.                     student.setGrade(Float.parseFloat(e.getElementsByTagName("grade").item(0).getTextContent()));  
  98.                     break;  
  99.                 }  
  100.             }  
  101.         } catch (Exception e) {  
  102.             throw new RuntimeException(e);//異常轉譯  
  103.         }  
  104.         return student;  
  105.     }  
  106. }  



 

e、測試DAO的功能

 

[java]  view plain  copy
 
  1. public class StudentDaoTest {  
  2.   
  3.     public static void main(String[] args) {  
  4.         StudentDao dao = new StudentDao();  
  5.           
  6. //      Student student = new Student();  
  7. //      student.setIdcard("333");  
  8. //        
  9. //      dao.save(student);  
  10.           
  11. //      Student s = dao.findByExamId("444");  
  12. //      System.out.println(s);  
  13.           
  14.         System.out.println(dao.delete("阿嬌"));  
  15.     }  
  16.   
  17. }  



 

f、開發界面

 

[java]  view plain  copy
 
  1. ublic class Main {  
  2.   
  3.     public static void main(String[] args) throws Exception {  
  4.         StudentDao dao = new StudentDao();  
  5.           
  6.         System.out.println("a、添加用戶\tb、查詢成績\tc、刪除用戶");  
  7.         System.out.println("請輸入操作類型:");  
  8.         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
  9.         String op = br.readLine();//讀取用戶輸入的a|b|c  
  10.         if("a".equals(op)){  
  11.             //添加  
  12.             System.out.println("請輸入學生姓名:");  
  13.             String name = br.readLine();  
  14.             System.out.println("請輸入學生准考證號:");  
  15.             String examid = br.readLine();  
  16.             System.out.println("請輸入學生身份證號:");  
  17.             String idcard = br.readLine();  
  18.             System.out.println("請輸入學生所在地:");  
  19.             String location = br.readLine();  
  20.             System.out.println("請輸入學生成績:");  
  21.             String grade = br.readLine();  
  22.               
  23.             //封裝數據  
  24.             Student student = new Student(idcard, examid, name, location, Float.parseFloat(grade));  
  25.             //調用dao  
  26.             boolean b = dao.save(student);  
  27.             if(b){  
  28.                 System.out.println("------添加成功------");  
  29.             }else{  
  30.                 System.out.println("------服務器忙------");  
  31.             }  
  32.         }else if("b".equals(op)){  
  33.             //查詢  
  34.             System.out.println("請輸入學生准考證號:");  
  35.             String examid = br.readLine();  
  36.             Student s = dao.findByExamId(examid);  
  37.             if(s==null)  
  38.                 System.out.println("------查無此人------");  
  39.             else  
  40.                 System.out.println(s);  
  41.         }else if("c".equals(op)){  
  42.             //刪除  
  43.             System.out.println("請輸入要刪除的學生姓名:");  
  44.             String name = br.readLine();  
  45.             boolean b = dao.delete(name);  
  46.             if(b){  
  47.                 System.out.println("------刪除成功------");  
  48.             }else{  
  49.                 System.out.println("------服務器忙------");  
  50.             }  
  51.         }else{  
  52.             System.out.println("你傻呀,輸錯了");  
  53.         }  
  54.     }  
  55.   
  56. }  

sax解析原理

在使用 DOM 解析 XML 文檔時,需要讀取整個 XML 文檔,在內存中構架代表整個 DOM 樹的Doucment對象,從而再對XML文檔進行操作。此種情況下,如果 XML 文檔特別大,就會消耗計算機的大量內存,並且容易導致內存溢出。

SAX解析允許在讀取文檔的時候,即對文檔進行處理,而不必等到整個文檔裝載完才會文檔進行操作。


SAX采用事件處理的方式解析XML文件,利用 SAX 解析 XML 文檔,涉及兩個部分:解析器和事件處理器: 解析器可以使用JAXP的API創建,創建出SAX解析器后,就可以指定解析器去解析某個XML文檔。 解析器采用SAX方式在解析某個XML文檔時,它只要解析到XML文檔的一個組成部分,都會去調用事件處理器的一個方法,解析器在調用事件處理器的方法時,會把當前解析到的xml文件內容作為方法的參數傳遞給事件處理器。 事件處理器由程序員編寫,程序員通過事件處理器中方法的參數,就可以很輕松地得到sax解析器解析到的數據,從而可以決定如何對數據進行處理

基本解析操作

    //1解析器
    SAXParser parse = SAXParserFactory.newInstance().newSAXParser();
    //2獲取xml讀取器
    XMLReader reader = parse.getXMLReader();
    //3注冊內容處理器
    reader.setContentHandler(new ContentHandler1());
    //4讀取xml文檔
    reader.parse("src/book.xml");

封裝讀取書

封裝到BOOK.java

public class sax3 {

//封裝讀取書
    public static void main(String[] args) throws Exception {

        SAXParser parse=SAXParserFactory.newInstance().newSAXParser();

        XMLReader reader=parse.getXMLReader();

        final List<Book> books=new ArrayList<Book>();
        reader.setContentHandler(new DefaultHandler(){

           private Book b=null;
           private String currentTagName=null;
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes) throws SAXException {

                if("書".equals(qName)){
                    b=new Book();
                }
                currentTagName=qName;
            }

            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                if("書".equals(qName)){
                    books.add(b);
                    b=null;
                }
                currentTagName=null;
            }
            @Override
            public void characters(char[] ch, int start, int length)
                    throws SAXException {
                if("書名".equals(currentTagName)){
                    b.setName(new String(ch,start,length));
                }
                if("作者".equals(currentTagName)){
                    b.setAuthor(new String(ch,start,length));
                }
                if("售價".equals(currentTagName)){
                    b.setPrice(new String(ch,start,length));
                }
            }
        });
        reader.parse("src/book.xml");

        for(Book book:books)
            System.out.println(book);
    }
}

dom4j解析原理

Dom4j是一個簡單、靈活的開放源代碼的庫。Dom4j是由早期開發JDOM的人分離出來而后獨立開發的。與JDOM不同的是,dom4j使用接口和抽象基類,雖然Dom4j的API相對要復雜一些,但它提供了比JDOM更好的靈活性。 Dom4j是一個非常優秀的Java XML API,具有性能優異、功能強大和極易使用的特點。現在很多軟件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。 使用Dom4j開發,需下載dom4j相應的jar文件。


1、基本練習 a、拷貝jar包: 把dom4j-1.6.1.jar加入到你的classpath中 b、基本操作

// 1、得到某個具體的節點內容:jinpingmei

@Test
public void test1() throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    List<Element> bookElements = root.elements();
//      Element bookName = (Element) bookElements.get(0).elements().get(0);
//      System.out.println(bookName.getText());
    System.out.println(bookElements.get(0).elementText("書名"));
}

// 2、遍歷所有元素節點:名稱

@Test
public void test2()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    treeWalk(root);
}
public void treeWalk(Element rootElement){//遞歸
    System.out.println(rootElement.getName());
    int nodeCount = rootElement.nodeCount();//子節點的數量
    for(int i=0;i<nodeCount;i++){
        Node node = rootElement.node(i);//得到一個子節點
        if(node instanceof Element){
            treeWalk((Element)node);
        }
    }
}

// 3、修改某個元素節點的主體內容:<售價>10元---20

@Test
public void test3()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    //得售價
    Element priceElement = root.element("書").element("售價");
    priceElement.setText("21元");
    //寫回XML文檔
//      OutputFormat format = OutputFormat.createCompactFormat();//去除空格回車換行,適合運行期間
    OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默認編碼是UTF-8
    XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
    writer.write(document);
    writer.close();
}

// 4、向指定元素節點中增加子元素節點:<出版社>黑馬程序員

@Test
public void test4()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    //得售價
    Element bookElement = root.element("書");
    //創建新元素
    Element publisherElement = DocumentHelper.createElement("出版社");
    publisherElement.setText("黑馬程序員");

    bookElement.add(publisherElement);
    //寫回XML文檔
//      OutputFormat format = OutputFormat.createCompactFormat();//去除空格回車換行,適合運行期間
    OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默認編碼是UTF-8
    XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
    writer.write(document);
    writer.close();
}

// 5、向指定元素節點上增加同級元素節點:<售價>21元 添加<批發價>

@Test
public void test5()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    //得售價
    Element bookElement = root.element("書");
    //創建新元素
    Element priceElement = DocumentHelper.createElement("批發價");
    priceElement.setText("30元");

    List<Element> bookChildren = bookElement.elements();//得到書的子元素
    bookChildren.add(2, priceElement);

    //寫回XML文檔
//      OutputFormat format = OutputFormat.createCompactFormat();//去除空格回車換行,適合運行期間
    OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默認編碼是UTF-8
    XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
    writer.write(document);
    writer.close();
}

// 6、刪除指定元素節點:批發價

@Test
public void test6()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    Element priceElement = root.element("書").element("批發價");

    priceElement.getParent().remove(priceElement);

    //寫回XML文檔
//      OutputFormat format = OutputFormat.createCompactFormat();//去除空格回車換行,適合運行期間
    OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默認編碼是UTF-8
    XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
    writer.write(document);
    writer.close();
}

// 7、操作XML文件屬性

@Test
public void test7()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    Element book = root.element("書");
    System.out.println(book.attributeValue("ISBN"));
}
@Test
public void test8()throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    //首先要得到根元素
    Element root = document.getRootElement();
    Element book = root.element("書");
    book.addAttribute("A", "B");
    //寫回XML文檔
//      OutputFormat format = OutputFormat.createCompactFormat();//去除空格回車換行,適合運行期間
    OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默認編碼是UTF-8
    XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
    writer.write(document);
    writer.close();
}

Xpath

XPath是一個努力為XSL轉換XSLT和XPointer [ ] [ ]之間共享一個共同的XPointer功能語法和語義的結果。它的主要目的是解決一個XML XML文檔部分[ ]。為了支持這一功能,還提供用於處理字符串的基本設施、數字和布爾值。XPath使用一個緊湊的、非XML語法方便使用在uri和XML屬性值的XPath。XPath操作基於XML文檔的邏輯結構,而不是其表面的語法。Xpath的名字來自其使用的符號在URL路徑通過一個XML文檔的層次結構導航。 除了用於定位,XPath還設計有一個真子集,可用於匹配(測試一個節點是否符合一個模式);使用XPath進行XSLT。

XPath模型的XML文檔的節點樹。有不同類型的節點,包括元素節點、屬性節點和文本節點。XPath定義了一個方法來計算每個節點類型字符串值。某些類型的節點也有名字。XPath完全支持XML命名空間的XML名稱] [。因此,一個節點的名稱被建模為一個地方的部分和一個可能的空命名空間URI;這就是所謂的擴展名。在[ 5數據模型]中詳細描述了數據模型。

@Test//Xpath
public void test11() throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    Node n = document.selectSingleNode("//書[1]/書名");
    System.out.println(n.getText());
}
@Test//Xpath:第一本書的ISBN的值
public void test12() throws Exception{
    SAXReader reader = new SAXReader();
    Document document = reader.read("src/book.xml");
    Node n = document.selectSingleNode("//書[1]");
    System.out.println(n.valueOf("@ISBN"));
}

xml約束之schema

XML Schema 也是一種用於定義和描述 XML 文檔結構與內容的模式語言,其出現是為了克服 DTD 的局限性

XML Schema 文件自身就是一個XML文件,但它的擴展名通常為.xsd。支持名稱空間。 一個XML Schema文檔通常稱之為模式文檔(約束文檔),遵循這個文檔書寫的xml文件稱之為實例文檔。

和XML文件一樣,一個XML Schema文檔也必須有一個根結點,但這個根結點的名稱為schema。

編寫了一個XML Schema約束文檔后,通常需要把這個文件中聲明的元素綁定到一個URI地址上,在XML Schema技術中有一個專業術語來描述這個過程,即把XML Schema文檔聲明的元素綁定到一個名稱空間上,以后XML文件就可以通過這個URI(即名稱空間)來告訴解析引擎,xml文檔中編寫的元素來自哪里,被誰約束。

學習目標:不需要我們編寫xsd 重點:根據xsd編寫出xml文檔。 難點:在xml中引入xsd約束

基本操作步驟:

a、根據xsd文件,找到根元素

<?xml version="1.0" encoding="UTF-8"?>
<書架>

</書架>

b、根元素來在哪個名稱空間 使用xmlns關鍵字來聲明名稱空間。

<?xml version="1.0" encoding="UTF-8"?>
<tf:書架 xmlns:tf="http://www.zhilinghui.com">

</tf:書架>

c、名稱空間和哪個xsd文件對應

<?xml version="1.0" encoding="UTF-8"?>
<tf:書架 xmlns:tf="http://www.zhilinghui.com"
    schemaLocation="http://www.zhilinghui.com book.xsd">

</tf:書架>

d、schemaLocation來自一個標准的名稱空間:固定寫法

<?xml version="1.0" encoding="UTF-8"?>
<tf:書架 xmlns:tf="http://www.zhilinghui.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.zhilinghui.com book.xsd">

</tf:書架>
==============================================================================================================================
DOM4J的另一種深度解讀:

DOM4J

 

    與利用DOM、SAX、JAXP機制來解析xml相比,DOM4J 表現更優秀,具有性能優異、功能強大和極端易用使用的特點,只要懂得DOM基本概念,就可以通過dom4j的api文檔來解析xml。dom4j是一套開源的api。實際項目中,往往選擇dom4j來作為解析xml的利器。

 

先來看看dom4j中對應XML的DOM樹建立的繼承關系

  

針對於XML標准定義,對應於圖2-1列出的內容,dom4j提供了以下實現:

  

同時,dom4j的NodeType枚舉實現了XML規范中定義的node類型。如此可以在遍歷xml文檔的時候通過常量來判斷節點類型了。

 

常用API

 

class org.dom4j.io.SAXReader

 

  • read  提供多種讀取xml文件的方式,返回一個Domcument對象

 

interface org.dom4j.Document

 

  • iterator  使用此法獲取node
  • getRootElement  獲取根節點

 

interface org.dom4j.Node

 

  • getName  獲取node名字,例如獲取根節點名稱為bookstore
  • getNodeType  獲取node類型常量值,例如獲取到bookstore類型為1——Element
  • getNodeTypeName  獲取node類型名稱,例如獲取到的bookstore類型名稱為Element

 

interface org.dom4j.Element

 

  • attributes  返回該元素的屬性列表
  • attributeValue  根據傳入的屬性名獲取屬性值
  • elementIterator  返回包含子元素的迭代器
  • elements  返回包含子元素的列表

 

interface org.dom4j.Attribute

 

  • getName  獲取屬性名
  • getValue  獲取屬性值

 

interface org.dom4j.Text

 

  • getText  獲取Text節點值

 

interface org.dom4j.CDATA

 

  • getText  獲取CDATA Section值

 

interface org.dom4j.Comment

 

  • getText  獲取注釋 

 

 

實例一:

復制代碼
  1 //先加入dom4j.jar包 
  2 import java.util.HashMap;
  3 import java.util.Iterator;
  4 import java.util.Map;
  5 
  6 import org.dom4j.Document;
  7 import org.dom4j.DocumentException;
  8 import org.dom4j.DocumentHelper;
  9 import org.dom4j.Element;
 10 
 11 /**   
 12 * @Title: TestDom4j.java
 13 * @Package 
 14 * @Description: 解析xml字符串
 15 * @author 無處不在
 16 * @date 2012-11-20 下午05:14:05
 17 * @version V1.0   
 18 */
 19 public class TestDom4j {
 20 
 21     public void readStringXml(String xml) {
 22         Document doc = null;
 23         try {
 24 
 25             // 讀取並解析XML文檔
 26             // SAXReader就是一個管道,用一個流的方式,把xml文件讀出來
 27             // 
 28             // SAXReader reader = new SAXReader(); //User.hbm.xml表示你要解析的xml文檔
 29             // Document document = reader.read(new File("User.hbm.xml"));
 30             // 下面的是通過解析xml字符串的
 31             doc = DocumentHelper.parseText(xml); // 將字符串轉為XML
 32 
 33             Element rootElt = doc.getRootElement(); // 獲取根節點
 34             System.out.println("根節點:" + rootElt.getName()); // 拿到根節點的名稱
 35 
 36             Iterator iter = rootElt.elementIterator("head"); // 獲取根節點下的子節點head
 37 
 38             // 遍歷head節點
 39             while (iter.hasNext()) {
 40 
 41                 Element recordEle = (Element) iter.next();
 42                 String title = recordEle.elementTextTrim("title"); // 拿到head節點下的子節點title值
 43                 System.out.println("title:" + title);
 44 
 45                 Iterator iters = recordEle.elementIterator("script"); // 獲取子節點head下的子節點script
 46 
 47                 // 遍歷Header節點下的Response節點
 48                 while (iters.hasNext()) {
 49 
 50                     Element itemEle = (Element) iters.next();
 51 
 52                     String username = itemEle.elementTextTrim("username"); // 拿到head下的子節點script下的字節點username的值
 53                     String password = itemEle.elementTextTrim("password");
 54 
 55                     System.out.println("username:" + username);
 56                     System.out.println("password:" + password);
 57                 }
 58             }
 59             Iterator iterss = rootElt.elementIterator("body"); ///獲取根節點下的子節點body
 60             // 遍歷body節點
 61             while (iterss.hasNext()) {
 62 
 63                 Element recordEless = (Element) iterss.next();
 64                 String result = recordEless.elementTextTrim("result"); // 拿到body節點下的子節點result值
 65                 System.out.println("result:" + result);
 66 
 67                 Iterator itersElIterator = recordEless.elementIterator("form"); // 獲取子節點body下的子節點form
 68                 // 遍歷Header節點下的Response節點
 69                 while (itersElIterator.hasNext()) {
 70 
 71                     Element itemEle = (Element) itersElIterator.next();
 72 
 73                     String banlce = itemEle.elementTextTrim("banlce"); // 拿到body下的子節點form下的字節點banlce的值
 74                     String subID = itemEle.elementTextTrim("subID");
 75 
 76                     System.out.println("banlce:" + banlce);
 77                     System.out.println("subID:" + subID);
 78                 }
 79             }
 80         } catch (DocumentException e) {
 81             e.printStackTrace();
 82 
 83         } catch (Exception e) {
 84             e.printStackTrace();
 85 
 86         }
 87     }
 88 
 89     /**
 90      * @description 將xml字符串轉換成map
 91      * @param xml
 92      * @return Map
 93      */
 94     public static Map readStringXmlOut(String xml) {
 95         Map map = new HashMap();
 96         Document doc = null;
 97         try {
 98             // 將字符串轉為XML
 99             doc = DocumentHelper.parseText(xml); 
100             // 獲取根節點
101             Element rootElt = doc.getRootElement(); 
102             // 拿到根節點的名稱
103             System.out.println("根節點:" + rootElt.getName()); 
104 
105             // 獲取根節點下的子節點head
106             Iterator iter = rootElt.elementIterator("head"); 
107             // 遍歷head節點
108             while (iter.hasNext()) {
109 
110                 Element recordEle = (Element) iter.next();
111                 // 拿到head節點下的子節點title值
112                 String title = recordEle.elementTextTrim("title"); 
113                 System.out.println("title:" + title);
114                 map.put("title", title);
115                 // 獲取子節點head下的子節點script
116                 Iterator iters = recordEle.elementIterator("script"); 
117                 // 遍歷Header節點下的Response節點
118                 while (iters.hasNext()) {
119                     Element itemEle = (Element) iters.next();
120                     // 拿到head下的子節點script下的字節點username的值
121                     String username = itemEle.elementTextTrim("username"); 
122                     String password = itemEle.elementTextTrim("password");
123 
124                     System.out.println("username:" + username);
125                     System.out.println("password:" + password);
126                     map.put("username", username);
127                     map.put("password", password);
128                 }
129             }
130 
131             //獲取根節點下的子節點body
132             Iterator iterss = rootElt.elementIterator("body"); 
133             // 遍歷body節點
134             while (iterss.hasNext()) {
135                 Element recordEless = (Element) iterss.next();
136                 // 拿到body節點下的子節點result值
137                 String result = recordEless.elementTextTrim("result"); 
138                 System.out.println("result:" + result);
139                 // 獲取子節點body下的子節點form
140                 Iterator itersElIterator = recordEless.elementIterator("form"); 
141                 // 遍歷Header節點下的Response節點
142                 while (itersElIterator.hasNext()) {
143                     Element itemEle = (Element) itersElIterator.next();
144                     // 拿到body下的子節點form下的字節點banlce的值
145                     String banlce = itemEle.elementTextTrim("banlce"); 
146                     String subID = itemEle.elementTextTrim("subID");
147 
148                     System.out.println("banlce:" + banlce);
149                     System.out.println("subID:" + subID);
150                     map.put("result", result);
151                     map.put("banlce", banlce);
152                     map.put("subID", subID);
153                 }
154             }
155         } catch (DocumentException e) {
156             e.printStackTrace();
157         } catch (Exception e) {
158             e.printStackTrace();
159         }
160         return map;
161     }
162 
163     public static void main(String[] args) {
164 
165         // 下面是需要解析的xml字符串例子
166         String xmlString = "<html>" + "<head>" + "<title>dom4j解析一個例子</title>"
167                 + "<script>" + "<username>yangrong</username>"
168                 + "<password>123456</password>" + "</script>" + "</head>"
169                 + "<body>" + "<result>0</result>" + "<form>"
170                 + "<banlce>1000</banlce>" + "<subID>36242519880716</subID>"
171                 + "</form>" + "</body>" + "</html>";
172 
173         /*
174          * Test2 test = new Test2(); test.readStringXml(xmlString);
175          */
176         Map map = readStringXmlOut(xmlString);
177         Iterator iters = map.keySet().iterator();
178         while (iters.hasNext()) {
179             String key = iters.next().toString(); // 拿到鍵
180             String val = map.get(key).toString(); // 拿到值
181             System.out.println(key + "=" + val);
182         }
183     }
184 
185 }
復制代碼

  

實例二:

復制代碼
 1 /**
 2  * 解析包含有DB連接信息的XML文件
 3  * 格式必須符合如下規范:
 4  * 1. 最多三級,每級的node名稱自定義;
 5  * 2. 二級節點支持節點屬性,屬性將被視作子節點;
 6  * 3. CDATA必須包含在節點中,不能單獨出現。
 7  *
 8  * 示例1——三級顯示:
 9  * <db-connections>
10  *         <connection>
11  *            <name>DBTest</name>
12  *            <jndi></jndi>
13  *            <url>
14  *                <![CDATA[jdbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=UTF8]]>
15  *             </url>
16  *            <driver>org.gjt.mm.mysql.Driver</driver>
17  *             <user>test</user>
18  *            <password>test2012</password>
19  *            <max-active>10</max-active>
20  *            <max-idle>10</max-idle>
21  *            <min-idle>2</min-idle>
22  *            <max-wait>10</max-wait>
23  *            <validation-query>SELECT 1+1</validation-query>
24  *         </connection>
25  * </db-connections>
26  *
27  * 示例2——節點屬性:
28  * <bookstore>
29  *         <book category="cooking">
30  *            <title lang="en">Everyday Italian</title>
31  *            <author>Giada De Laurentiis</author>
32  *            <year>2005</year>
33  *            <price>30.00</price>
34  *         </book>
35  *
36  *         <book category="children" title="Harry Potter" author="J K. Rowling" year="2005" price="$29.9"/>
37  * </bookstore>
38  *
39  * @param configFile
40  * @return
41  * @throws Exception
42  */
43 public static List<Map<String, String>> parseDBXML(String configFile) throws Exception {
44     List<Map<String, String>> dbConnections = new ArrayList<Map<String, String>>();
45     InputStream is = Parser.class.getResourceAsStream(configFile);
46     SAXReader saxReader = new SAXReader();
47     Document document = saxReader.read(is);
48     Element connections = document.getRootElement();
49 
50     Iterator<Element> rootIter = connections.elementIterator();
51     while (rootIter.hasNext()) {
52         Element connection = rootIter.next();
53         Iterator<Element> childIter = connection.elementIterator();
54         Map<String, String> connectionInfo = new HashMap<String, String>();
55         List<Attribute> attributes = connection.attributes();
56         for (int i = 0; i < attributes.size(); ++i) { // 添加節點屬性
57             connectionInfo.put(attributes.get(i).getName(), attributes.get(i).getValue());
58         }
59         while (childIter.hasNext()) { // 添加子節點
60             Element attr = childIter.next();
61             connectionInfo.put(attr.getName().trim(), attr.getText().trim());
62         }
63         dbConnections.add(connectionInfo);
64     }
65 
66     return dbConnections;
67 }
 


免責聲明!

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



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