一、简介。
1.xml解析技术有两种:dom和sax
2.dom:Document Object Model,即文档对象模型,是W3C组织推荐的解析XML的一种方式。
sax:Simple API for XML,不是官方标准,单它是xml社区事实上的标准。
3.XML解析器:Crimson(sun,jdk自带)、Xerces(IBM 最好的解析器)、A elfred2(dom4j),使用哪种解析器对程序员基本上没有什么影响,我们学习的是解析开发包,解析开发包调用什么样的解析器对程序员没有意义。
4.XML解析开发包:Jaxp(sun)、Jdom(不推荐使用)、dom4j(比较不错),Pull(android的sdk自带,它使用的是另外的解析方式streaming api for xml,即stax)
5.JAXP:Java API for xml Processing,jaxp是sun提供的一套xml解析API,jaxp很好地支持了dom和sax解析方式
解析XML文档使用的包名:
javax.xml
org.xml.sax
org.w3c.dom
javax.xml.parsers包中,定义了几个工厂类,程序员调用这些工程类,可以得到对xml文档进行解析的dom或者sax的解析器对
象。
6.DOM解析过程:首先将整个文档加载到内存,形成DOM树。使用dom进行解析,得到Document对象
7.使用DOM解析方式的缺点:整个文档需要全部放入内存,如果是大文件极易出现内存溢出的情况。
使用DOM解析方式的有点:操作速度快。
二、使用DOM对XML文档实现CRUD操作。
首先创建一个类:Book,该类对应着XML文档的一个节点。
1 package p00.domain; 2 3 public class Book { 4 public String title; 5 public double price; 6 public String id; 7 public String getId() 8 { 9 return id; 10 } 11 public void setId(String id) 12 { 13 this.id=id; 14 } 15 public String getTitle() 16 { 17 return title; 18 } 19 public double getPrice() 20 { 21 return price; 22 } 23 public void setTitle(String title) 24 { 25 this.title=title; 26 } 27 public void setPrice(double price) 28 { 29 this.price=price; 30 } 31 public String toString() 32 { 33 return "图书ISBN为:"+id+" 书名为:"+title+" 价格为:"+price; 34 } 35 36 }
得到Document对象的公共方法:
1 private static Document getDocument() throws Exception { 2 DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); 3 //获得解析器实例 4 DocumentBuilder db=dbf.newDocumentBuilder(); 5 //获得Document实例 6 File file=new File("xmldata/books.xml"); 7 if(!file.exists()) 8 { 9 System.out.println("目标文件不存在!"); 10 return null; 11 } 12 Document document=db.parse(file); 13 return document; 14 }
通过接受Document对象参数写入到新文件newbooks.xml的方法:
1 /** 2 * 根据得到的Document对象将其中的内容保存到硬盘中的XML文件,完成持久化的工作。 3 * @param document 4 * @throws Exception 5 */ 6 private static void saveToAnotherPlace(Document document) throws Exception { 7 TransformerFactory tf=TransformerFactory.newInstance(); 8 Transformer transformer=tf.newTransformer(); 9 10 Element rootSource=document.getDocumentElement(); 11 Source xmlSource=new DOMSource(rootSource); 12 Result outputTarget=new StreamResult("xmldata/books1.xml"); 13 transformer.transform(xmlSource, outputTarget); 14 }
原本books.xml文档中的内容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <books> 3 <book id="book1"> 4 <title>JAVA编程思想</title> 5 <price>80.00</price> 6 </book> 7 <book id="book2"> 8 <title>JAVA核心技术</title> 9 <price>100.00</price> 10 </book> 11 </books>
1、读取(R)
1 package p01.getElementsByDomDemo; 2 3 import java.io.File; 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 import java.util.List; 7 8 import javax.xml.parsers.DocumentBuilder; 9 import javax.xml.parsers.DocumentBuilderFactory; 10 11 import org.w3c.dom.Document; 12 import org.w3c.dom.Element; 13 import org.w3c.dom.Node; 14 import org.w3c.dom.NodeList; 15 16 import p00.domain.Book; 17 18 public class getElementsDemo { 19 /** 20 * 该类演示使用dom对xml文档的查询,包括元素节点查询和元素属性值查询。 21 */ 22 public static List<Book>list=new ArrayList<Book>(); 23 public static void main(String[] args) throws Exception { 24 /** 25 * 得到所有的元素并保存到list中。 26 */ 27 list=getAllElementsToList(); 28 traverse(list);//遍历集合,查看集合中的内容是否正确。 29 } 30 /** 31 * 该方法用于遍历集合元素。 32 * @param list2 33 */ 34 private static void traverse(List<Book> list2) { 35 System.out.println(); 36 System.out.println("得到的集合内容为:"); 37 Iterator<Book>it=list2.iterator(); 38 while(it.hasNext()) 39 { 40 Book book=it.next(); 41 System.out.println(book); 42 } 43 } 44 public static List<Book> getAllElementsToList() throws Exception 45 { 46 List<Book>list=new ArrayList<Book>(); 47 DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); 48 DocumentBuilder db=dbf.newDocumentBuilder(); 49 File file=new File("xmldata/books.xml"); 50 if(!file.exists()) 51 { 52 System.out.println("目标文件不存在!"); 53 return list; 54 } 55 Document domtree=db.parse(file); 56 //得到根元素列表 57 NodeList roots=domtree.getElementsByTagName("books"); 58 Node root=roots.item(0); 59 //根据根节点,遍历xml文档中的元素。 60 NodeList books=root.getChildNodes(); 61 //显示结果为5本书,事实上包含了回车和换行。 62 // System.out.println("books节点的子节点长度为:"+books.getLength()); 63 //遍历得到的结果集,并去除回车和换行。 64 for(int i=0;i<books.getLength();i++) 65 { 66 Node node=books.item(i); 67 String name=node.getNodeName(); 68 if("book".equals(name)) 69 { 70 Book book=new Book(); 71 Element bookElement=(Element)node;//父接口向子接口强制转换发生异常。 72 String idValue=bookElement.getAttribute("id"); 73 book.setId(idValue); 74 System.out.println("id属性值为:"+idValue); 75 76 NodeList tp=node.getChildNodes(); 77 //这里由于回车换行的关系,所以长度为5 78 // System.out.println("book节点的子节点长度为:"+tp.getLength()); 79 for(int j=0;j<tp.getLength();j++) 80 { 81 Node node1=tp.item(j); 82 String nodename=node1.getNodeName(); 83 if("title".equals(nodename)) 84 { 85 String bookName=node1.getTextContent(); 86 book.setTitle(bookName); 87 System.out.println("书名为:"+bookName); 88 } 89 if("price".equals(nodename)) 90 { 91 String bookPrice=node1.getTextContent(); 92 System.out.println("价格为:"+bookPrice); 93 double bookprice=Double.parseDouble(bookPrice); 94 book.setPrice(bookprice); 95 } 96 } 97 list.add(book); 98 } 99 else 100 continue; 101 } 102 return list; 103 } 104 105 }
读取的时候应当注意的事项是调用getChildNodes方法的时候会将回车换行符作为一个子节点,应当加以判断识别才行。
2、修改(U)
1 /** 2 * 修改XML文档的内容,将JAVA编程思想修改为Thinking in Java 3 * @param document 4 */ 5 private static void updateXMLContent(Document document) { 6 Element root=document.getDocumentElement(); 7 NodeList books=root.getElementsByTagName("book"); 8 for(int i=0;i<books.getLength();i++) 9 { 10 Node node=books.item(i); 11 Element book=(Element)node; 12 String id=book.getAttribute("id"); 13 if("book1".equals(id)) 14 { 15 NodeList childs=node.getChildNodes(); 16 for(int j=0;j<childs.getLength();j++) 17 { 18 Node title=childs.item(j); 19 String nodeName=title.getNodeName(); 20 if("title".equals(nodeName)) 21 { 22 Element aim=(Element)title; 23 aim.setTextContent("Thinking in java"); 24 } 25 else 26 continue; 27 } 28 } 29 else 30 continue; 31 } 32 }
修改后的内容:
1 <?xml version="1.0" encoding="UTF-8"?><books> 2 <book id="book1"> 3 <title>Thinking in java</title> 4 <price>80.00</price> 5 </book> 6 <book id="book2"> 7 <title>JAVA核心技术</title> 8 <price>100.00</price> 9 </book> 10 </books>
3、删除(D)
1 /** 2 * 删除指定元素的方法,要求:删除id值为002的元素。 3 * @param document 4 */ 5 private static void removeOldNodeFromXML(Document document) { 6 7 Element root=document.getDocumentElement(); 8 NodeList books=root.getElementsByTagName("book"); 9 for(int i=0;i<books.getLength();i++) 10 { 11 Node node=books.item(i); 12 Element book=(Element)node; 13 String id=book.getAttribute("id"); 14 if("book2".equals(id)) 15 { 16 Node parent=node.getParentNode(); 17 parent.removeChild(node); 18 } 19 else 20 continue; 21 } 22 23 }
删除后内容:
1 <?xml version="1.0" encoding="UTF-8"?><books> 2 <book id="book1"> 3 <title>JAVA编程思想</title> 4 <price>80.00</price> 5 </book> 6 7 </books>
4、添加(C)
1 /** 2 * 添加新元素的方法。 3 * :添加一个新节点,节点要求:id为book3,title为计算机网络,price为1.0 4 * @param document 5 */ 6 private static void addNewNodeToXML(Document document) { 7 Element root=document.getDocumentElement(); 8 Element book=document.createElement("book"); 9 book.setAttribute("id", "book3"); 10 Element title=document.createElement("title"); 11 Element price=document.createElement("price"); 12 title.setTextContent("计算机网络"); 13 price.setTextContent("1.0"); 14 book.appendChild(title); 15 book.appendChild(price); 16 root.appendChild(book); 17 }
添加后内容:
1 <?xml version="1.0" encoding="UTF-8"?><books> 2 <book id="book1"> 3 <title>JAVA编程思想</title> 4 <price>80.00</price> 5 </book> 6 <book id="book2"> 7 <title>JAVA核心技术</title> 8 <price>100.00</price> 9 </book> 10 <book id="book3"><title>计算机网络</title><price>1.0</price></book></books>
注意使用这种方式添加的元素没有格式上的缩进。
5、完整代码。
1 package p01.getElementsByDomDemo; 2 3 import java.io.File; 4 5 import javax.xml.parsers.DocumentBuilder; 6 import javax.xml.parsers.DocumentBuilderFactory; 7 import javax.xml.transform.Result; 8 import javax.xml.transform.Source; 9 import javax.xml.transform.Transformer; 10 import javax.xml.transform.TransformerFactory; 11 import javax.xml.transform.dom.DOMSource; 12 import javax.xml.transform.stream.StreamResult; 13 14 import org.w3c.dom.Document; 15 import org.w3c.dom.Element; 16 import org.w3c.dom.Node; 17 import org.w3c.dom.NodeList; 18 19 public class CUDDemo { 20 21 public static void main(String[] args) throws Exception { 22 Document document=getDocument(); 23 //修改操作:把id为book1的书籍title的值改为Thinking in java 24 // updateXMLContent(document); 25 26 //添加新元素操作 27 // addNewNodeToXML(document); 28 29 //删除指定元素的方法。 30 // removeOldNodeFromXML(document); 31 //作为一个独立的方法将得到的document对象中的内容写入到硬盘中的文件。 32 saveToAnotherPlace(document); 33 } 34 /** 35 * 删除指定元素的方法,要求:删除id值为002的元素。 36 * @param document 37 */ 38 private static void removeOldNodeFromXML(Document document) { 39 40 Element root=document.getDocumentElement(); 41 NodeList books=root.getElementsByTagName("book"); 42 for(int i=0;i<books.getLength();i++) 43 { 44 Node node=books.item(i); 45 Element book=(Element)node; 46 String id=book.getAttribute("id"); 47 if("book2".equals(id)) 48 { 49 Node parent=node.getParentNode(); 50 parent.removeChild(node); 51 } 52 else 53 continue; 54 } 55 56 } 57 /** 58 * 添加新元素的方法。 59 * :添加一个新节点,节点要求:id为book3,title为计算机网络,price为1.0 60 * @param document 61 */ 62 private static void addNewNodeToXML(Document document) { 63 Element root=document.getDocumentElement(); 64 Element book=document.createElement("book"); 65 book.setAttribute("id", "book3"); 66 Element title=document.createElement("title"); 67 Element price=document.createElement("price"); 68 title.setTextContent("计算机网络"); 69 price.setTextContent("1.0"); 70 book.appendChild(title); 71 book.appendChild(price); 72 root.appendChild(book); 73 } 74 75 /** 76 * 修改XML文档的内容,将JAVA编程思想修改为Thinking in Java 77 * @param document 78 */ 79 private static void updateXMLContent(Document document) { 80 Element root=document.getDocumentElement(); 81 NodeList books=root.getElementsByTagName("book"); 82 for(int i=0;i<books.getLength();i++) 83 { 84 Node node=books.item(i); 85 Element book=(Element)node; 86 String id=book.getAttribute("id"); 87 if("book1".equals(id)) 88 { 89 NodeList childs=node.getChildNodes(); 90 for(int j=0;j<childs.getLength();j++) 91 { 92 Node title=childs.item(j); 93 String nodeName=title.getNodeName(); 94 if("title".equals(nodeName)) 95 { 96 Element aim=(Element)title; 97 aim.setTextContent("Thinking in java"); 98 } 99 else 100 continue; 101 } 102 } 103 else 104 continue; 105 } 106 } 107 108 /** 109 * 根据得到的Document对象将其中的内容保存到硬盘中的XML文件,完成持久化的工作。 110 * @param document 111 * @throws Exception 112 */ 113 private static void saveToAnotherPlace(Document document) throws Exception { 114 TransformerFactory tf=TransformerFactory.newInstance(); 115 Transformer transformer=tf.newTransformer(); 116 117 Element rootSource=document.getDocumentElement(); 118 Source xmlSource=new DOMSource(rootSource); 119 Result outputTarget=new StreamResult("xmldata/books1.xml"); 120 transformer.transform(xmlSource, outputTarget); 121 } 122 123 /** 124 * 得到Document对象的方法。 125 * @return 126 * @throws Exception 127 */ 128 private static Document getDocument() throws Exception { 129 DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); 130 //获得解析器实例 131 DocumentBuilder db=dbf.newDocumentBuilder(); 132 //获得Document实例 133 File file=new File("xmldata/books.xml"); 134 if(!file.exists()) 135 { 136 System.out.println("目标文件不存在!"); 137 return null; 138 } 139 Document document=db.parse(file); 140 return document; 141 } 142 143 }
三、SAX
使用该解析技术只能实现对XML文档的读取操作。使用这种方式的优点就是它的解析方式为“逐行读取”,并非将XML文档一次性加载进内存,这样就能够避免内存溢出的情况了,该解析方式是dom4j的解析方式。
注意DefaultHandler类,该类实现了某些处理xml文档必须的接口,但是均没有具体的方法,也就是说是空方法,如果想要解析xml文档,需要覆写该方法。
1 package p02.readElementsBySaxDemo; 2 3 import java.io.File; 4 5 import javax.xml.parsers.ParserConfigurationException; 6 import javax.xml.parsers.SAXParser; 7 import javax.xml.parsers.SAXParserFactory; 8 9 import org.xml.sax.Attributes; 10 import org.xml.sax.SAXException; 11 import org.xml.sax.helpers.DefaultHandler; 12 13 /** 14 * 该类的功能是通过Sax技术实现对xml文档的查找操作。 15 * 使用SAX技术不能实现对XML文档的增删改操作。 16 * @author kdyzm 17 * 18 */ 19 public class ReadXMLBySax { 20 21 public static void main(String[] args) throws Exception, SAXException { 22 SAXParserFactory spf=SAXParserFactory.newInstance(); 23 SAXParser sp=spf.newSAXParser(); 24 File file=new File("xmldata/books.xml"); 25 MyHandler mh=new MyHandler(); 26 sp.parse(file, mh); 27 } 28 29 } 30 31 /** 32 * 该类重写了默认处理类中的部分方法。 33 * @author kdyzm 34 * 35 */ 36 class MyHandler extends DefaultHandler 37 { 38 39 //文档开始的时候触发该事件 40 @Override 41 public void startDocument() throws SAXException { 42 System.out.println("开始解析文档!"); 43 super.startDocument(); 44 } 45 46 //文档结束的时候触发该事件 47 @Override 48 public void endDocument() throws SAXException { 49 System.out.println("解析文档结束!"); 50 super.endDocument(); 51 } 52 53 //当开始解析一个元素的时候触发该事件 54 @Override 55 public void startElement(String uri, String localName, String qName, 56 Attributes attributes) throws SAXException { 57 System.out.println("开始解析元素:"+qName+" 属性id的值是:"+attributes.getValue("id")); 58 super.startElement(uri, localName, qName, attributes); 59 } 60 61 //解析完成一个元素的时候触发该事件 62 @Override 63 public void endElement(String uri, String localName, String qName) 64 throws SAXException { 65 super.endElement(uri, localName, qName); 66 System.out.println("解析元素结束:"+qName); 67 } 68 69 //遇到字符串的时候触发该事件。 70 @Override 71 public void characters(char[] ch, int start, int length) 72 throws SAXException { 73 System.out.println("解析得到的字符串是:"+new String(ch,start,length)); 74 super.characters(ch, start, length); 75 } 76 77 }
输出:
开始解析文档!
开始解析元素:books 属性id的值是:null
解析得到的字符串是:
开始解析元素:book 属性id的值是:book1
解析得到的字符串是:
开始解析元素:title 属性id的值是:null
解析得到的字符串是:JAVA编程思想
解析元素结束:title
解析得到的字符串是:
开始解析元素:price 属性id的值是:null
解析得到的字符串是:80.00
解析元素结束:price
解析得到的字符串是:
解析元素结束:book
解析得到的字符串是:
开始解析元素:book 属性id的值是:book2
解析得到的字符串是:
开始解析元素:title 属性id的值是:null
解析得到的字符串是:JAVA核心技术
解析元素结束:title
解析得到的字符串是:
开始解析元素:price 属性id的值是:null
解析得到的字符串是:100.00
解析元素结束:price
解析得到的字符串是:
解析元素结束:book
解析得到的字符串是:
解析元素结束:books
解析文档结束!