body,td { font-family: calibri; font-size: 10pt }
- XML.03-DOM和SAX解析
-
- XML的DOM解析
- 解析
- 处理
- 回写
- XML的SAX解析
- SAX和DOM方式的不同:
- SAX解析原理
- SAX解析范例
- XML的DOM解析
-
解析xml常用的有两种方式,DMO和SAX
DOM和SAX的区别:
- DOM:
- 在内存中生成树桩结构
- 优点是可以支持增删改查各种操作
- 缺点在于,如果文档过大的时候,可能会产生内存溢出的风险
- SAX:
- 基于事件驱动,边读边解析
- 优点:占用内存小
- 缺点,不支持增删改操作.(DOM4J会在内存中生成树状结构,虽然是SAX方式解析…)
XML的DOM解析
xml的DOM解析,主要会用到两个包中的类
- javax.xml.parsers :用来解析
- javax.xml.transform:用来回写
解析
public static Document getDocument(String src) throws Exception{ //获取工厂类 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //获取解析器 DocumentBuilder builder = factory.newDocumentBuilder(); //返回Document(org.w3c.dom.Document) return builder.parse(src); }
处理
在拿到document之后,就可以想干哈就干哈了.
在元素末尾增加一个子元素
/** * DOM大法之--在元素末尾增加一个元素 * @throws Exception */ public static void addElementTest() throws Exception{ //解析 Document document = JaxpDomUtils.getDocument("src/book.xml"); //处理 NodeList nodeList = document.getElementsByTagName("书"); Node book2 = nodeList.item(1);
Element cat = document.createElement("cat"); cat.setTextContent("I am a cat"); book2.appendChild(cat); //回写 JaxpDomUtils.writeBack(document, "src/book.xml"); }
这个地方需要注意,Node和Element. Node表示文档树上的一个节点,这个文档不局限于HTML或者XML,而element表示HTML或者xml中一个元素.
在任意位置增加元素
/** * DOM大法之--在任意位置增加元素 * @throws Exception */ public static void addElementAnyWhereTest() throws Exception{ Document document = JaxpDomUtils.getDocument("src/book.xml"); Node book2 = document.getElementsByTagName("书").item(1); Node author2 = document.getElementsByTagName("作者").item(1); Element cat = document.createElement("cat"); cat.setTextContent("I am a cat too"); book2.insertBefore(cat, author2); JaxpDomUtils.writeBack(document, "src/book.xml"); }
删除一个节点
/** * DOM大法之--删除一个元素 * @throws Exception */ public static void deleteNodeTest() throws Exception{ Document document = JaxpDomUtils.getDocument("src/book.xml"); Node cat1 = document.getElementsByTagName("cat").item(0); Node book = cat1.getParentNode(); book.removeChild(cat1); JaxpDomUtils.writeBack(document, "src/book.xml");
}
这里比较蛋疼的是,必须先找到要删除的元素,然后再找他爹,然后通过他爹的remove方法把它删掉…
改
/** * DOM大法之--修改元素 * @throws Exception */ public static void changeNodeTest() throws Exception { Document document = JaxpDomUtils.getDocument("src/book.xml"); Node author2 = document.getElementsByTagName("作者").item(1); author2.setTextContent("西川结衣"); JaxpDomUtils.writeBack(document, "src/book.xml");
}
查找
/** * DOM大法之--删除一个元素 * @throws Exception */ public static void deleteNodeTest() throws Exception{ Document document = JaxpDomUtils.getDocument("src/book.xml"); Node cat1 = document.getElementsByTagName("cat").item(0); Node book = cat1.getParentNode(); book.removeChild(cat1); JaxpDomUtils.writeBack(document, "src/book.xml");
}
Node下面有很多get方法,需要的时候再翻文档吧.
回写
public static void writeBack(Document document, String dest) throws Exception{ //回写的工厂类 TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult(dest)); }
XML的SAX解析
SAX和DOM方式的不同:
- DOM需要将整个XML文件都读取后再进行解析,如果XML文档非常大,就会消耗计算机的大量内存,并且容易导致内存溢出
- SAX 是边读边解析.
SAX解析原理
SAX方式和DOM方式的套路差不多. 只有一点不一样,SAX方式没有增删改的功能,只是单纯的读取解析,所以就没有回写的必要了.
这玩意儿主要的方法,大概是这个样子的: void parse(String uri, DefaultHandler dh)
那么这里就涉及到两个东西:
- 解析器:
- 获取解析器工厂
- 获取解析器对象
- 解析XML(XML 文件路径,事件处理器)
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理
- 一般用DefaultHandler,他是SAX时间处理程序的默认基类.
- 基于事件触发,比如遇到一个开始标签,就会去执行startElement()方法…(消息订阅机制?! 貌似上学的时候学过这玩意儿…)
对于一个标准的XML它的消息触发机制大概是这个样子的.
SAX解析范例
写一个自己的Handler
/** * 解析xml文件 * @author thecatcher * */class MyHandler1 extends DefaultHandler{
//开始标签 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("read a start label for an element:"+qName); } //元素内容 @Override public void characters(char[] ch, int start, int length) throws SAXException { String str = new String(ch,start,length); System.out.println(str); } //结束标签 @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("read a end label for an element:"+qName); }}
发散一下,既然是个方法那就可以自己定义行为了. 比如读取特定标签
/** * 读取特定标签 * @author thecatcher * */class MyHandler21 extends DefaultHandler{ private boolean flag=false; private int count =0; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("作者".equals(qName)){ flag=true; count++; } }
@Override public void characters(char[] ch, int start, int length) throws SAXException { if(flag&&count==2){ String str=new String(ch, start, length); System.out.println(str);
} } @Override public void endElement(String uri, String localName, String qName) throws SAXException { flag=false; }}
解析主类:
public void readXMLTest() throws ParserConfigurationException, SAXException, IOException{ SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/book2.xml", new MyHandler21()); }
时间: 2024-10-07 09:39:44