XML解析方法分為兩種:DOM方式和SAX方式
DOM:Document Object Model,文檔對象模型。這種方式是W3C推薦處理XML的一種方式
SAX:Simple API for XML。該方式不是官方標准,屬於開源社區XML-DEV
XML解析開發包
JAXP:SUN公司推出的解析標准實現
Dom4J:開源組織推出的解析開發包
JDOM:同上
JAXP:(Java API for XML Processing)開發包是JavaSE的一部分,它由以下幾個包及其子包組成
org.w3c.dom:提供DOM方方式解析XML的標准接口
org.xml.sax:提供SAX方式解析XML的標准接口
javax.xml:提供了解析XML文檔的類
javax.xml.parsers包中,定義了幾個工廠類。我們可以通過調用這些工廠類,得到對XML文檔進行解析的DOM和SAX解析器對象。
DocumentBuilderFactory
SAXParersFactory
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
利用JAXP繼續DOM解析
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
javax.xml.parsers包中的DocumentBuilderFactory用於創建DOM模式的解析器對象,DocumentBuilderFactory是一個抽象工廠類,它不能直接實例化,但該類提供了一個newInstance()方法
,這個方法會根據本地默認安裝的解析器自動創建一個工廠對象並返回

DOM方式解析會讀取完整個XML文檔,在內存中構建代表整個DOM樹的Document對象,從而再對XML文檔進行操作:增、刪、改、查
如果文檔特別大,就會消耗計算機的大量內存,並且容易導致內存溢出。
獲得JAXP中的DOM解析器
--->調用DocumentBuilderFactory.newInstance()方法得到創建DOM解析器的工廠
--->調用工廠對象的newDocumentBuilder()方法得到DOM解析器對象
--->調用DOM解析器對象的parse()方法解析XML文檔,得到代表整個文檔的Document對象,進而可以利用DOM特性對整個XML文檔繼續操作。
1 /*固定寫法*/ 2 //得到解析工廠DocumentBuilderFactory 3 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 4 5 //得到解析器 6 DocumentBuilder builder = factory.newDocumentBuilder(); 7 8 //解析指定的XML文檔 9 Document document = builder.parse("src/book.xml");
DOM模型(document object model)
DOM解析器在解析XML文檔時,會把文檔中的所有元素,按照其出現的層次關系,解析成一個個Node對象節點
在dom中,節點之間的關系如下:
- 位於一個節點之上的節點是該節點的父節點(parent)
- 一個節點之下的節點是該節點的子節點(children)
- 在同一層次,具有相同父節點的節點是兄弟節點(sibling)
- 一個節點的下一個層次的節點集合是節點后代(descendant)
- 父、祖父節點以及所有位於節點的上面的,都是節點的祖先(ancestor)
節點的類型
Node對象提供了一系列常量來代表節點的類型,當開發人員獲得某個Node類型之后,就可以把Node節點轉換成相應的節點對象(Node的子類對象),以便調用其特有的方法
Node對象提供了相應的方法區獲取它的父節點或子節點。編程人員通過這些方法可以讀取整個XML文檔的內容、或添加、修改、刪除XML文檔的內容
如何更新XML文檔
- javax.xml.transform包中de Transformer類用於把代表XML文件的Document對象轉換為某種格式后進行輸出。例如把XML文件應用樣式表后轉成一個html文檔。利用這個對象
- 把Document對象又重新寫入到XML文件中
- Transformer通過transform方法完成轉換的操作,該方法接收一個源和一個目的地
- javax.xml.transform.dom.DOMSource類來關聯要轉換的Document對象
- 用javax.xml.transform.strem.StreamResult對象來表示數據的目的地
- Transformer對象提供TransformerFactory獲得
-
1 // 把內存中Documeng樹寫回XML文件中 2 TransformerFactory facotry = TransformerFactory.newInstance(); 3 //創建factory實例 4 Transformer ts = facotry.newTransformer(); 5 ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); 6 //將源寫入到目的中去
1 import javax.xml.parsers.DocumentBuilder; 2 import javax.xml.parsers.DocumentBuilderFactory; 3 import javax.xml.transform.Transformer; 4 import javax.xml.transform.TransformerFactory; 5 import javax.xml.transform.dom.DOMSource; 6 import javax.xml.transform.stream.StreamResult; 7 8 import org.w3c.dom.Document; 9 import org.w3c.dom.Element; 10 import org.w3c.dom.Node; 11 import org.w3c.dom.NodeList; 12 13 //利用Jaxp進行DOm方式解析 14 public class JaxpDomDemo { 15 16 public static void main(String[] args) throws Exception { 17 // 得到解析工廠DocumentBuilderFactory 18 //得到解析工廠DocumentBuilderFacetory 19 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 20 // 得到解析器DocumentBuilder 21 DocumentBuilder builder = factory.newDocumentBuilder(); 22 // 解析指定的XML文檔,得到代表內存DOM樹的Document對象 23 Document document = builder.parse("src/book.xml"); 24 test3(document); 25 } 26 27 // 1、得到某個具體的節點內容:打印第2本書的作者 28 public static void test1(Document document) { 29 // 根據標簽的名稱獲取所有的作者元素 30 NodeList nl = document.getElementsByTagName("作者");
//Nodelist getElementByTagName(Stirng tagname按文檔順序返回包含文檔中且具有給定標記名稱的所有Element的NodeList 31
// 按照索引取第2個作者元素 NodeList 有兩個主要的方法Node item(int index) 返回集合中的第index個項,如果index大於或等於此列表的索引則返回null
//int getLength()返回列表的節點數。有效子節點索引的范圍是0到length-1
32 Node node = nl.item(1); 33 // 打印該元素的文本 34 String text = node.getTextContent(); //node有許多操作方法 getTextContent()方法返回此節點及其后代的文本相關內容 35 System.out.println(text); 36 } 37 38 // 2、遍歷所有元素節點:打印元素的名稱 39 public static void test2(Node node) { 40 // 判斷當前節點是不是一個元素節點 41 if (node.getNodeType() == Node.ELEMENT_NODE) { 42 // 如果是:打印他的名稱 43 System.out.println(node.getNodeName()); 44 } 45 // 如果不是:找到他的孩子們 46 NodeList nl = node.getChildNodes(); //NodeList getChildNodes()包含此節點的NodeList。如果不存在,這是不包含節點的NodeList 47 int len = nl.getLength(); 48 for (int i = 0; i < len; i++) { 49 // 遍歷孩子們:遞歸 50 Node n = nl.item(i); 51 test2(n); 52 } 53 } 54 55 // 3、修改某個元素節點的主體內容:把第一本書的售價改為38.00元 56 public static void test3(Document document) throws Exception { 57 // 找到第一本書的售價 58 NodeList nl = document.getElementsByTagName("售價"); 59 // 設置其主體內容 60 Node node = nl.item(0); 61 node.setTextContent("39.00元"); 62 // 把內存中Documeng樹寫回XML文件中 63 TransformerFactory facotry = TransformerFactory.newInstance(); 64 //創建factory實例 65 Transformer ts = facotry.newTransformer(); 66 ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); 67 //將源寫入到目的中去 68 69 } 70 71 // 4、向指定元素節點中增加子元素節點:第一本中增加子元素<內部價>99.00</內部價> 72 public static void test4(Document document) throws Exception { 73 // 創建一個新的元素並設置其主體內容 74 Element e = document.createElement("內部價"); 75 e.setTextContent("99.00元"); 76 // 找到第一本書元素 77 Node firstBookNode = document.getElementsByTagName("書").item(0); 78 // 把新節點掛接到第一本書上 79 firstBookNode.appendChild(e); 80 // 把內存中Documeng樹寫回XML文件中 81 TransformerFactory facotry = TransformerFactory.newInstance(); 82 Transformer ts = facotry.newTransformer(); 83 ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); 84 } 85 86 // 5、向指定元素節點上增加同級元素節點:在第一本書的售價前面增加批發價 87 public static void test5(Document document) throws Exception { 88 // 創建一個新的元素並設置其中的主體內容 89 Element e = document.createElement("批發價"); 90 e.setTextContent("58.00元"); 91 // 找到第一本書的售價 92 Node firstPrice = document.getElementsByTagName("售價").item(0); 93 // 在售價的前面加入新建的元素:增加子元素一定要使用父元素來做
94 firstPrice.getParentNode().insertBefore(e, firstPrice); //增加子元素一定要使用父元素來做 95 // 把內存中Documeng樹寫回XML文件中 96 TransformerFactory facotry = TransformerFactory.newInstance(); 97 Transformer ts = facotry.newTransformer(); 98 ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); 99 } 100 101 // 6、刪除指定元素節點:刪除內部價 102 public static void test6(Document document) throws Exception { 103 // 找到內部價節點,用爸爸刪除 刪除的時候要有父節點刪除子節點 104 Node n = document.getElementsByTagName("內部價").item(0); 105 n.getParentNode().removeChild(n); 106 // 把內存中Documeng樹寫回XML文件中 107 TransformerFactory facotry = TransformerFactory.newInstance(); 108 Transformer ts = facotry.newTransformer(); 109 ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); 110 } 111 112 // 7、操作XML文件屬性:打印第一本書的出版社 113 public static void test7(Document document) throws Exception { 114 // 得到第一本書 115 //document.getElementByTagName("書") 獲取書說有元素 116 Node n = document.getElementsByTagName("書").item(0); //item(0)獲取第一個元素 117 // 打印指定屬性的取值 118 Element e = (Element) n; //打印指定的屬性值 119 System.out.println(e.getAttribute("出版社")); //getAttribute() 120 } 121 122 // 8、添加一個出版社屬性給第二本書 123 public static void test8(Document document) throws Exception { 124 // 得到第二本書 125 Node n = document.getElementsByTagName("書").item(1); 126 // 打印指定屬性的取值 127 Element e = (Element) n; 128 e.setAttribute("出版社", "上海傳智"); //設置該值 129 // 把內存中Documeng樹寫回XML文件中 130 //把內存中的Document樹寫回到XML文件中 131 TransformerFactory facotry = TransformerFactory.newInstance(); 132 Transformer ts = facotry.newTransformer(); 133 ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); 134 } 135 }
測試
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 <exam> 3 <student examid="222" idcard="111"> 4 <name>張三</name> 5 <location>沈陽</location> 6 <grade>89</grade> 7 </student> 8 <student examid="444" idcard="333"> 9 <name>李四</name> 10 <location>大連</location> 11 <grade>97</grade> 12 </student> 13 <student examid="666" idcard="555"> 14 <name>李宗瑞</name> 15 <location>台北</location> 16 <grade>100.0</grade> 17 </student> 18 </exam>
建立一個學生類
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 public String getIdcard() { 8 return idcard; 9 } 10 public void setIdcard(String idcard) { 11 this.idcard = idcard; 12 } 13 public String getExamid() { 14 return examid; 15 } 16 public void setExamid(String examid) { 17 this.examid = examid; 18 } 19 public String getName() { 20 return name; 21 } 22 public void setName(String name) { 23 this.name = name; 24 } 25 public String getLocation() { 26 return location; 27 } 28 public void setLocation(String location) { 29 this.location = location; 30 } 31 public float getGrade() { 32 return grade; 33 } 34 public void setGrade(float grade) { 35 this.grade = grade; 36 } 37 @Override 38 public String toString() { 39 return "Student [examid=" + examid + ", grade=" + grade + ", idcard=" 40 + idcard + ", location=" + location + ", name=" + name + "]"; 41 } 42 43 }
創建一個接口:該接口有以以下的功能
- 添加學生信息到XML中
- 根據准考證號查詢學生信息 如何學生不在,則返回null
- 根據學生姓名刪除學生
package com.meijunjie.dao; import com.meijunjie.domain.Student; public interface IStudentDao { /** * 添加學生信息到XML中 * @param s * @return */ boolean createStudent(Student s); /** * 根據准考證號查詢學生信息 * @param examid * @return 如果學生不存在,返回null */ Student findStudent(String examid); /** * 根據學生姓名刪除學生 * @param name * @return 如果人不存在也返回false */ boolean deleteStudent(String name); }
創建工具類采用DOM方式解析XML文檔 ,更新XML文檔
1 package cn.meijunjie.util; 2 3 import javax.xml.parsers.DocumentBuilder; 4 import javax.xml.parsers.DocumentBuilderFactory; 5 import javax.xml.transform.Transformer; 6 import javax.xml.transform.TransformerFactory; 7 import javax.xml.transform.dom.DOMSource; 8 import javax.xml.transform.stream.StreamResult; 9 10 import org.w3c.dom.Document; 11 //操作XML的工具類 12 //工具類中的異常可以拋也可以處理 13 public class DocumentUtil { 14 public static Document getDocument() throws Exception{
//讀取XML文檔 15 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 16 return builder.parse("src/exam.xml"); 17 }
//向XML文檔中寫入 18 public static void write2xml(Document document)throws Exception{ 19 Transformer ts = TransformerFactory.newInstance().newTransformer(); 20 ts.transform(new DOMSource(document), new StreamResult("src/exam.xml")); 21 } 22 }
實現該接口:
package cn.meijunjie.dao; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import cn.itcast.domain.Student; import cn.itcast.util.DocumentUtil; //異常:拋的話,上層能解決才行 //上一層如果處理不了,自己必須處理。 public class StudentDao implements IStudentDao { /** * 添加學生信息到XML中 * @param s * @return */ public boolean createStudent(Student s){ System.out.println("JAXP"); //目標:在根元素exam中添加student子元素 boolean result = false; try { Document document = DocumentUtil.getDocument(); //讀取文檔內容 //創建name、location、grade元素並設置其主體內容 Element nameE = document.createElement("name"); nameE.setTextContent(s.getName()); Element locationE = document.createElement("location"); locationE.setTextContent(s.getLocation()); Element gradeE = document.createElement("grade"); gradeE.setTextContent(s.getGrade()+""); //創建student元素,並設置其屬性 Element studentE = document.createElement("student"); studentE.setAttribute("idcard", s.getIdcard()); studentE.setAttribute("examid", s.getExamid());//CTRL+ALT+ARROW studentE.appendChild(nameE); studentE.appendChild(locationE); studentE.appendChild(gradeE); //得到exam元素,把student掛接上去 Node node = document.getElementsByTagName("exam").item(0); node.appendChild(studentE); //寫回XML文件中 DocumentUtil.write2xml(document); result = true; } catch (Exception e) { throw new RuntimeException(e);//異常轉義。異常鏈 } return result; } /** * 根據准考證號查詢學生信息 * @param examid * @return 如果學生不存在,返回null */ public Student findStudent(String examid){ Student s = null; try{ //得到Document對象 Document document = DocumentUtil.getDocument(); //得到所有的student元素 NodeList nl = document.getElementsByTagName("student"); //遍歷student元素,判斷他的examid屬性的取值是否與參數匹配 for(int i=0;i<nl.getLength();i++){ Node node = nl.item(i); // if(node.getNodeType()==Node.ELEMENT_NODE){ // Element e = (Element)node; if(node instanceof Element){ Element e = (Element)node; if(e.getAttribute("examid").equals(examid)){ //如果匹配:說明找到了學生;創建學生對象 s = new Student(); //設置學生對象的各個屬性取值 s.setExamid(examid); s.setIdcard(e.getAttribute("idcard")); s.setName(e.getElementsByTagName("name").item(0).getTextContent()); s.setLocation(e.getElementsByTagName("location").item(0).getTextContent()); s.setGrade(Float.parseFloat(e.getElementsByTagName("grade").item(0).getTextContent())); } } } }catch(Exception e){ throw new RuntimeException(e); } return s; } /** * 根據學生姓名刪除學生 * @param name * @return 如果人不存在也返回false */ public boolean deleteStudent(String name){ boolean result = false; try{ //得到Document對象 Document document = DocumentUtil.getDocument(); //得到所有的name元素 NodeList nl = document.getElementsByTagName("name"); //遍歷name元素,判斷其主體內容是否與參數一致 for(int i=0;i<nl.getLength();i++){ //如果一致:找到他的爸爸的爸爸,刪除它的爸爸 Node n = nl.item(i); if(n.getTextContent().equals(name)){ n.getParentNode().getParentNode().removeChild(n.getParentNode()); //寫回XML文檔 DocumentUtil.write2xml(document); result = true; break; } } }catch(Exception e){ throw new RuntimeException(e); } return result; } }
