Java 原生解析
在Java 中,原生解析XML 文档的方式有两种,分别是:
Dom 解析XML
简介
Dom 解析功能强大,可增删改查,操作时会将XML 文档以文档对象的方式读取到内存中,因此适用于小文档。
优点
Document 对象代表了一个XML 文档的模型树(类似于数据结构中的树),所有的其他Node 都以一定的顺序包含在Document 对象之内,排列成一个树状结构,以后对XML 文档的所有操作都与解析器无关,直接在这个Document 对象上进行操作即可。
代码
解析代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
| package com.vgbh;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; 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 DomXMLDemo { public static void main(String[] args) {
DomXMLDemo dxd = new DomXMLDemo(); String uri = "bookstore.xml"; String uri1 = "F:/WorkSpace/domB.xml";
dxd.updateDomXMLDemo(uri, "0", "changedName"); } public void queryDomXMLDemo (String uri) { try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); Document doc = dbBuilder.parse(uri); NodeList bookList = doc.getElementsByTagName("book"); for (int i = 0 ;i < bookList.getLength();i ++) { System.out.println("----------开始第" + (i+1) + "遍历。-------------"); Element e = (Element)bookList.item(i); System.out.println("name:" + e.getElementsByTagName("name").item(0).getFirstChild().getNodeValue()); System.out.println("author:" + e.getElementsByTagName("author").item(0).getFirstChild().getNodeValue()); System.out.println("price:" + e.getElementsByTagName("price").item(0).getFirstChild().getNodeValue()); System.out.println("language:" + e.getElementsByTagName("language").item(0).getFirstChild().getNodeValue()); System.out.println("country:" + e.getElementsByTagName("country").item(0).getFirstChild().getNodeValue()); System.out.println("----------第" + (i+1) + "遍历结束。--------------");
} } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}
public void insertDomXMLDemo (String uri, String names, String authors, String prices, String languages, String countrys) { Document doc ; Element bookstore , book ; Element name = null ; Element author = null ; Element price = null ; Element language = null ; Element country = null ; try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); doc = dbBuilder.newDocument(); if (doc != null) { bookstore = doc.createElement("booksore"); book = doc.createElement("book"); book.setAttribute("id", "3"); name = doc.createElement("name"); language = doc.createElement("language"); author = doc.createElement("author"); price = doc.createElement("price"); country = doc.createElement("country"); name.appendChild(doc.createTextNode(names)); author.appendChild(doc.createTextNode(authors)); price.appendChild(doc.createTextNode(prices)); language.appendChild(doc.createTextNode(languages)); country.appendChild(doc.createTextNode(countrys)); book.appendChild(name); book.appendChild(author); book.appendChild(price); book.appendChild(language); book.appendChild(country); bookstore.appendChild(book); doc.appendChild(bookstore); TransformerFactory tfFactory = TransformerFactory.newInstance(); Transformer tf = tfFactory.newTransformer(); tf.setOutputProperty(OutputKeys.INDENT, "true"); tf.transform(new DOMSource(doc), new StreamResult(uri)); System.out.println("生成XML文件成功!"); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } } public void updateDomXMLDemo (String uri, String id, String name) {
try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); Document doc = dbBuilder.parse(uri); NodeList bookList = doc.getElementsByTagName("book"); for (int i = 0; i < bookList.getLength(); i++) { if (String.valueOf(i).equals(id)) { Element e = (Element) bookList.item(i); e.getElementsByTagName("name").item(0).getFirstChild().setNodeValue(name); break; } } TransformerFactory tfFactory = TransformerFactory.newInstance(); Transformer tf = tfFactory.newTransformer(); tf.setOutputProperty(OutputKeys.INDENT, "true"); tf.transform(new DOMSource(doc), new StreamResult(uri)); System.out.println("生成XML文件成功!"); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } } }
|
输出样例
- queryDomXMLDemo的输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| -----------------开始第1遍历。---------------------- name:cet4 author:college-English price:55 language:english country:2 -----------------第1遍历结束。---------------------- -----------------开始第2遍历。---------------------- name:cet6 author:me price:33 language:lalalal country:chinese -----------------第2遍历结束。----------------------
|
从这里可以看出,Dom 遍历XML 文件是追条进行遍历,所以只是用较小的XML 文件,并且这样可以修改其中的值,完成数据更新。
insertDomXMLDemo 的输出结果:
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> <booksore> <book id="3"> <name>一生有你</name> <author>午歌</author> <price>25</price> <language>chinese</language> <country>china</country> </book> </booksore>
|
updateDomXMLDemo 的输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version="1.0" encoding="UTF-8" > <bookstore> <book id="1"> <name>cet4</name> <author>college-English</author> <price>55</price> <language>english</language> <country>2</country> </book> <book id="2"> <name>cet6</name> <author>me</author> <price>33</price> <language>lalalal</language> <country>chinese</country> </book> </bookstore>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> <bookstore> <book id="1"> <name>changedName</name> <author>college-English</author> <price>55</price> <language>english</language> <country>2</country> </book> <book id="2"> <name>cet6</name> <author>me</author> <price>33</price> <language>lalalal</language> <country>chinese</country> </book> </bookstore>
|
总结
- 上述的结果可以看出在经过修改XML 文件后,数据替换,但是要注意XML 文件的属性问题,例如编码格式的、版本号等变化所引起的问题。
- 对于以上的三种关于XML 文件的解析、写入、更新方法,我觉得可以写出更具体的方法供这三种函数调用,具体就是问题细节化,这样可以省去大量的时间开发。
- 想理解Dom解析XML 文件的这三种函数,其实也很简单,将要解决的问题进行细分,然后按照不同的步骤进行解决,注重理解不同步骤之间的关系和顺序即可。
Sax 解析XML
简介
Sax 解析是从头到尾逐行逐个元素读取内容,修改较为不便,但适用于只读的大文档。
Sax 采用事件驱动的方式解析文档。
优点
在Sax 的解析过程中,读取到文档开头、结尾,元素的开头和元素的结尾都会触发一些回调方法,你可以在这些回调方法中进行相应事件处理这四个方法是:
- startDocument()
- endDocument()
- startElement()
- endElement()
此外,只读取到节点处是不够的,我们还需要characters() 方法来仔细处理元素内包含的内容将这些回调方法集合起来,便形成了一个类,这个类也就是我们需要的触发器SaxHandler 。
代码
Sax 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| package com.vgbh;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
public class SaxXMLDemo {
public static void main(String[] args) { SaxXMLDemo sxd = new SaxXMLDemo(); String uri = "bookstore.xml"; try { sxd.querySaxXMLDemo (uri); } catch (Exception e) { e.printStackTrace(); } } private void querySaxXMLDemo(String uri) throws Exception {
SAXParserFactory spFactory = SAXParserFactory.newInstance(); SAXParser sParser = spFactory.newSAXParser(); SaxHandler sh = new SaxHandler(); sParser.parse(uri, sh); }
}
class SaxHandler extends DefaultHandler { public void characters (char[] character, int start, int end) throws SAXException { String content = new String(character, start, end); System.out.println(content); super.characters(character, start, end); } public void startDocument () throws SAXException { System.out.println("开始解析文档..."); super.startDocument(); }
public void endDoucement () throws SAXException{ System.out.println("结束解析文档..."); super.endDocument(); } public void startElement (String uri, String localName, String qName, Attributes attribute) throws SAXException { if (attribute != null) { for (int i = 0; i < attribute.getLength(); i ++) { System.out.print(attribute.getQName(i) + "=\"" + attribute.getValue(i) + "\""); } } System.out.print(qName + ":"); super.startElement(uri, localName, qName, attribute); } public void endElement (String uri, String localNmae, String qName) throws SAXException { super.endElement(uri, localNmae, qName); } }
|
总结
- SAX 解析XML 文件主要依靠的是对SaxHandler 类的方法重写,所以理解原生类的函数很重要。
- SaxHandler类在线API:http://docs.basex.org/javadoc/org/basex/build/xml/SAXHandler.html
Dom4j 解析XML
简介
Dom4j 是一种用于解析、写入XML 文件的Java API ,同时由于是开源的,所以可以在GitHub上找到源码。
对于XML的解析,Dom4j 很强大也很好用,并且他的性能、功能和易用性都是非常的好,所以你可以尝试一下使用它。
代码
解析代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| package com.vgbh;
import java.io.FileOutputStream; import java.io.IOException; import java.util.List;
import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter;
public class Dom4jXMLDemo {
public static void main(String[] args) { Dom4jXMLDemo dxd = new Dom4jXMLDemo(); String uri = "bookstore.xml"; String uri1 = "F:/WorkSpace/dom4jDemoC.xml"; dxd.queryDom4jXMLDemo(uri); } public void queryDom4jXMLDemo(String uri) { try { SAXReader sReader = new SAXReader(); Document doc = sReader.read(uri); Element root = doc.getRootElement(); List<Element> books = root.elements(); for (int i = 0; i < books.size(); i++) { Book book = new Book(); Element element = books.get(i); book.setId(element.attributeValue("id")); book.setName(element.elementText("name")); book.setAuthor(element.elementText("author")); book.setPrice(element.elementText("price")); book.setLanguage(element.elementText("language")); book.setCountry(element.elementText("country")); System.out.println("id:" + book.getId() + " name:" + book.getName() + " author:" + book.getAuthor() + " price:" + book.getPrice() + " language:" + book.getLanguage() + " country:" + book.getCountry()); } } catch (DocumentException e) { e.printStackTrace(); } } public void insertDom4jXMLDemo (String uri) { Document doc = DocumentHelper.createDocument(); Element bookstore = doc.addElement("bookstore"); Element book1 = bookstore.addElement("book"); Element name1 = book1.addElement("name"); Element author1 = book1.addElement("author"); Element price1 = book1.addElement("price"); Element language1 = book1.addElement("language"); Element country1 = book1.addElement("country"); book1.addAttribute("id", "1"); name1.setText("一生有你"); author1.setText("午歌"); price1.setText("25"); language1.setText("chinese"); country1.setText("china"); OutputFormat format = OutputFormat.createPrettyPrint(); format.setIndent(" "); format.setEncoding("UTF-8"); XMLWriter writer = null; try { writer = new XMLWriter(new FileOutputStream(uri),format); writer.write(doc); } catch (IOException e) { e.printStackTrace(); } } }
class Book { private String id ; private String name ; private String author ; private String price ; private String language ; private String country ; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
|
结果
queryDom4jXMLDemo 的结果:
1 2
| id:1 name:changedName author:college-English price:55 language:english country:2 id:2 name:cet6 author:me price:33 language:lalalal country:chinese
|
从结果中可以看出,在解析XML 文件时,他是将元素返回为对象,再通过获取对象的值从而获得数据。
我在代码中使用了内部类的方式接受传回来的数据,这样保存数据会方便很多,不过需要即用即销。
insertDom4jXMLDemo的结果:
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" encoding="UTF-8"?> <bookstore> <book id="1"> <name>一生有你</name> <author>午歌</author> <price>25</price> <language>chinese</language> <country>china</country> </book> </bookstore>
|
结果显示的很完美,doc树正常显示,格式也没有问题。
Jdom 解析XML
简介
Jdom 只是一种适合Java程序员来使用的Java XML API。
要用Jdom进行开发,需要到jar包,因为是开源的,所以GitHub上也有,
代码
解析代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
| package com.vgbh;
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List;
import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter;
public class JdomXMLDemo {
public static void main(String[] args) { JdomXMLDemo jxd = new JdomXMLDemo(); String uri = "bookstore.xml"; String uri1 = "F:/WorkSpace/JdomDemoD.xml"; jxd.updateJdomXMLDemo(uri,"0"); } public void insertJdomXMLDemo (String uri) { Element bookstore = new Element("bookstore"); Element book = new Element("book"); Element name = new Element("name"); Element author = new Element("author"); Element price = new Element("price"); Element language = new Element("language"); Element country = new Element("country"); Document doc = new Document(bookstore); name.setText("names"); author.setText("authors"); price.setText("prices"); language.setText("languages"); country.setText("countrys"); book.addContent(name); book.addContent(author); book.addContent(price); book.addContent(language); book.addContent(country); bookstore.addContent(book); Format format = Format.getCompactFormat(); format.setEncoding("UTF-8"); format.setIndent(" "); XMLOutputter XMLOut = new XMLOutputter(); try { XMLOut.output(doc, new FileOutputStream(uri)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } System.out.println("写入成功!"); } public void queryJdomXMLDemo (String uri) { try { SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(uri); Element book = doc.getRootElement(); List list = book.getChildren("book"); for (int i = 0; i < list.size(); i++) { Element e = (Element) list.get(i);
System.out.println("name:" + e.getChildText("name") + " author:" + e.getChildText("author") + " price:" + e.getChildText("price") + " lanuage:" + e.getChildText("language") + " country:" + e.getChildText("country")); } } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void updateJdomXMLDemo (String uri, String id) { try { SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(uri); Element book = doc.getRootElement(); List list = book.getChildren("book"); for (int i = 0; i < list.size(); i++) { if (String.valueOf(i).equals(id)) { Element e = (Element) list.get(i);
Element name = e.getChild("name"); name.setText("xiugaiguode "); System.out.println("name:" + e.getChildText("name") + " author:" + e.getChildText("author") + " price:" + e.getChildText("price") + " lanuage:" + e.getChildText("language") + " country:" + e.getChildText("country")); } }
Format format = Format.getCompactFormat(); format.setEncoding("UTF-8"); format.setIndent(" "); XMLOutputter XMLOut = new XMLOutputter(); XMLOut.output(doc, new FileOutputStream(uri)); System.out.println("修改成功!"); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
|
Digester
使用步骤
- 创建一个org.apache.commons.digester3.Digester 类的实例对象。(补充说明一下,只要我们完成了XML 解析操作,并且不是在多个线程中使用同一个Digester 对象,那么就可以安全的重复使用我们创建的这个Digester ,不过从用Digester 并不是很推荐,最好每一个XML 解析对应一个单独的Digester 实例)
- 为Digester 配置属性值,通过配置属性值,我们可以改变Digester 的解析行为。(具体配置哪些属性、如何配置)
- 可以将我们创建的初始对象push 到Digester 栈里。
- 在输入的XML 文档中,给我们所有需要出发的规则(rule )处理需要的元素匹配模式(pattern )注册规则。针对任何一个模式,可以注册任意数量的规则。(如果一个模式对应多个规则,则begin 和body 事件方法会按照他们注册的顺序依次执行,而end 事件方法是倒序执行的)
- 最后,调用Digester.parse() 方法,该方法需要传入XML 文件的应用作为参数,该参数支持多种格式的文件流。(该方法会抛出IOException or SAXException 异常,以及各种在解析规则处理时遇到的异常,如NoSuchMethodException、 IllegalAccessException)
简单示例
将要解析的XML 文件
1 2 3 4 5
| <foo name="The Parent"> <bar id="123" title="The First Child" /> <bar id="456" title="The Second Child" /> <bar id="789" title="The Second Child" /> </foo>
|
创建Java Bean 对应XML 文件中的元素信息
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package cn.vgbhfive.digesterTest.pojo;
import java.util.ArrayList; import java.util.Iterator; import java.util.List;
public class Foo { private String name; private List<Bar> barList = new ArrayList<Bar>();
public void addBar(Bar bar) { barList.add(bar); }
public Bar findBar(int id) { for (Bar bar : barList) { if (bar.getId() == id) { return bar; } } return null; }
public Iterator<Bar> getBars() { return barList.iterator(); }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<Bar> getBarList() { return barList; }
public void setBarList(List<Bar> barList) { this.barList = barList; }
}
|
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package cn.vgbhfive.digesterTest.pojo;
public class Bar {
private int id; private String title;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; } }
|
使用Digester 解析XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package cn.vgbhfive.digesterTest;
import java.io.IOException;
import org.apache.commons.digester3.Digester; import org.xml.sax.SAXException;
import apache.commons.digester3.example.pojo.Bar; import apache.commons.digester3.example.pojo.Foo;
public class Main {
public static void main(String[] args) {
try { Digester digester = new Digester();
digester.setValidating(false);
digester.addObjectCreate("foo", "cn.vgbhfive.digesterTest.pojo.Foo"); digester.addSetProperties("foo"); digester.addObjectCreate("foo/bar", "cn.vgbhfive.digesterTest.pojo.Bar"); digester.addSetProperties("foo/bar"); digester.addSetNext("foo/bar", "addBar", "cn.vgbhfive.digesterTest.pojo.Bar");
Foo foo = digester.parse(Main.class.getClassLoader().getResourceAsStream("example.xml"));
System.out.println(foo.getName()); for (Bar bar : foo.getBarList()) { System.out.println(bar.getId() + "," + bar.getTitle()); } } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } } }
|
输出结果
1 2 3 4
| The Parent 123,The First Child 456,The Second Child 789,The Second Child
|
上述代码涉及类型的自动转换,所有的类型转换都是由commons-beanutils 包中的ConverUtils 来完成。
Digester 属性配置
org.apache.commons.digester3.Digester 实例对象包含若干成员属性,这些属性值是可以设置的,以便自定义解析操作。
可以配置的属性:
- classLoader:
- errorHandler:
- namespaceAware:
- xincludeAware:
- ruleNamespaceURL:
- rules:
- useContextClassLoader:
- validating:
为了让配置生效,属性值的更改一定要在parse方法调用之前设置。
当Digester 遇到DOCTYPE 声明时,可以使用本地dtd 文件。
Digester 对象栈
Digester 使用的一个核心技术就是动态构建一颗Java 对象树,在构建的过程中,最重要的辅助数据结构即对象栈。
以简单示例的XML 为例:
首先会创建一个Foo 对象,并压入对象栈,然后设置Foo 的属性值name,紧接着创建Bar 对象并压入栈,然后设置Bar 的属性值,然后将该Bar 对象添加的到Foo 对象的barlist 属性集合中,然后Bar 对象弹出对象栈。
以此类推,遇到起始标记的元素创建对象入栈,遇到结尾标记的元素做出栈操作,出栈前,需要将出栈对象并关联到上一个栈顶对象。
最终,解析完XML 后,留在栈顶的就关联了所有在xml解析中创建的动态对象。
Digester暴露出的与对象栈操作API如下所示:
- clear(): 清除对象栈。
- peek(): 返回栈顶对象引用,但是不弹出。
- pop(): 返回栈顶对象,并弹出。
- push(): 入栈操作。
Digester 元素匹配模式
Digester 的一个关键特性是可以自动识别xml的层次结构,程序员只需要关心遇到匹配到某个元素后需要做哪些操作即可。
1 2 3 4 5 6 7 8 9 10 11
| <a> -- Matches pattern "a" <b> -- Matches pattern "a/b" <c/> -- Matches pattern "a/b/c" <c/> -- Matches pattern "a/b/c" </b> <b> -- Matches pattern "a/b" <c/> -- Matches pattern "a/b/c" <c/> -- Matches pattern "a/b/c" <c/> -- Matches pattern "a/b/c" </b> </a>
|
Digester 规则处理
当匹配到模式时,会触发规则处理,具体的规则处理机制是由org.apache.commons.digester3.Rule 接口封装的实现类处理。
Rule 接口定义的方法:
- begin(): 匹配到xml元素开始标记时,调用该方法。
- body(): 匹配到xml元素body时,调用该方法。
- end(): 匹配到xml元素结束标记时,调用该方法。
- finish(): 当所有解析方法解析完毕后,调用该方法,用于清楚临时数据等。
Digester 提供的实现Rule 接口的实现类:
- ObjectCreateRule
- FactoryCreateRule
- SetPropertiesRule
- SetPropertyRule
- SetNextRule
- SetTopRule
- CallMethodRule
- CallParamRule
- NodeCreateRule
详细内容请见官方API 文档。
Digester 日志
日志是调试、排查错误非常关键的一个环节,Digester 记录了非常详细的日志,我们可以按如下方式来开启日志打印功能。
pom.xml 添加依赖
1 2 3 4 5
| <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
|
log4j 配置文件log4j.properties
1 2 3 4 5 6 7 8
| ### set log levels ### log4j.rootLogger = debug, stdout
### \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
|
DEBUG 日志
1 2 3 4 5 6 7 8 9 10
| 2017-06-04 18:26:33 [ main:51 ] - [ DEBUG ] Fire body() for SetPropertiesRule[aliases={}, ignoreMissingProperty=true] 2017-06-04 18:26:33 [ main:51 ] - [ DEBUG ] Popping body text '' 2017-06-04 18:26:33 [ main:51 ] - [ DEBUG ] Fire end() for SetPropertiesRule[aliases={}, ignoreMissingProperty=true] 2017-06-04 18:26:33 [ main:52 ] - [ DEBUG ] Fire end() for ObjectCreateRule[className=apache.commons.digester3.example.pojo.Foo, attributeName=null] 2017-06-04 18:26:33 [ main:52 ] - [ DEBUG ] [ObjectCreateRule]{foo} Pop 'apache.commons.digester3.example.pojo.Foo' 2017-06-04 18:26:33 [ main:52 ] - [ DEBUG ] endDocument() The Parent 123,The First Child 456,The Second Child 789,The Second Child
|
实例开发
XML 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <web-app> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>application</param-name> <param-value>org.apache.struts.example.ApplicationResources</param-value> </init-param> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> </servlet> </web-app>
|
Java Bean 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.util.HashMap; import java.util.Map;
public class ServletBean {
private String servletName; private String servletClass; private Map<String, String> initParams = new HashMap<String, String>(); public void addInitParam(String paramName, String paramValue) { initParams.put(paramName, paramValue); }
public String getServletName() { return servletName; }
public void setServletName(String servletName) { this.servletName = servletName; }
public String getServletClass() { return servletClass; }
public void setServletClass(String servletClass) { this.servletClass = servletClass; }
public Map<String, String> getInitParams() { return initParams; }
public void setInitParams(Map<String, String> initParams) { this.initParams = initParams; } }
|
编写规则解析XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import java.io.IOException;
import org.apache.commons.digester3.Digester; import org.apache.commons.digester3.Rule; import org.apache.commons.digester3.SetNextRule; import org.xml.sax.SAXException;
import apache.commons.digester3.example.pojo.Bar; import apache.commons.digester3.example.pojo.Foo; import apache.commons.digester3.example.pojo.ServletBean;
public class WebMain {
public static void main(String[] args) { try { Digester digester = new Digester();
digester.setValidating(false);
digester.addObjectCreate("web-app/servlet", "apache.commons.digester3.example.pojo.ServletBean"); digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0); digester.addCallMethod("web-app/servlet/servlet-class", "setServletClass", 0); digester.addCallMethod("web-app/servlet/init-param", "addInitParam", 2); digester.addCallParam("web-app/servlet/init-param/param-name", 0); digester.addCallParam("web-app/servlet/init-param/param-value", 1);
ServletBean servletBean = digester .parse(ExampleMain.class.getClassLoader().getResourceAsStream("web.xml"));
System.out.println(servletBean.getServletName()); System.out.println(servletBean.getServletClass()); for(String key : servletBean.getInitParams().keySet()){ System.out.println(key + ": " + servletBean.getInitParams().get(key)); }
} catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } } }
|
输出结果
1 2 3 4
| action org.apache.struts.action.ActionServlet application: org.apache.struts.example.ApplicationResources config: /WEB-INF/struts-config.xml
|
错误排查
Digester 是基于SAX 开发的. Digestion 会抛出两种类型的Exception:
- java.io.IOException
- org.xml.sax.SAXException
一般情况下SAXException 异常内部会组合另一个异常,换句话说,就是当Digester 遇到异常的时候,会首先将该异常封装成一个SAXException 异常,然后将该SAXException 重新抛出。所以在捕获SAXException 异常,并仔细检查被封装的内部异常,有助于排查错误;
参考资料
https://blog.csdn.net/qq_36594739 (这是我以前的博客)
http://commons.apache.org/proper/commons-digester/guide/core.html
https://www.cnblogs.com/chenpi/p/6930730.html
个人备注
此博客内容均为作者学习所做笔记,侵删!
若转作其他用途,请注明来源!