通常用來讀取xml文件的工具包有DOM、SAX和JDOM等,但用過的人都知道,它們屬於比較底層的API,寫起來代碼量很大,並且若是修改了xml文件的格式,代碼也要作大幅度的改動。而使用Apache Jakarta的Digester,解析XML文件很是方便且不須要過多的關心底層的具體解析過程。Digester原本僅僅是Jakarta Struts中的一個工具,用於處理struts-config.xml配置文件。顯然,將XML文件轉換成相應的Java對象是一項很通用的功能,這個工具理應具備更普遍的用途,因此很快它就在Jakarta Commons項目(用於提供可重用的Java組件庫)中有了一席之地。Digester由"事件"驅動,經過調用預約義的規則操做對象棧,將XML文件轉換爲Java對象。html
工做原理以下: Digester底層採用SAX(Simple API for XML)析XML文件,因此很天然的,對象轉換由"事件"驅動,在遍歷每一個節點時,檢查是否有匹配模式,若是有,則執行規則定義的操做,好比建立特定的Java對象,或調用特定對象的方法等。此處的XML元素根據匹配模式(matching pattern)識別,而相關操做由規則(rule)定義。java
1.addObjectCreate(String rule,Class class)web
設置節點與Java對象的映射規則,rule指定節點的篩選規則,class設置映射對象。SAX解析時,遇到rule指定的節節點,會建立一個class實例放入堆棧中。apache
好比:digester.addObectCreate("database/user","com.model.UserBean").解析遇到user節點時,會建立一個UserBean實例並放入堆棧中。api
2.addSetProperties(String rule)工具
設置節點的屬性設置規則。當解析遇到符合rule的節點時,根據屬性列表中的屬性值對,使用Java反射機制使用標準的JavaBean方法設置棧頂對象實例;this
好比:digester.addSetProperties("database/user"),解析遇到user節點時,會獲取鍵值對 userName=guest,password=guest,得到棧頂的UserBean對象,設置實例的userName、password屬性;編碼
3.addBeanPropertySetter(String rule)spa
該方法的做用及使用方法相似於addSetProperties,只不過它是用rule所指定的標籤來調用對象的setter。.net
4.addSetNext(String rule,String methodName)
設置當前rule節點與父節點的調用規則,當遇到rule節點時,調用堆棧中的次棧頂元素調用methodName方法。將棧頂元素做爲次頂元素指定方法的輸入參數。
好比:digester.addSetNext("database/user","addUser"),調用database實例的addUser,user爲參數
5.addCallMethod(String rule,String methodName,int paraNumber)
該方法一樣設置對象的屬性,但更加靈活,不須要對象具備setter
根據rule規則指定的屬性,調用對象的methodName方法,paraNumber參數是表示方法須要的參數個數,當paraNumber=0時,能夠單獨使用,否則須要配合addCallParam方法
好比:digester.addCallMethod("database/user/userName","setUserName",0), 參數爲xml當前值;無參方法:digester.addCallMethod( "pattern", "methodName" );.
6.addCallParam(String rule,int paraIndex,String attributeName)
該方法與addCallMethod配合使用,根據rule指定的標籤屬性來調用方法
paraIndex代表須要填充的方法形參序號,從0開始,方法由addCallMethdo指定,attributeName指定標籤屬性名;
使用注意事項:
1.Digester類調用的順序,必須與XML數據文件絕對一致;
2.Digester類依賴於JavaBean規範,類必須符合規範;
3.XML文件中標籤/屬性的名稱必須與Bean中的一致(包括大小寫);
//--webconfig.xml--
<?xml version="1.0" encoding="UTF-8"?>
<web>
<root name = "root_name1">
<bar id="0" title="The Zero Child"/>
<bar id="123" title="The First Child"/>
<bar id="456" title="The Second Child"/>
</root>
<root name = "root_name2">
<bar id="789" title="Another Child"/>
</root>
</web>
Digest |
|
Digester digester = new Digester(); |
新建一個類 |
digester.setValidating(false); |
是否進行XML與相應的DTD的合法性驗證(此處爲false) |
digester.addObjectCreate("root", "Root"); |
當遇到<root>時建立一個Root對象,並將其放在棧頂 |
digester.addSetProperties("root"); |
根據<root>元素的屬性(attribute),對剛建立的Root對象的屬性(property)進行設置 |
digester.addObjectCreate("root/bar", "Bar"); |
當遇到<root>的子元素<bar>時建立一個Bar對象,並將其放在棧頂。 |
digester.addSetProperties("root/bar"); |
根據<bar>元素的屬性(attribute),對剛建立的Bar對象的屬性(property)進行設置 |
digester.addSetNext("root/bar", "addBar", "Bar"); |
當再次遇到<root>的子元素<bar>時建立一個Bar對象,並將其放在棧頂,同時調用第二棧頂元素(Root對象)的addBar方法。 |
digester.parse(); |
進行解析,獲得的是Object |
以下xml代碼,右邊是左邊元素對應的匹配模式:
- <datasources> 'datasources'
- <datasource> 'datasources/datasource'
- <name/> 'datasources/datasource/name'
- <driver/> 'datasources/datasource/driver'
- </datasource>
- <datasource> 'datasources/datasource'
- <name/> 'datasources/datasource/name'
- <driver/> 'datasources/datasource/driver'
- </datasource>
- </datasources>
例子1:
下面介紹解析xml文件的代碼
下面是存放地址及編碼的xml文件viewcache.xml(片斷):
- <?xml version="1.0" encoding="UTF-8" ?>
- <viewcache>
- <areas>
- <area>
- <id>1098</id>
- <parentId>1001</parentId>
- <areaType>province</areaType>
- <name>北京</name>
- <ordering>1867</ordering>
- </area>
- <area>
- <id>1099</id>
- <parentId>1098</parentId>
- <areaType>capital</areaType>
- <name>北京</name>
- <ordering>1868</ordering>
- <phoneArea>010</phoneArea>
- </area>
- <area>
- <id>4476</id>
- <parentId>1099</parentId>
- <areaType>county</areaType>
- <name>北京市朝陽區</name>
- <ordering>1869</ordering>
- <phoneArea>010</phoneArea>
- </area>
- <area>
- <id>4477</id>
- <parentId>1099</parentId>
- <areaType>county</areaType>
- <name>北京市崇文區</name>
- <ordering>1870</ordering>
- <phoneArea>010</phoneArea>
- </area>
- <area>
- <id>4478</id>
- <parentId>1099</parentId>
- <areaType>county</areaType>
- <name>北京市大興區</name>
- <ordering>1871</ordering>
- <phoneArea>010</phoneArea>
- </area>
- </areas>
- </viewcache>
此xml文件分3層結構,分別爲:
<viewcache>節點 其下包含1個<areas>節點
<areas>節點 其下包含多個<area>節點
<area>節點,其下包含各類信息節點 : 如:<id> 、<name>等。
咱們的操做目標是把area中的信息節點的內容提取出來。
把每一個<arrea>看作爲一個對象,<area>中信息節點的內容爲對象中的元素。
設定一個類Area.java 其內容以下:
- public class Area {
- private int id;
- private String name;
- private String areaType;
- private int parentId;
- private int ordering;
- private String zip;
-
- private String phoneArea;
-
- public int getOrdering() {
- return ordering;
- }
- public void setOrdering(int ordering) {
- this.ordering = ordering;
- }
- public String getAreaType() {
- return areaType;
- }
- public void setAreaType(String areaType) {
- this.areaType = areaType;
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getParentId() {
- return parentId;
- }
- public void setParentId(int parentId) {
- this.parentId = parentId;
- }
-
- public String getZip() {
- return zip;
- }
-
- public void setZip(String zip) {
- this.zip = zip;
- }
-
- public String getPhoneArea() {
- return phoneArea;
- }
-
- public void setPhoneArea(String phoneArea) {
- this.phoneArea = phoneArea;
- }
- }
建立一個ViewCache類,用來保存解析後的全部對象:
- public class ViewCache {
- private List areaList = new ArrayList();
- public List getAreaList() {
- return areaList;
- }
- public void setAreaList(List areaList) {
- this.areaList = areaList;
- }
-
-
- public void addArea(Area area) {
- this.areaList.add(area);
- }
- }
建立一個類AreaDigester,對xml文件進行解析:
- public class AreaDigester {
-
- public ViewCache digester() throws Exception {
- Digester digester = new Digester();
- digester.setValidating(false);
- //addObjectCreate:當碰到第一個參數的節點時建立類型爲第二個參數的對象並壓入棧中
- digester.addObjectCreate("viewcache/areas", ViewCache.class);
-
- digester.addObjectCreate("viewcache/areas/area", Area.class);
-
- digester.addBeanPropertySetter("viewcache/areas/area/id", "id");
- digester.addBeanPropertySetter("viewcache/areas/area/parentId", "parentId");
- digester.addBeanPropertySetter("viewcache/areas/area/name", "name");
- digester.addBeanPropertySetter("viewcache/areas/area/areaType", "areaType");
- digester.addBeanPropertySetter("viewcache/areas/area/ordering", "ordering");
- digester.addBeanPropertySetter("viewcache/areas/area/zip", "zip");
- digester.addBeanPropertySetter("viewcache/areas/area/phoneArea", "phoneArea");
-
- digester.addSetNext("viewcache/areas/area", "addArea");
-
- ViewCache vc = null;
- try {
- vc = (ViewCache) digester.parse("viewcache.xml");
- } catch (IOException e) {
- throw new Exception(e);
- } catch (SAXException e) {
- throw new Exception(e);
- }
- return vc;
- }
- }
調用AreaDigester的digester方法,便可把解析後的全部地址對象,存放在ViewCache的list中。
例子2:
要解析的xml文件books.xml以下:
- <?xml version="1.0" encoding="UTF-8" ?>
- <library name="alibaba圖書館">
- <book title ="thinking in java" author="xxx">
- <chapter>
- <no>第一章</no>
- <caption>第一章的標題</caption>
- </chapter>
- <chapter>
- <no>第二章</no>
- <caption>第二章的標題</caption>
- </chapter>
- </book>
- <book title="effective java" author="yyy">
- <chapter>
- <no>第一章</no>
- <caption>第一章的標題</caption>
- </chapter>
- </book>
- </library>
Library類以下:
- public class Library {
- private String name;
- private List<Book> bookList = new ArrayList<Book>();
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public List<Book> getBookList() {
- return bookList;
- }
-
- public void addBook(Book book) {
- bookList.add(book);
- }
- }
Book類以下:
- public class Book {
-
- private String title;
- private String author;
- private List<Chapter> chapters = new ArrayList<Chapter>();
-
-
- public void setBookInfo(String title, String author) {
- this.title = title;
- this.author = author;
- }
-
- public void addChapter(Chapter chapter) {
- this.chapters.add(chapter);
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getAuthor() {
- return author;
- }
-
- public void setAuthor(String author) {
- this.author = author;
- }
-
- public List<Chapter> getChapters() {
- return chapters;
- }
-
- public void setChapters(List<Chapter> chapters) {
- this.chapters = chapters;
- }
- }
Chapter類以下:
- public class Chapter {
-
- private String no;
- private String caption;
-
- public String getNo() {
- return no;
- }
-
- public void setNo(String no) {
- this.no = no;
- }
-
- public String getCaption() {
- return caption;
- }
-
- public void setCaption(String caption) {
- this.caption = caption;
- }
- }
解析xml的類以下:
- public class MainTest {
-
-
- public static void main(String[] args) {
-
- Digester digester = new Digester();
-
- digester.setValidating(false);
-
- digester.addObjectCreate("library", Library.class);
-
- digester.addSetProperties("library");
-
-
-
-
- digester.addObjectCreate("library/book", Book.class);
-
-
- digester.addCallMethod("library/book", "setBookInfo", 2);
- digester.addCallParam("library/book", 0, "title");
- digester.addCallParam("library/book", 1, "author");
-
-
-
-
- digester.addObjectCreate("library/book/chapter", Chapter.class);
-
- digester.addBeanPropertySetter("library/book/chapter/no");
-
-
-
-
-
- digester.addCallMethod("library/book/chapter/caption", "setCaption", 0);
-
-
- digester.addSetNext("library/book/chapter", "addChapter");
-
-
- digester.addSetNext("library/book", "addBook");
-
-
- try {
-
- Library library = (Library) digester.parse(MainTest.class.getResourceAsStream("books.xml"));
- System.out.println(" 圖書館: " + library.getName());
- System.out.println(" 共藏書: " + library.getBookList().size() + " 本 ");
- System.out.println(" ***************************** ");
-
- for (Book book : library.getBookList()) {
- System.out.println(" 書名: " + book.getTitle() + " 做者: " + book.getAuthor());
- System.out.println(" ------------------------------ ");
-
- System.out.println(" 共 " + book.getChapters().size() + " 章 ");
- for (Chapter chapter : book.getChapters()) {
- System.out.println(chapter.getNo() + ": " + chapter.getCaption());
- }
- System.out.println(" ------------------------------ ");
- }
- } catch (IOException e) {
- e.printStackTrace();
- } catch (SAXException e) {
- e.printStackTrace();
- }
- }
- }
例子3:
Digester解析xml的規則,除了在java類中描述設置以外,還能夠把解析規則放在xml文件中。以例子2中的代碼爲例,規則在books-rule.xml文件中,內容以下:(The DTD is distributed in the commons-digester.jar
. It can be found at org/apache/commons/digester/xmlrules/digester-rules.dtd,經過查看DTD文件,能夠知道有哪些標籤可使用
)
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE digester-rules PUBLIC
- "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"
- "digester-rules.dtd">
- <digester-rules>
- <object-create-rule pattern="library" classname="com.alibaba.chj.digester.Library" />
- <set-properties-rule pattern="library">
- <alias attr-name="name" prop-name="name" />
- </set-properties-rule>
- <pattern value="library/book">
- <object-create-rule classname="com.alibaba.chj.digester.Book" />
- <set-properties-rule />
- <pattern value="chapter">
- <object-create-rule classname="com.alibaba.chj.digester.Chapter" />
- <bean-property-setter-rule pattern="no" propertyname="no" />
- <bean-property-setter-rule pattern="caption" propertyname="caption" />
- <set-next-rule methodname="addChapter" />
- </pattern>
- <set-next-rule methodname="addBook" />
- </pattern>
- </digester-rules>
解析xml類的代碼,修改成:
- public class MainTest {
-
-
- public static void main(String[] args) {
- try {
- Digester digester = DigesterLoader.createDigester(DigesterXmlRuleTest.class.getResource("books-rule.xml"));
- Library library = (Library) digester.parse(DigesterXmlRuleTest.class.getResourceAsStream("books.xml"));
- System.out.println(" 圖書館: " + library.getName());
- System.out.println(" 共藏書: " + library.getBookList().size() + " 本 ");
- System.out.println(" ***************************** ");
-
- for (Book book : library.getBookList()) {
- System.out.println(" 書名: " + book.getTitle() + " 做者: " + book.getAuthor());
- System.out.println(" ------------------------------ ");
-
- System.out.println(" 共 " + book.getChapters().size() + " 章 ");
- for (Chapter chapter : book.getChapters()) {
- System.out.println(chapter.getNo() + ": " + chapter.getCaption());
- }
- System.out.println(" ------------------------------ ");
- }
- } catch (IOException e) {
- e.printStackTrace();
- } catch (SAXException e) {
- e.printStackTrace();
- }
- }
- }
用於規則放在xml文件中,因此解析的類,顯得更加簡潔一些。