xml總結(六)dom4j,xml處理技術比較

dom4j(Version 1.6.1)快速入門

Parsing XML

或許你想要做的第一件事情就是解析一個某種類型的XML文檔,用dom4j很容易做到。請看下面的示範代碼:

import java.net.URL;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

public class Foo {

public Document parse(URL url) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(url);
return document;
}
}

使用迭代器(Iterators)

我們可以通過多種方法來操作XML文檔,這些方法返回java裏標準的迭代器(Iterators)。例如:

public void bar(Document document) throws DocumentException {
Element root = document.getRootElement();
//迭代根元素下面的所有子元素
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
Element element = (Element) i.next();
//處理代碼
}

//迭代根元素下面名稱爲"foo"的子元素
for ( Iterator i = root.elementIterator( "foo" ); i.hasNext(); ) {
Element foo = (Element) i.next();
//處理代碼
}

// 迭代根元素的屬性attributes)元素
for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
Attribute attribute = (Attribute) i.next();
// do something
}
}

強大的XPath導航

在dom4j中XPath可以表示出在XML樹狀結構中的Document或者任意的節點(Node)(例如:Attribute,Element 或者 ProcessingInstruction等)。它可以使在文檔中複雜的操作僅通過一行代碼就可以完成。例如:

public void bar(Document document) {
List list = document.selectNodes( "//foo/bar" );

Node node = document.selectSingleNode( "//foo/bar/author" );

String name = node.valueOf( "@name" );
}

如果你想得到一個XHTML文檔中的所有超文本鏈接(hypertext links)你可以使用下面的代碼:

public void findLinks(Document document) throws DocumentException {

List list = document.selectNodes( "//a/@href" );

for (Iterator iter = list.iterator(); iter.hasNext(); ) {
Attribute attribute = (Attribute) iter.next();
String url = attribute.getValue();
}
}

如果你需要關於XPath語言的任何幫助,我們強烈推薦這個站點Zvon tutorial他會通過一個一個的例子引導你學習。

快速遍歷(Fast Looping)


如果你不得不遍歷一個非常大的XML文檔,然後纔去執行,我們建議你使用快速遍歷方法(fast looping method),它可以避免爲每一個循環的節點創建一個迭代器對象,如下所示:

public void treeWalk(Document document) {
treeWalk( document.getRootElement() );
}

public void treeWalk(Element element) {
for ( int i = 0, size = element.nodeCount(); i < size; i++ ) {
Node node = element.node(i);
if ( node instanceof Element ) {
treeWalk( (Element) node );
}
else {
// do something....
}
}
}

生成一個新的XML文檔對象

在dom4j中你可能常常希望用程序生成一個XML文檔對象,下面的程序爲你進行了示範:

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class Foo {

public Document createDocument() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement( "root" );

Element author1 = root.addElement( "author" )
.addAttribute( "name", "James" )
.addAttribute( "location", "UK" )
.addText( "James Strachan" );

Element author2 = root.addElement( "author" )
.addAttribute( "name", "Bob" )
.addAttribute( "location", "US" )
.addText( "Bob McWhirter" );

return document;
}
}

將一個文檔對象寫入文件中

將一個文檔對象寫入Writer對象的一個簡單快速的途徑是通過write()方法。

FileWriter out = new FileWriter( "foo.xml" );
document.write( out );

如果你想改變輸出文件的排版格式,比如你想要一個漂亮的格式或者是一個緊湊的格式,或者你想用Writer 對象或者OutputStream 對象來操作,那麼你可以使用XMLWriter 類。

import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

public class Foo {

public void write(Document document) throws IOException {

// 寫入文件
XMLWriter writer = new XMLWriter(
new FileWriter( "output.xml" )
);
writer.write( document );
writer.close();


// 以一種優雅的格式寫入System.out對象
OutputFormat format = OutputFormat.createPrettyPrint();
writer = new XMLWriter( System.out, format );
writer.write( document );

// 以一種緊湊的格式寫入System.out對象
format = OutputFormat.createCompactFormat();
writer = new XMLWriter( System.out, format );
writer.write( document );
}
}

轉化爲字符串,或者從字符串轉化

