XML 的 解析 :DOM 和 SAX

来源:互联网 发布:淘宝新店运营计划 编辑:程序博客网 时间:2024/04/27 06:55

按照DTD 或者 Schema 标准,写好一个 XML 文件之后,就需要将 XML 文件的内容进行解析,以便于知道在这个XML文件中有什么内容,又有什么作用。那么怎么解析出这个 XML 的信息呢?有两种方式:DOM 和 SAX。其中,DOM方式是W3C 推荐的标准方式,但是 SAX 是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。


DOM:优点,对文档CRUD比较方便,但是内存占用较大

SAX:优点,占用内存小,解析速度快,但是只适合文档的读取,不适合CRUD


1、DOM

DOM 解析下,XML 文件的每一个组成部分都会用一个对象表示,例如标签用Element、属性用Attr,但是不管什么对象,都是Node的子类,所以在开发中把获得的任意节点都当做Node对象。这里就体现了JAVA中,一切皆对象的思想。

范例:

book.dtd

<!ENTITY bookName "Think in JAVA"><!ELEMENT 书架 ANY><!ELEMENT 书 (书名,作者,售价)><!ELEMENT 书名 (#PCDATA)><!ELEMENT 作者 (#PCDATA)><!ELEMENT 售价 (#PCDATA)><!ATTLIST 书名ISBN码 CDATA #IMPLIED>
book.xml

<?xml version="1.0" ?><!DOCTYPE 书架 SYSTEM "book.dtd"><书架><书><书名>&bookName;</书名><!-- 使用引用实体 --><作者>海竹</作者><售价>30.0</售价></书><书><书名 ISBN码="521">WEB 实战经典</书名><!-- 自己定义,并使用“ISBN码”属性 --><作者>西行</作者><售价>29.9</售价></书></书架>

DomDemo.java

package com.haizhu.xml;import java.io.IOException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.w3c.dom.Document;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;public class DomDemo {public void read() throws ParserConfigurationException, SAXException, IOException{// 创建工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 得到 COM 解析器DocumentBuilder builder = factory.newDocumentBuilder();// 解析 XML 文件,得到代表文档 的 documentDocument document = builder.parse("src/com/haizhu/xml/book.xml");// 读取出指定名称的节点,作为集合对象NodeList list = document.getElementsByTagName("书名");// 分别取出这个节点集合中的两个节点对象Node node = list.item(1);// 取出这个节点对象的内容String content = node.getTextContent();System.out.println(content);}public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {DomDemo demo = new DomDemo();demo.read();}}
结果:
WEB 实战经典

为了解析出书名中的“ISBN码”这个属性,我们可以运用向下转型的方法,将Node 对象转换成 Element 对象,这样就可以使用更多更方便操作的方法,如下所示:

package com.haizhu.xml;import java.io.IOException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;public class DomDemo {public void read() throws ParserConfigurationException, SAXException, IOException{// 创建工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 得到 COM 解析器DocumentBuilder builder = factory.newDocumentBuilder();// 解析 XML 文件,得到代表文档 的 documentDocument document = builder.parse("src/com/haizhu/xml/book.xml");// 读取出指定名称的节点,作为集合对象NodeList list = document.getElementsByTagName("书名");// 分别取出这个节点集合中的两个节点对象Element node = (Element) list.item(1);// 向下转型,因为我们确定这个集合就是 Element 对象// 取出这个节点对象的内容String content = node.getTextContent();String attr = node.getAttribute("ISBN码");// 调用 取出对应名称的属性 的方法System.out.println(content);System.out.println(attr);}public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {DomDemo demo = new DomDemo();demo.read();}}
结果:

WEB 实战经典521

除了上面的读取信息,还有更多操作,比如增加,删除,修改等:

package com.haizhu.xml;import java.io.FileOutputStream;import java.io.IOException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerConfigurationException;import javax.xml.transform.TransformerException;import javax.xml.transform.TransformerFactory;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;public class DomDemo {public void read() throws ParserConfigurationException, SAXException, IOException{// 创建工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 得到 COM 解析器DocumentBuilder builder = factory.newDocumentBuilder();// 解析 XML 文件,得到代表文档 的 documentDocument document = builder.parse("src/com/haizhu/xml/book.xml");// 读取出指定名称的节点,作为集合对象NodeList list = document.getElementsByTagName("书名");// 分别取出这个节点集合中的两个节点对象Element node = (Element) list.item(1);// 向下转型,因为我们确定这个集合就是 Element 对象// 取出这个节点对象的内容String content = node.getTextContent();String attr = node.getAttribute("ISBN码");// 调用 取出对应名称的属性 的方法System.out.println(content);System.out.println(attr);}public void add() throws ParserConfigurationException, SAXException, IOException, TransformerException{DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse("src/com/haizhu/xml/book.xml");// ***********************先增加一本书**************************// 创建一个书的节点对象Element book = (Element)document.createElement("书");// 取出书的父节点对象,也就是根节点,注意根节点不需要名称Element bookShelf = (Element)document.getDocumentElement();// 将书添加到父节点bookShelf.appendChild(book);// ***********************为一本书增加书名,作者,售价**************************// 跟上面的步骤是一样的,如下:Element bookName = (Element)document.createElement("书名");Element author = (Element)document.createElement("作者");Element price = (Element)document.createElement("售价");bookName.setTextContent("Steve Jobs");author.setTextContent("Walter Isaacson");price.setTextContent("106.0");book.appendChild(bookName);book.appendChild(author);book.appendChild(price);// ***********************增加  属性**************************bookName.setAttribute("ISBN码", "U R NO.1 !");// ***********************更新xml文档**************************// 上面的操作指示把内容写进了内存,但是没有写入xml文档,需要如下操作:TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();transformer.transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/com/haizhu/xml/book.xml")));}public void delete() throws ParserConfigurationException, SAXException, IOException, TransformerException {// 得到 documentDocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse("src/com/haizhu/xml/book.xml");// 得到ElementElement toDelete = (Element)document.getElementsByTagName("售价").item(0);Element dFather = (Element)document.getElementsByTagName("书").item(0);// 移除dFather.removeChild(toDelete);// 提交TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();transformer.transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/com/haizhu/xml/book.xml")));}public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, TransformerException {DomDemo demo = new DomDemo();demo.read();demo.add();demo.delete();}}


2、SAX

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

a、解析器可以使用 JAXP 的API 创建,创建出 SAX 解析器后,就可以知道你个解析器去解析某个 XML 文档。

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

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

package com.haizhu.xml;import java.io.IOException;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.Attributes;import org.xml.sax.ContentHandler;import org.xml.sax.Locator;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;public class SAXDemo {public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {// 1、创建工厂SAXParserFactory factory = SAXParserFactory.newInstance();// 2、得到解析器SAXParser saxParser = factory.newSAXParser();// 3、得到读取器XMLReader reader = saxParser.getXMLReader();// 4、设置内容处理器,每个处理器有自己的处理方法//reader.setContentHandler(new ListHandler());//reader.setContentHandler(new NeedTagValueHandler());reader.setContentHandler(new NeedTagValueHandler());// 5、读取xml文档reader.parse("src/com/haizhu/xml/book.xml");}}// 取出 XML 中所有的内容class ListHandler implements ContentHandler{// 开始@Overridepublic void startElement(String uri, String localName, String qName,Attributes atts) throws SAXException {System.out.println("<"+qName+">");// 循环取出属性,注意中间的判断可以使用 “ && ”for(int i=0;atts!=null && i<atts.getLength();i++){String attName = atts.getQName(i);String attValue = atts.getValue(i);System.out.println(attName+" = "+attValue);}}// 结束@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {System.out.println("</"+qName+">");}// 内容@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {System.out.println(new String(ch,start,length));}@Overridepublic void setDocumentLocator(Locator locator) {}@Overridepublic void startDocument() throws SAXException {}@Overridepublic void endDocument() throws SAXException {}@Overridepublic void startPrefixMapping(String prefix, String uri)throws SAXException {}@Overridepublic void endPrefixMapping(String prefix) throws SAXException {}@Overridepublic void ignorableWhitespace(char[] ch, int start, int length)throws SAXException {}@Overridepublic void processingInstruction(String target, String data)throws SAXException {}@Overridepublic void skippedEntity(String name) throws SAXException {}}//取出 XML 中指定属性的值class TagValueHandler extends DefaultHandler{// 继承这个类就可以选择的覆写需要的方法,而不用全部覆写private String currentTag;// 记住当前解析到的标签内容// 开始@Overridepublic void startElement(String uri, String localName, String qName,Attributes atts) throws SAXException {currentTag = qName;}// 结束@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {currentTag = null;}// 内容@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {if("作者".equals(currentTag)){System.out.println(new String(ch,start,length));}}}//上面的例子取出了所有的作者,能不能取出指定的第N位作者的名字呢?如下:class NeedTagValueHandler extends DefaultHandler{private String currentTag;private int needNum = 2;// 想获取第几个作者的值private int currentNum;// 开始@Overridepublic void startElement(String uri, String localName, String qName,Attributes atts) throws SAXException {currentTag = qName;if(currentTag.equals("作者")){currentNum++;}}// 结束@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {currentTag = null;}// 内容@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {if("作者".equals(currentTag) && currentNum==needNum){System.out.println(new String(ch,start,length));}}}








原创粉丝点击