按照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 文件,得到代表文档 的 document Document 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,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,IOException{ // 创建工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 得到 COM 解析器 DocumentBuilder builder = factory.newDocumentBuilder(); // 解析 XML 文件,得到代表文档 的 document Document 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,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,IOException{ // 创建工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 得到 COM 解析器 DocumentBuilder builder = factory.newDocumentBuilder(); // 解析 XML 文件,得到代表文档 的 document Document 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,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,TransformerException { // 得到 document DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse("src/com/haizhu/xml/book.xml"); // 得到Element Element 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,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,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{ // 开始 @Override public 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); } } // 结束 @Override public void endElement(String uri,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)); } @Override public void setDocumentLocator(Locator locator) {} @Override public void startDocument() throws SAXException {} @Override public void endDocument() throws SAXException {} @Override public void startPrefixMapping(String prefix,String uri) throws SAXException {} @Override public void endPrefixMapping(String prefix) throws SAXException {} @Override public void ignorableWhitespace(char[] ch,int length) throws SAXException {} @Override public void processingInstruction(String target,String data) throws SAXException {} @Override public void skippedEntity(String name) throws SAXException {} } //取出 XML 中指定属性的值 class TagValueHandler extends DefaultHandler{ // 继承这个类就可以选择的覆写需要的方法,而不用全部覆写 private String currentTag; // 记住当前解析到的标签内容 // 开始 @Override public void startElement(String uri,Attributes atts) throws SAXException { currentTag = qName; } // 结束 @Override public void endElement(String uri,String qName) throws SAXException { currentTag = null; } // 内容 @Override public void characters(char[] ch,int length) throws SAXException { if("作者".equals(currentTag)){ System.out.println(new String(ch,length)); } } } //上面的例子取出了所有的作者,能不能取出指定的第N位作者的名字呢?如下: class NeedTagValueHandler extends DefaultHandler{ private String currentTag; private int needNum = 2; // 想获取第几个作者的值 private int currentNum; // 开始 @Override public void startElement(String uri,Attributes atts) throws SAXException { currentTag = qName; if(currentTag.equals("作者")){ currentNum++; } } // 结束 @Override public void endElement(String uri,int length) throws SAXException { if("作者".equals(currentTag) && currentNum==needNum){ System.out.println(new String(ch,length)); } } }原文链接:https://www.f2er.com/xml/299979.html