如果你有一個文檔(Document)對象或者任何一個節點(Node)對象的引用(reference),象屬性(Attribute)或者元素(Element),你可以通過asXML()方法把它轉化爲一個默認的XML字符串:

Document document = ...;
String text = document.asXML();

如果你有一些XML內容的字符串表示,你可以通過DocumentHelper.parseText()方法將它重新轉化爲文檔(Document)對象:

String text = " James ";
Document document = DocumentHelper.parseText(text);

通過XSLT樣式化文檔(Document)


使用Sun公司提供的JAXP API將XSLT 應用到文檔(Document)上是很簡單的。它允許你使用任何的XSLT引擎(例如:Xalan或SAXON等)來開發。下面是一個使用JAXP創建一個轉化器(transformer),然後將它應用到文檔(Document)上的例子:

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import org.dom4j.Document;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;

public class Foo {

public Document styleDocument(
Document document,
String stylesheet
) throws Exception {

// 使用 JAXP 加載轉化器
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(
new StreamSource( stylesheet )
);

// 現在來樣式化一個文檔(Document)
DocumentSource source = new DocumentSource( document );
DocumentResult result = new DocumentResult();
transformer.transform( source, result );

// 返回經過樣式化的文檔(Document)
Document transformedDoc = result.getDocument();
return transformedDoc;
}
}

 <hr>

XML 技術是隨着 Java 的發展而發展起來的。在 XML 出現之前對於簡單的數據格式通常是存儲在 ini 配置文件等文本文件中,複雜的格式則採用自定義的文件格式,因此對於每種文件格式都要有專門的解析程序。 XML 出現以後解決了這個問題,程序面對的是有固定格式的 XML 文件,只要通過標準 API 就可以進行 XML 文件的處理。

XML 文件在案例系統中應用是很廣泛的,比如 ClientConfig.xml ServerConfig.xml 文件就是使用 XML 文件來做配置文件的,元數據文件以及元數據加載器更是離不開 XML 。因此本章將系統講解一下 XML 文件的處理技術。

1.1    XML處理技術比較

Java 領域 XML 文件的技術大致分爲兩類: XML API OXMapping XML API XML 處理的基礎,可選技術包括 JDOM Dom4j 等; OXMapping Object-XML Mapping 的簡稱,這種技術隱藏了 XML 底層操作的細節,可以將 XML 文件映射成一個 JavaBean 對象,也可以把一個 JavaBean 對象保存成一個 XML 文件,可選技術 XStream Digester Castor 等。 XML API OXMapping 的關係類似於 JDBC ORMaping 的關係, OXMapping 內部實現使用 XML API 來完成,兩種實現技術從不同的層面實現了 XML 的處理。

XML API

此類 XML 處理技術中最流行的莫過於 JDOM Dom4j 了,二者的使用方式非常相似。不過 Dom4j 的優勢比 JDOM 更明顯一些:

Dom4j 大量的使用接口,這使得 Dom4j Dom4j 更加靈活和具有可擴展性;

Dom4j 的性能表現比 JDOM 好;

Dom4j 支持 XPath 等高級特性;

正是由於這些優點,很多開源項目都開始使用 Dom4j XML 解析技術,本書也將使用 Dom4j 做爲 XML 處理的首選。

OXMapping

使用 XML API 解析是略顯煩瑣的,受 ORMapping 技術的啓發,人們發明了 OXMapping 技術,使用 OXMapping 技術,我們可以將 XML 文件映射成一個 JavaBean 對象,也可以把一個 JavaBean 對象保存成一個 XML 文件,這大大簡化了我們的開發工作量,使得開發人員能更多的關注應用層面的東西。

開源世界中涌現出很多 OXMapping 框架,包括 XStream Digester Castor 等。 XStream Digester 把映射的過程在代碼中完成,而 Castor 則需要寫一個和 Hibernate cfg.xml 類似的映射配置文件。與 Digester 比起來, XStream 的主要優點就是更加小巧,使用也更加方便,不過目前使用 Digester 是“開源名牌” Apache 下的子項目,網上可以參考的資料也比 XStream 多,好在 XStream 比較簡潔,所以並不會對 XStream 造成太大影響。

http://www.blogjava.net/huanzhugege/

1.2    Dom4j的使用

