常用 XML 解析技术
現在的軟件項目都不是獨立的一個項目,都是多系統協調工作。這樣的話就涉及到系統間的通訊,通訊就會跟報文傳輸掛上關系。系統間使用怎樣的報文格式進行通訊呢?有的使用固定長度格式報文;有的使用變長格式報文;有的使用 XML格式報告。本場 Chat 主要和大家分享一下 XML 格式報文的解析。Java 是一個開源的語言,本場 Chat 將給大家介紹一下常用的 XML 解析框架及特點。
主要內容:
- XML 的簡介及一些常見概念 ;
- Java 內置解析 XML API: DOM、SAX;
- XML 解析框架 JDOM;
- XML 解析框架 DOM4J;
- XML 解析框架 XStream ;
- 總結 。
現在的軟件項目都不是獨立的一個項目,都是多系統協調工作。這樣的話就涉及到系統間的通訊,通訊就會跟報文傳輸掛上關系。系統間使用怎樣的報文格式進行通訊呢?有的使用固定長度格式報文;有的使用變長格式報文;有的使用 XML 格式報告。本分享主要和大家分享一下 XML 格式報文的解析。Java 是一個開源的語言,本分享將給大家介紹一下常用的 XML 解析框架及特點。
- XML 的簡介及一些常見概念
- Java 內置解析 XML API: DOM、SAX
- XML 解析框架 JDOM
- XML 解析框架 DOM4J
- XML 解析框架 XStream
- 總結
XML 的簡介及一些常見概念
XML 的概念
XML 是 Extensible Markup Language 簡稱,中文翻譯為可擴展標記語言。XML 是一種通用的數據交換格式,它的平臺無關性、語言無關性、系統無關性,給數據集成與交互帶來了極大的方便。XML 在不同的語言環境中解析方式都是一樣的,只不過實現的語法不同而已。
XML 可用來描述數據、存儲數據、傳輸數據/交換數據。
XML 文檔節點的類型主要有:
XML 的基本語法
在使用過程中,請記住以下幾個基本語法。
- 聲明格式,如下:
- 根節點:必須有一個根節點。
- 標簽:標簽必須有結束且區分大小寫,標簽必須順序嵌套。
- 屬性:必須使用引號引起值。
- 空格會被保留。
- 命名規則:命名必須見名知意。
- 名字可包含字母、數字以及其他的字符。
- 名字不能以數字或者標點符號開始。
- 名字不能以字符“xml”(或者 XML、Xml)開始。
- 名字不能包含空格。
- 不應在 XML 元素名稱中使用“:” ,這是由于它用于命名空間(NameSpaces)的保留字。
- 標簽優先于屬性。
- XML 命名空間可提供避免元素命名沖突的方法。
- CDATA:字符數據,<![CDATA[字符數據]]> ,字符數據不進行轉義。
- 實體:使用方式為“&實體;”,XML 中有5個預定義的實體,如下表所示。
| < | < | 小于 |
| > | > | 大于 |
| & | & | 和號 |
| ' | ' | 單引號 |
| " | " | 引號 |
注釋:在 XML 中,只有字符 "<" 和 "&" 確實是非法的。大于號是合法的,但是用實體引用來代替它是一個好習慣。
XML 約束
1.XML DTD 約束
DTD 是 DocType Definition 的簡稱,中文翻譯為文檔類型定義,DTD 的作用是定義 XML 文檔的合法構建模塊。它使用一系列的合法元素來定義文檔結構,用于約定 XML 的格式。規定了文檔中所使用的元素、實體、元素的屬性、元素與實體之間的關系。
DTD主要作用有:
- 使用 DTD 可以提供一種統一的格式。
XML 的可擴展性為文檔的作者提供了很高的靈活性,可有時候需要的是統一,要求某一類文檔具有相同的結構。
- 使用 DTD 可以保證數據交流和共享的順利進行。
- DTD 使用戶能夠不依賴具體的數據就知道文檔的邏輯結構。
在沒有 XML 文檔的時候,也可以根據 DTD 為 XML 文檔編寫樣式單,編寫處理程序,這樣可以有效地提高工作效率。
- 使用 DTD 可以驗證數據的有效性。
DTD 對文檔的邏輯結構進行了約束,這種約束可以比較寬松,也可以十分嚴格。可以根據 DTD 檢查數據,以驗證其是否符合規定和要求,這可以保證數據的正確和有效。
DTD 主要定義方式:
(1)內部定義法,DTD 文件放在 XML 文件內部。
<!DOCTYPE 根元素 [元素聲明]>請看下面的例子,book.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE bookstore [ <!ELEMENT bookstore (book+)> <!ELEMENT book (bookname,author,price)> <!ATTLIST book id CDATA #REQUIRED> <!ELEMENT bookname (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)> ]> <bookstore> <book> <bookname>帶你飛培訓教程</bookname> <author>huangjinjin</author> <price>1.00元</price> </book> <book> <bookname>降龍十八講秘籍</bookname> <author>洪七公</author> <price>0.01元</price> </book> </bookstore>(2)外部定義,請看下面這個例子。
bookstore.dtd:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE bookstore [ <!ELEMENT bookstore (book+)> <!ELEMENT book (bookname,author,price)> <!ATTLIST book id CDATA #REQUIRED> <!ELEMENT bookname (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)> ]>book.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE bookstore SYSTEM "bookstore.dtd"> <bookstore> <book> <bookname>帶你飛培訓教程</bookname> <author>huangjinjin</author> <price>1.00元</price> </book> <book> <bookname>降龍十八講秘籍</bookname> <author>洪七公</author> <price>0.01元</price> </book> </bookstore>2.XML Schema 約束
XML Schema 是基于 XML DTD 的替代者,XML Schema 描述 XML 文檔的結構。XML Schema 語言也稱作 XML Schema 定義(XML Schema Definition 簡稱 XSD)。DTD 不是通過 XML 語法定義文檔結構,不能定義數據類型和限制;Schema 通過 XML 語法定義文檔結構,可以定義數據類型和限制。
XML Schema 對 XML 文件的主要約定有:
- 定義可出現在 XML 文檔中的元素;
- 定義可出現在 XML 文檔中的屬性;
- 定義哪個元素是子元素;
- 定義子元素的次序;
- 定義子元素的數目;
- 定義元素是否為空,或者是否可包含文本;
- 定義元素和屬性的數據類型;
- 定義元素和屬性的默認值以及固定值。
為何使用 Schema,原因有幾下幾點:
- XML Schema 可針對未來的需求進行擴展;
- XML Schema 更完善,功能更強大;
- XML Schema 基于 XML 編寫;
- XML Schema 支持數據類型和限制;
- XML Schema 支持命名空間。
我們看下面這個例子。
book.xsd 文件:
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.mybook.org/BookSchema" xmlns:tns="http://www.mybook.org/BookSchema" elementFormDefault="qualified"> <!-- 定義一個標簽 --> <element name="bookstore"> <!-- 復合類型 就是該標簽含有子標簽 --> <complexType> <!-- 含有不限定個數的子標簽 --> <sequence maxOccurs="unbounded"> <!-- 定義一個子標簽 --> <element name="book"> <complexType> <sequence> <!-- 定義一個文本子標簽 --> <element name="bookname" type="string" /> <element name="author" type="string" /> <element name="price" type="string" /> </sequence> <attribute name="id" type="string"></attribute> </complexType> </element> </sequence> </complexType> </element> </schema>book.xml
<?xml version="1.0" encoding="UTF-8" ?> <bookstore xmlns="http://www.w3.org/2001/XMLSchema-instance" xmlns:nsbook="http://www.mybook.org/BookSchema" nsbook:schemaLocation="http://www.mybook.org/BookSchema book.xsd"> <book id="1"> <bookname>帶你飛培訓教程</bookname> <author>huangjinjin</author> <price>1.00元</price> </book> <book id="2"> <bookname>降龍十八講秘籍</bookname> <author>洪七公</author> <price>0.01元</price> </book> </bookstore>Java 內置解析 XML API: DOM、SAX
DOM
DOM的全稱是 Document Object Model,即文檔對象模型,W3C 組織推薦處理 XML 的一種方式。在應用程序中,基于 DOM 的 XML 分析器將一個 XML 文檔轉換成一個對象模型的集合(通常稱 DOM 樹),應用程序正是通過對這個對象模型的操作,來實現對 XML 文檔數據的操作。通過 DOM 接口,應用程序可以在任何時候訪問 XML 文檔中的任何一部分數據,因此這種利用 DOM 接口的機制也被稱作隨機訪問機制。
DOM 接口提供了一種通過分層對象模型來訪問 XML 文檔信息的方式,這些分層對象模型依據 XML 的文檔結構形成了一棵節點樹。無論 XML 文檔中所描述的是什么類型的信息,即便是制表數據、項目列表或一個文檔,利用 DOM 所生成的模型都是節點樹的形式。也就是說 DOM 強制使用樹模型來訪問 XML 文檔中的信息。由于 XML 本質上就是一種分層結構,所以這種描述方法是相當有效的。
DOM 樹所提供的隨機訪問方式給應用程序的開發帶來了很大的靈活性,它可以任意地控制整個 XML 文檔中的內容。然而,由于 DOM 分析器把整個 XML 文檔轉化成 DOM 樹放在了內存中,因此當文檔比較大或者結構比較復雜時,對內存的需求就比較高。而且對于結構復雜的樹的遍歷也是一項耗時的操作。所以 DOM 分析器對機器性能的要求比較高,實現效率不十分理想。不過,由于 DOM 分析器所采用的樹結構的思想與 XML 文檔的結構相吻合,同時鑒于隨機訪問所帶來的方便,因此 DOM 分析器還是有很廣泛的使用價值的。
其優點主要有:
其缺點主要有:
DOM 操作 XML 例子,請見下面代碼:
// 創建一個DocumentBuilderFactory的對象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 創建一個DocumentBuilder的對象 try { // 創建DocumentBuilder對象 DocumentBuilder db = dbf.newDocumentBuilder(); // 通過DocumentBuilder對象的parser方法加載books.xml文件到當前項目下 Document document = db.parse("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\3.xml"); // 獲取所有book節點的集合 NodeList bookList = document.getElementsByTagName("book"); // 通過nodelist的getLength()方法可以獲取bookList的長度 System.out.println("一共有" + bookList.getLength() + "本書"); // 遍歷每一個book節點 for (int i = 0; i < bookList.getLength(); i++) { System.out.println("=================下面開始遍歷第" + (i + 1) + "本書的內容================="); // 通過 item(i)方法 獲取一個book節點,nodelist的索引值從0開始 Node book = bookList.item(i); // 獲取book節點的所有屬性集合 NamedNodeMap attrs = book.getAttributes(); System.out.println("第 " + (i + 1) + "本書共有" + attrs.getLength() + "個屬性"); // 遍歷book的屬性 for (int j = 0; j < attrs.getLength(); j++) { // 通過item(index)方法獲取book節點的某一個屬性 Node attr = attrs.item(j); // 獲取屬性名 值 System.out.print("屬性名:" + attr.getNodeName()+", 屬性值" + attr.getNodeValue()); } // 解析book節點的子節點 NodeList childNodes = book.getChildNodes(); // 遍歷childNodes獲取每個節點的節點名和節點值 System.out.println("第" + (i + 1) + "本書共有" + childNodes.getLength() + "個子節點"); for (int k = 0; k < childNodes.getLength(); k++) { // 區分出text類型的node以及element類型的node if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) { // 獲取了element類型節點的節點名 System.out.print("第" + (k + 1) + "個節點的節點名:" + childNodes.item(k).getNodeName()); // 獲取了element類型節點的節點值 System.out.println("--節點值是:" + childNodes.item(k).getFirstChild().getNodeValue()); } } System.out.println("======================結束遍歷第" + (i + 1) + "本書的內容================="); } } catch (Exception e) { e.printStackTrace(); }SAX
SAX 的全稱是 Simple APIs for XML,即 XML 簡單應用程序接口。與 DOM 不同,SAX 提供的訪問模式是一種順序模式,這是一種快速讀寫 XML 數據的方式。當使用 SAX 分析器對 XML 文檔進行分析時,會觸發一系列事件,并激活相應的事件處理函數,應用程序通過這些事件處理函數實現對 XML 文檔的訪問,因而 SAX 接口也被稱作事件驅動接口。SAX 不是官方標準,但它是 XML 社區事實上的標準,幾乎所有的 XML 解析器都支持它。
其優點主要有:
其缺點主要有:
SAX 處理 XML 例子,請見下面代碼:
// 獲取Sax解析工程對象 SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); // 新建xml處理器 SAXParserHandler handler = new SAXParserHandler(); parser.parse("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\3.xml", handler); System.out.println("共有" + handler.getBookList().size() + "本書"); for (Book book : handler.getBookList()) { System.out.println(book.getId()); System.out.println(book.getBookname()); System.out.println(book.getAuthor()); System.out.println(book.getPrice()); } } catch (Exception e) { e.printStackTrace(); }XML 處理器 SAXParserHandler 關鍵代碼,如下:
/** * 解析xml元素 */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 調用DefaultHandler類的startElement方法 super.startElement(uri, localName, qName, attributes); if (qName.equals("book")) { bookIndex++; // 創建一個book對象 book = new Book(); // 開始解析book元素的屬性 System.out.println("============開始遍歷某一本書的內容================="); // 不知道book元素下屬性的名稱以及個數,如何獲取屬性名以及屬性值 int num = attributes.getLength(); for (int i = 0; i < num; i++) { System.out.print("book元素的第" + (i + 1) + "個屬性名是:" + attributes.getQName(i)); System.out.println(", 屬性值是:" + attributes.getValue(i)); if (attributes.getQName(i).equals("id")) { book.setId(attributes.getValue(i)); } } } else { System.out.print("節點名是:" + qName +", "); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // 調用DefaultHandler類的endElement方法 super.endElement(uri, localName, qName); // 判斷是否針對一本書已經遍歷結束 if (qName.equals("book")) { bookList.add(book); book = null; System.out.println("===========結束遍歷某一本書的內容================="); } else if (qName.equals("bookname")) { book.setBookname(value); } else if (qName.equals("author")) { book.setAuthor(value); } else if (qName.equals("price")) { book.setPrice(value); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); value = new String(ch, start, length); if (!value.trim().equals("")) { System.out.println("節點值是:" + value); } }XML 解析框架 JDOM
JDOM 目的是成為 Java 特定文檔模型,簡化與 XML 的交互并且比使用 DOM 實現更快。由于是第一個 Java 特定模型,所以 JDOM 一直得到大力推廣和促進。正在考慮通過“Java 規范請求 JSR-102”將它最終用作“Java 標準擴展”。從2000年初就已經開始了 JDOM 開發。JDOM 與 DOM 主要有兩方面不同。第一,JDOM 僅使用具體類而不使用接口,這在某些方面簡化了 API,但是也限制了靈活性;第二,API 大量使用了 Collections 類,簡化了那些已經熟悉這些類的 Java 開發者的使用。
JDOM 文檔聲明其目的是“使用20%(或更少)的精力解決80%(或更多)Java/XML 問題”。JDOM 對于大多數 Java/XML 應用程序來說非常有用,并且大多數開發者發現 API 比 DOM 容易理解得多。JDOM 還包括對程序行為的相當廣泛檢查以防止用戶做任何在 XML 中無意義的事。然而它仍需要您充分理解 XML 以便做一些超出基本的工作(或者甚至理解某些情況下的錯誤)。這也許是比學習 DOM 或 JDOM 接口都更有意義的工作。JDOM 自身不包含解析器。它通常使用 SAX2 解析器來解析和驗證輸入 XML 文檔,盡管它還可以將以前構造的 DOM 表示作為輸入。它包含一些轉換器以將 JDOM 表示輸出成 SAX2 事件流、DOM 模型或 XML 文本文檔。JDOM 是在 Apache 許可證變體下發布的開放源碼。同時需要注意的是 JDOM 目前分為兩個版本,分別為JDOM 1.x 和 JDOM 2.x。
其主要特征有:
JDOM 解析 XML 的例子,如下:
import java.io.File; import java.io.FileInputStream; import java.util.List; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; public class JDomTest { public static void main(String[] args) { try { // 創建一個SAXBuilder對象 SAXBuilder sb = new SAXBuilder(); File file = new File("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\1.xml"); FileInputStream in = new FileInputStream(file); // 構造文檔對象 Document doc = sb.build(in); // 獲取根元素bookstore Element root = doc.getRootElement(); // 取名字為book的所有元素 List<Element> books = root.getChildren("book"); for (int i = 0; i < books.size(); i++) { Element e = books.get(i); List<Element> sube = e.getChildren(); System.out.println("第" + (i + 1) + "本書信息:"); e = sube.get(0); System.out.println(e.getName() + "=" + e.getText()); e = sube.get(1); System.out.println(e.getName() + "=" + e.getText()); e = sube.get(2); System.out.println(e.getName() + "=" + e.getText()); } } catch (Exception e) { e.printStackTrace(); } } }XML 解析框架 DOM4J
雖然 DOM4J 代表了完全獨立的開發結果,但最初它是 JDOM 的一種智能分支。它合并了許多超出基本 XML 文檔表示的功能,包括集成的 XPath 支持、 XML Schema 支持以及用于大文檔或流化文檔的基于事件的處理。它還提供了構建文檔表示的選項,它通過 DOM4J API 和標準 DOM 接口具有并行訪問功能。
為支持所有這些功能,DOM4J 使用接口和抽象基本類方法。DOM4J 大量使用了 API 中的 Collections 類,但是在許多情況下,它還提供一些替代方法以允許更好的性能或更直接的編碼方法。直接好處是,雖然 DOM4J 付出了更復雜的 API 的代價,但是它提供了比 JDOM 大得多的靈活性。在添加靈活性、XPath 集成和對大文檔處理的目標時,DOM4J 的目標與 JDOM 是一樣的:針對 Java 開發者的易用性和直觀操作。它還致力于成為比 JDOM 更完整的解決方案,實現在本質上處理所有 Java/XML 問題的目標。在完成該目標時,它比 JDOM 更少強調防止不正確的應用程序行為。
DOM4J 是一個非常非常優秀的 Java XML API,具有性能優異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件。如今你可以看到越來越多的 Java 軟件都在使用 DOM4J 來讀寫 XML,特別值得一提的是 Sun 的 JAXM 也在用 DOM4J。同時需要注意的是 DOM4J 目前也分為兩個版本,分別為 DOM4J 1.x和 DOM4J 2.x。
其特征主要有:
DOM4J 解析 XML 的例子,如下:
import java.io.File; import java.util.Iterator; import java.util.List; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class DOM4JTest { public static void main(String[] args) { try { // 創建SAXReader的對象reader SAXReader reader = new SAXReader(); // 通過reader對象的read方法加載books.xml文件,獲取docuemnt對象。 Document document = reader.read( new File("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\1.xml")); // 通過document對象獲取根節點bookstore Element element = document.getRootElement(); // 通過element對象的elementIterator方法獲取迭代器 Iterator<Element> iter = element.elementIterator(); int index = 0; // 遍歷迭代器,獲取根節點中的信息(書籍) while (iter.hasNext()) { Element e = iter.next(); System.out.println("第" + (index + 1) + "本書"); List<Attribute> bookAttrs = e.attributes(); for (Attribute attr : bookAttrs) { System.out.println("屬性名:" + attr.getName() + ",屬性值:" + attr.getValue()); } index = index + 1; Iterator<Element> siter = e.elementIterator(); while (siter.hasNext()) { e = siter.next(); System.out.println(e.getName() + "=" + e.getStringValue()); } } } catch (Exception e) { e.printStackTrace(); } } }XML解析框架 XStream
XStream 是一種 OXMapping 技術,是用來處理 XML 文件序列化的框架,將 JavaBean 序列化或將 XML 文件反序列化,不需要其它輔助類和映射文件,使得 XML 序列化不再繁索。另外,Xstream 也可以將 JavaBean 序列化成 Json 或反序列化,使用非常方便。Java 自帶的 JAXB(Java Architecture for XML Binding) API 也有相應的功能。下面分別介紹下這兩種 API 的使用方法。
JAXB 介紹
JAXB 相關的重要 Class 和 Interface 有:
- JAXBContext 類,是應用的入口,用于管理 XML/Java 綁定信息。
- Marshaller 接口,將 Java 對象序列化為 XML 數據。
- Unmarshaller 接口,將 XML 數據反序列化為 Java 對象。
JDK 中 JAXB 相關的重要 Annotation有:
- @XmlType,將 Java 類或枚舉類型映射到 XML 模式類型。
- @XmlAccessorType(XmlAccessType.FIELD),控制字段或屬性的序列化。FIELD 表示 JAXB 將自動綁定 Java 類中的每個非靜態的(static)、非瞬態的(由 @XmlTransient 標注)字段到 XML。其他值還有 XmlAccessType.PROPERTY 和 XmlAccessType.NONE。
- @XmlAccessorOrder,控制 JAXB 綁定類中屬性和字段的排序。
- @XmlJavaTypeAdapter,使用定制的適配器(即擴展抽象類 XmlAdapter 并覆蓋 marshal()和 unmarshal()方法),以序列化 Java 類為 XML。
- @XmlElementWrapper,對于數組或集合(即包含多個元素的成員變量),生成一個包裝該數組或集合的 XML 元素(稱為包裝器)。
- @XmlRootElement,將 Java 類或枚舉類型映射到 XML 元素。
- @XmlElement,將 Java 類的一個屬性映射到與屬性同名的一個 XML 元素。
- @XmlAttribute,將 Java 類的一個屬性映射到與屬性同名的一個 XML 屬性。
注意以下幾點:
- 對于要序列化(marshal)為 XML 的 Java 類,絕不能把成員變量聲明為 public,否則運行將拋出異常 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException。
- 對于 JAXB 相關的重要 Annotation 的聲明,如 @Xml.....,可以放在成員變量的 setter() 或 getter() 方法上,兩者中任選其一即可,但決不能放在成員變量上,否則運行將拋出異常 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException。
我們看一個例子,Book2.java 對象:
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Book2 { private String id; private String bookname; private String author; private String price; public String getId() { return id; } @XmlAttribute public void setId(String id) { this.id = id; } public String getBookname() { return bookname; } @XmlElement public void setBookname(String bookname) { this.bookname = bookname; } public String getAuthor() { return author; } @XmlElement public void setAuthor(String author) { this.author = author; } public String getPrice() { return price; } @XmlElement public void setPrice(String price) { this.price = price; } }將 JavaBean 轉成 XML,如下:
import java.io.FileOutputStream; import java.io.StringWriter; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; //將java bean轉成xml public class JaxbMarshal { public static void main(String[] args) { try { Book2 book = new Book2(); book.setId("1"); book.setAuthor("千年老二"); book.setBookname("葵花寶典"); book.setPrice("1234"); JAXBContext context = JAXBContext.newInstance(Book2.class); Marshaller m = context.createMarshaller(); StringWriter sw = new StringWriter(); m.marshal(book, sw); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化 m.marshal(book, new FileOutputStream("src/main/java/book.xml")); System.out.println(sw.toString()); } catch (Exception e) { e.printStackTrace(); } } }將 XML 轉成 JavaBean,如下:
import java.io.File; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; //將xml轉成java bean public class JaxbUnMarshal { public static void main(String[] args) { try { JAXBContext context = JAXBContext.newInstance(Book2.class); Unmarshaller m = context.createUnmarshaller(); Book2 book = (Book2)m.unmarshal(new File("src/main/java/book.xml")); System.out.println(book.getId()); System.out.println(book.getBookname()); System.out.println(book.getAuthor()); System.out.println(book.getPrice()); } catch (Exception e) { e.printStackTrace(); } } }XStream 介紹
XStream 是個很強大的工具,能將 Java 對象和 XML 之間相互轉化。XStream 不在意 Java 類中成員變量是私有還是公有,也不在乎是否有默認構造函數。它調用方式也非常簡單:從 XML 對象轉化為 Java 對象,使用 fromXML() 方法;從 Java 對象序列化為 XML,toXML() 即可,很方便。XStream 也支持注解方式,這些都是為了簡化輸出而設計。
XStream常用注解說明有:
- @XStreamAlias 注解可在類與屬性上,設置別名;
- @XStreamAliasType 注解設置在類,設置類型別名;
- @XStreamAsAttribute 注解設置在屬性上,作用是將類內成員作為父節點屬性輸出;
- @XStreamConverter 注解設置在屬性上,注入轉化器;
- @XStreamConverters 注解設置在屬性上,注入多個轉化器;
- @XStreamImplicit 常用在集合屬性上,表明只把集合里的元素列序號到 XML中;
- @XStreamInclude
- @XStreamOmitField 注解可設置在屬性上,表明該屬性不會被序列化到 XML 中。
接下來,我們看下 XStream 使用例子。
Person 實體類,如下:
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAliasType; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamOmitField; @XStreamAliasType("p") public class Person { @XStreamAsAttribute private int id; @XStreamAlias("n") private String name; @XStreamAlias("a") @XStreamOmitField private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }XStream 操作 XML,如下:
import com.thoughtworks.xstream.XStream; public class XStreamTest { public static void main(String[] args) { Person person=new Person(); person.setName("獨孤求敗"); person.setAge(100); XStream xstream = new XStream(); // 進行注解的檢測 如果沒有這行注解將不起作用 xstream.autodetectAnnotations(true); //XML序列化 String xml = xstream.toXML(person); System.out.println(xml); //XML反序列化 Person person1=(Person)xstream.fromXML(xml); System.out.println(person1.getName()); System.out.println(person1.getAge()); } }備注: xstream.autodetectAnnotations(true) 的作用是開啟注解掃描,如果沒有改行代碼,默認為 false,不開啟注解掃描,這樣的話 Person.java 將不起任何作用。
總結
我們綜合看下 DMO、SAX 和 JDOM 三者之間的區別。
(1)DOM:拉模型,把整個文檔加載到內存中。
- 優點:整個文檔樹在內存中,便于操作;支持刪除、修改、重新排列等多種功能;
- 缺點:將整個文檔調入內存(包括無用的節點),浪費時間和空間;
- 使用場合:一旦解析了文檔還需多次訪問這些數據;硬件資源充足(內存、CPU)。
(2)SAX:推模型,事件驅動編程,基于回調 SAX ,事件驅動。當解析器發現元素開始、元素結束、文本、文檔的開始或結束等時,發送事件,程序員編寫響應這些事件的代碼,保存數據。
- 優點:不用事先調入整個文檔,占用資源少;
- 缺點:不是持久的;事件過后,若沒保存數據,那么數據就丟了;無狀態性;從事件中只能得到文本,但不知該文本屬于哪個元素;
- 使用場合:數據量較大的XML文檔,占用內存高,機器內存少,無法一次加載XML到內存;只需XML文檔的少量內容,很少回頭訪問;
(3)JDOM:為減少 DOM、SAX 的編碼量,出現了 JDOM。
- 優點:20-80原則,極大減少了代碼量,提供常用 API 減少重復勞動;
- 使用場合:要實現的功能簡單,如解析、創建等Java程序。
再來看下三者之間的性能比較。
(1)DOM4J 性能最好,連 Sun 的 JAXM 也在用 DOM4J。目前許多開源項目中大量采用 DOM4J,例如大名鼎鼎的 Hibernate 也用 DOM4J 來讀取 XML 配置文件。如果不考慮可移植性,那就采用 DOM4J。
(2)JDOM 和 DOM 在性能測試時表現不佳,在測試 10M 文檔時內存溢出。在小文檔情況下還值得考慮使用 DOM 和 JDOM。雖然 JDOM 的開發者已經說明 他們期望在正式發行版前專注性能問題,但是從性能觀點來看,它確實沒有值得推薦之處。另外,DOM 仍是一個非常好的選擇。DOM 實現廣泛應用于多種編程語言。它還是許多其它與 XML 相關的標準的基礎,因為它正式獲得 W3C 推薦(與基于非標準的 Java 模型相對),所以在某些類型的項目中可能也需要它(如在 JavaScript 中使用 DOM)。
(3)SAX 表現較好,這要依賴于它特定的解析方式——事件驅動。一個 SAX 檢測即將到來的 XML 流,但并沒有載入到內存(當然當 XML 流被讀入時,會有部分文檔暫時隱藏在內存中)。
這里提供下源碼地址:https://gitee.com/hjj520/xml,大家可以自行下載學習。
本文首發于GitChat,未經授權不得轉載,轉載需與GitChat聯系。
閱讀全文: http://gitbook.cn/gitchat/activity/5aa3ab85291bf90af9b04b2c
您還可以下載 CSDN 旗下精品原創內容社區 GitChat App , GitChat 專享技術內容哦。
總結
以上是生活随笔為你收集整理的常用 XML 解析技术的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你是怎样毁掉自己的?
- 下一篇: springCloud sentinel