Dom4j 是一個易用的、開源的庫,用於 XML XPath XSLT 。它應用於 Java 平臺,採用了 Java 集合框架並完全支持 DOM SAX JAXP Dom4j sourceforge.net 上的一個開源項目,地址爲 http://sourceforge.net/projects/dom4j

Dom4j 裏基於接口編程是一個非常顯著的優點,下面是其主要的接口的繼承體系結構圖:

5 . 1

這些接口大部分都是定義在包 org.dom4j 中,下面簡單介紹各個接口的意義:

5 . 1 Dom4j 主要接口

Node

Node 爲是 dom4j 中所有的 XML 節點的基類型接口

Attribute

Attribute 定義了 XML 的屬性

Branch

Branch 爲能夠包含子節點的節點如 XML 元素 (Element) 和文檔 (Docuemnts) 定義了一個公共的行爲

Document

定義了 XML 文檔

Element

Element 定義 XML 元素

DocumentType

DocumentType 定義 XML DOCTYPE 聲明

Entity

Entity 定義 XML entity

CharacterData

CharacterData 是一個標識藉口,標識基於字符的節點。如 CDATA Comment, Text

CDATA

CDATA 定義了 XML CDATA 區域

Comment

Comment 定義了 XML 註釋的行爲

Text

Text 定義 XML 文本節點

ProcessingInstruction

ProcessingInstruction 定義 XML 處理指令

 

讀取 XML 文件

XML 應用中,最常用的莫過於 XML 文件的解析讀取了, Dom4j 提供了多種讀取 XML 文檔的方式,包括 Dom 樹遍歷、 Visitor 方式和 XPath 方式。

無論哪種方式,我們首先都要根據 xml 文件構造一個 Document 對象:

SAXReader reader = new SAXReader();

Document document = reader.read(new File(fileName));

這裏我們選用了 SAXReader 做爲 XML 讀取器,我們同樣也可以選擇 DOMReader 做爲 XML 讀取器:

SAXReader reader = new DOMReader();

Document document = reader.read(new File(fileName));

其中 reader read 方法有多個重載方法,可以從 InputStream, File, URL 等多種不同的源來讀取 XML 文檔。

1 Dom 樹遍歷

這種讀取方式中把 Dom 看成一個普通的樹,要讀取 XML 中某個節點的值,只要採用數據結構中的樹遍歷算法定位到需要讀取的節點即可。

要便利 Dom 樹,首先要取得樹的根節點:

Element root = document.getRootElement();

取得根節點以後就可以一級一級的向下讀了:

// 遍歷所有子節點

for ( Iterator i = root.elementIterator(); i.hasNext(); )

{

       Element element = (Element) i.next();

       // do something

    }

    // 遍歷名稱爲“ foo ”的節點

for ( Iterator i = root.elementIterator( foo ); i.hasNext();)

{

       Element foo = (Element) i.next();

       // do something

    }

    // 遍歷屬性

for ( Iterator i = root.attributeIterator(); i.hasNext(); )

{

       Attribute attribute = (Attribute) i.next();

       // do something

}

2 Visitor 方式

Dom 樹遍歷是最普通,也是最常用的 XML 讀取方式,其他的 XML 解析引擎,比如 JDom 等,也是使用這種方式進行 XML 的讀取。不過 Dom4j 提供了另外一種讀取方式,那就是 Visitor 方式。這種方式實現了 Visitor 模式,調用者只要編寫一個 Visitor 就可以了。 Visitor 模式使得訪問者易於增加新的操作,同時使訪問者集中相關的操作而分離無關的操作。

編寫的 Visitor 必須實現 org.dom4j.Visitor 接口, Dom4j 還提供了一個 Default Adapter 模式的默認適配器 org.dom4j.VisitorSupport

public class DemoVisitor extends VisitorSupport

{

public void visit(Element element)

{

System.out.println(element.getName());

}

public void visit(Attribute attr)

{

System.out.println(attr.getName());

}

}

然後在要開始遍歷的節點調用此 Visitor 即可:

root.accept(new DemoVisitor ())

此方式需要遍歷所有的節點和元素,因此速度會稍慢一些。

3 XPath 方式

Dom4j 最吸引人的特性莫過於對 XPath 的集成支持了,這個特性並不是所有的 XML 解析引擎都支持的,但是確實一個非常有用的特性。

XPath 是尋址、搜索和匹配文檔的各個部分的語言。它使用路徑標記法來指定和匹配文檔的各個部分,該標記法與文件系統和 URL 中使用的類似。例如, XPath:/x/y/z 搜索文檔的根節點 x ,其下存在節點 y ,其下存在節點 z 。該語句返回與指定路徑結構匹配的所有節點。 /x/y/* 返回父節點爲 x y 節點下的任何節點。 /x/y[@name=a] 匹配所有父節點爲 x y 節點,其屬性稱爲 name ,屬性值爲 a

XPath 大大簡化了 XML 的尋址操作,使用者只要通過匹配表達式告訴引擎要匹配文檔的哪些部分即可,具體的匹配工作由 XPath 引擎來完成。這種方式更加接近於人類的自然思維方式。我們來看一個實際的例子:

有一個 XML 文件記錄了一個部門的基本情況:

<?xml version="1.0" encoding="GB2312"?>

<department>

     <name> 開發部 </name>

     <level>2</level>

     <employeeList>

         <employee number="001" name="Tom" />

         <employee number="002" name="Jim" />

         <employee number="003" name="Lily" />

     </employeeList>

</department>

name 代表部門名稱, level 爲部門的級別, employeeList 下是部門所有的員工列表。下面編寫一個程序讀取此文件並打印出部門的信息。

代碼 5 . 1 XPath 演示

InputStream inStream = null;

try

{

     inStream = Dom4jDemo01.class.getResourceAsStream(

"/com/cownew/Char0502/Department01.xml");

     SAXReader reader = new SAXReader();

     Document doc = reader.read(new InputStreamReader(inStream));

     Node nameNode = doc.selectSingleNode("//department/name");

     System.out.println(" 部門名稱 :" + nameNode.getText());

 

     Node levelNode = doc.selectSingleNode("//department/level");

     System.out.println(" 部門級別 :" + levelNode.getText());

 

     List employeeNodeList = doc

                   .selectNodes("//department/employeeList/employee");

     System.out.println(" 部門下屬僱員 :");

     for (int i = 0, n = employeeNodeList.size(); i < n; i++)

     {

         DefaultElement employeeElement = (DefaultElement) employeeNodeList

                            .get(i);

         String name = employeeElement.attributeValue("name");

         String number = employeeElement.attributeValue("number");

         System.out.println(name + " ,工號 :" + number);

     }

} finally

{

     ResourceUtils.close(inStream);

}

運行結果

部門名稱 : 開發部

部門級別 :2

部門下屬僱員 :

Tom ,工號 :001

Jim ,工號 :002

Lily ,工號 :003

 

使用 XPath 以後,我們只要使用“ //department/name ”這種非常清晰的方式就可以直接定位到具體的節點。 XPath 方式中定位單個節點使用 selectSingleNode 方法,而定位多節點則使用 selectNodes 方法。

案例系統中所有的 XML 文件都是使用 XPath 方式進行解析的,包括 ClientConfig.java ServerConfig.java EntityMetaDataParser.java 等。

XML 文件的創建

Dom4j XML 文件的創建和其他的 XML 引擎類似,首先以 Document 的根節點爲基礎構造出一棵節點樹,然後調用相應的 IO 類庫就可以將 XML 文件保存到適當的介質中了。

下面演示一下生成上文提到的那個部門信息 XML 文件的過程

代碼 5 . 2 XML 創建演示

import java.io.FileWriter;

import java.io.IOException;

 

import org.dom4j.Document;

import org.dom4j.DocumentHelper;

import org.dom4j.Element;

import org.dom4j.io.OutputFormat;

import org.dom4j.io.XMLWriter;

 

public class Dom4jDemo02

{

     public static void main(String[] args)

     {

         // 創建文檔對象

         Document document = DocumentHelper.createDocument();

 

         // 添加根節點 "department"

         Element departElement = document.addElement("department");

 

         // 添加 "name" 節點

         Element departNameElement = DocumentHelper.createElement("name");

         departNameElement.setText(" 開發部 ");

         departElement.add(departNameElement);

 

         // 添加 "level" 節點

         Element departLevelElement = DocumentHelper.createElement("level");

         departLevelElement.setText("2");

         departElement.add(departLevelElement);

 

         // 添加員工列表 "employeeList" 節點

         Element employeeElementList = DocumentHelper

                   .createElement("employeeList");

         departElement.add(employeeElementList);

 

         // 添加員工節點 "employee"

         Element emp1Element = DocumentHelper.createElement("employee");

         emp1Element.addAttribute("number", "001");

         emp1Element.addAttribute("name", "Tom");

         employeeElementList.add(emp1Element);

 

         Element emp2Element = DocumentHelper.createElement("employee");

         emp2Element.addAttribute("number", "002");

         emp2Element.addAttribute("name", "Jim");

         employeeElementList.add(emp2Element);

 

         Element emp3Element = DocumentHelper.createElement("employee");

         // 添加屬性

         emp3Element.addAttribute("number", "003");

         emp3Element.addAttribute("name", "Lily");

         employeeElementList.add(emp3Element);

 

         try

         {

              writeToFile(document, "c:/department.xml");

         } catch (IOException e)

         {

              e.printStackTrace();

         }

     }

 

     private static void writeToFile(Document document, String file)

              throws IOException

     {

         // 美化格式

         OutputFormat format = OutputFormat.createPrettyPrint();

         format.setEncoding("GB2312");

         XMLWriter writer = null;

         try

         {

              writer = new XMLWriter(new FileWriter(file), format);

              writer.write(document);

         } finally

         {

              if (writer != null)

                   writer.close();

         }

     }

}

運行以後就可以在 c:/ 下發現生成了和 5.2.1 的文件內容一樣的 department.xml 了。

這裏有兩點需要注意的:

1 OutputFormat format = OutputFormat.createPrettyPrint()

XML 通常是需要人閱讀的, Dom4j 默認的生成格式是緊縮格式的,這樣可以減少空間佔用,但是帶來的缺點就是文件格式非常難看,因此我們採用鎖緊格式進行輸出。

2 format.setEncoding("GB2312")

Dom4j 默認的編碼格式是“ UTF-8 ”,這在輸出中文字符的時候會有問題,因此我們改成“ GB2312 ”格式。

這裏使用了 Dom4j 提供的工具類 DocumentHelper 提供的 createElement 方法來創建一個節點,這個工具類還有 public static CDATA createCDATA(String text) public static Comment createComment(String text) public static Entity createEntity(String name, String text) 等方法可以幫助我們更快的創建節點。 DocumentHelper 還提供了 parseText 方法,可以直接將字符串解析成 Documen 對象。

http://www.blogjava.net/huanzhugege/

1.3    XStream的使用

在使用 XStream 之前首先到 http://xstream.codehaus.org 下載 XStream 的最新版本,然後把 XSteam***.jar xpp3-***.jar 導入到 ClassPath 下,然後就可以使用了,當然不加入 xpp3-***.jar 也可以,我們可以使用 DomDriver 做爲 XML 解析驅動(只要在實例化 XStream 的時候使用 new XStream(new DomDriver()) 即可),不過 Xpp3 XStream 提供的一個很有效率的 XML pull-parser 實現,推薦使用,可以提高解析的效率。

XML 的解析

我們有一個記錄書籍進行的 XML 文件:

<book>

     <name>J2EE Guide Book</name>

     <author>

         <name>Jerry</name>

         <email>[email protected]</email>

     </author>

</book>

爲了解析此 XML 文件,我們首先創建代表書籍和人員的兩個 JavaBean

代碼 5 . 3 人員和書籍的 JavaBean

public class BookInfo

{

     private String name;

     private PersonInfo author;

     public PersonInfo getAuthor()

     {

         return author;

     }

     public void setAuthor(PersonInfo author)

     {

         this.author = author;

     }

     public String getName()

     {

         return name;

     }

     public void setName(String name)

     {

         this.name = name;

     }

}

 

public class PersonInfo

{

     private String name;

     private String email;

     public String getEmail()

     {

         return email;

     }

     public void setEmail(String email)

     {

         this.email = email;

     }

     public String getName()

     {

         return name;

     }

     public void setName(String name)

     {

         this.name = name;

     }

}

然後我們就可以進行文件的解析了,這也是重頭戲:

代碼 5 . 4 XStream XML 解析

XStream xstream = new XStream();

xstream.alias("book", BookInfo.class);

xstream.alias("author", PersonInfo.class);

InputStream inStream = XStreamDemo.class

         .getResourceAsStream("/com/cownew/Char0503/Books.xml");

InputStreamReader reader = new InputStreamReader(inStream);

BookInfo book = (BookInfo) xstream.fromXML(reader);

StringBuffer sb = new StringBuffer();

sb.append(book.getName()).append(" 的作者 ");

sb.append(book.getAuthor().getName()).append(" Email :");

sb.append(book.getAuthor().getEmail());

System.out.println(sb);

運行結果:

J2EE Guide Book 的作者 Jerry Email :[email protected]     

由於 book 節點和 author 節點對應的數據類型是我們的自定義類型,因此我們必須首先向 XStream 註冊這兩個類型

xstream.alias("book", BookInfo.class);

xstream.alias("author", PersonInfo.class);

由於我們是使用 XStream 解析已有的 XML 文件,因此我們必須讓 XStream 知道標籤對應的類型是什麼,如果我們是使用 XStream 進行 XML 文件的生成,那麼我們甚至無需向 XStream 註冊別名即可進行文件解析。

註冊完類型以後,調用 XStream 類的 fromXML 方法即可把 XML 解析成 JavaBean 對象,無需額外的操作。

XML 文件的保存

我們不僅需要解析 XML 文件,有的時候還需要將數據保存到 XML 文件, XStream 同樣能很好的完成,並且能更體現出 XStream 的強大。

代碼 5 . 5 XStream XML 的保存

List bookList = new ArrayList();

PersonInfo p1 = new PersonInfo();

p1.setName("Tom");

p1.setEmail("[email protected]");

PersonInfo p2 = new PersonInfo();

p2.setName("Jerry");

p2.setEmail("[email protected]");

    

BookInfo book1 = new BookInfo();

book1.setName("About Face");

book1.setAuthor(p1);

    

BookInfo book2 = new BookInfo();

book2.setName("UI Design");

book2.setAuthor(p2);

    

bookList.add(book1);

bookList.add(book2);

    

XStream xstream = new XStream();

String xml = xstream.toXML(bookList);

System.out.println(xml);

    

List list = (List) xstream.fromXML(xml);

for(int i=0,n=list.size();i<n;i++)

{

     BookInfo book = (BookInfo) list.get(i);

     StringBuffer sb = new StringBuffer();

     sb.append(book.getName()).append(" 的作者 ");

     sb.append(book.getAuthor().getName()).append(" Email :");

     sb.append(book.getAuthor().getEmail());

     System.out.println(sb);

}

運行結果:

<list>

  <com.cownew.Char0503.BookInfo>

    <name>About Face</name>

    <author>

      <name>Tom</name>

      <email>[email protected]</email>

    </author>

  </com.cownew.Char0503.BookInfo>

  <com.cownew.Char0503.BookInfo>

    <name>UI Design</name>

    <author>

      <name>Jerry</name>

      <email>[email protected]</email>

    </author>

  </com.cownew.Char0503.BookInfo>

</list>

About Face 的作者 Tom Email :[email protected]

UI Design 的作者 Jerry Email :[email protected]

 

不可思議吧!我們就是像在序列化一樣把 JavaBean “序列化”爲 XML 格式字符串,然後又輕鬆的將 XML 格式字符串“反序列化”爲 JavaBean

不過美中不足的就是“ <com.cownew.Char0503.BookInfo> ”這個標籤顯得有點羅嗦。解決方式很簡單,使用 5.3.1 一節中提到的 alias 方法就可以辦到:

xstream.alias("book", BookInfo.class); 添加到 XStream xstream = new XStream(); 之後,然後重新運行:

<list>

  <book>

    <name>About Face</name>

    <author>

      <name>Tom</name>

      <email>[email protected]</email>

    </author>

  </book>

  <book>

    <name>UI Design</name>

    <author>

      <name>Jerry</name>

      <email>[email protected]</email>

    </author>

  </book>

</list>

About Face 的作者 Tom Email :[email protected]

UI Design 的作者 Jerry Email :[email protected]

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章