第 10 章 xml dom 物件模型

86
10 10 XML DOM XML DOM 第第第第 第第第第 DOM DOM 第第第 第第第 JAXP API JAXP API 第第第 第第第 Java Java 第第第第第第第 第第第第第第第 XML XML 第第 第第 DOM DOM 第第第第第 第第第第第 XML XML 第第第第第 第第第第第 XPath/XSLT XPath/XSLT Java Java

Upload: duff

Post on 07-Jan-2016

72 views

Category:

Documents


1 download

DESCRIPTION

第 10 章 XML DOM 物件模型. DOM 的基礎 JAXP API 的基礎 在 Java 程式載入和剖析 XML 文件 DOM 的節點介面 XML 文件的驗證 XPath/XSLT 與 Java. General Purpose XML Programming. Needed for: domain-specific applications implementing new generic tools Important constituents: parsing XML documents into XML trees - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 10 章  XML DOM 物件模型

第第 1010 章 章 XML DOMXML DOM 物件模物件模型型

DOM DOM 的基礎的基礎 JAXP API JAXP API 的基礎的基礎 在 在 Java Java 程式載入和剖析 程式載入和剖析 XML XML 文件文件 DOM DOM 的節點介面的節點介面 XML XML 文件的驗證文件的驗證 XPath/XSLT XPath/XSLT 與 與 JavaJava

Page 2: 第 10 章  XML DOM 物件模型

General Purpose XML General Purpose XML ProgrammingProgramming

Needed for:Needed for:• domain-specificdomain-specific applications applications• implementing implementing new generic toolsnew generic tools

Important constituents:Important constituents:• parsingparsing XML documents into XML trees XML documents into XML trees• navigatingnavigating through XML trees through XML trees• manipulatingmanipulating XML trees XML trees• serializingserializing XML trees as XML XML trees as XML documentsdocuments

Page 3: 第 10 章  XML DOM 物件模型

XMLXML 程式設計程式設計 一般來說,一般來說, XMLXML 剖析器主要有兩種類型:剖析器主要有兩種類型:

•樹狀基礎的剖析器(樹狀基礎的剖析器( Tree-based ParseTree-based Parserr ):):

將將 XMLXML 文件轉換成樹狀結構文件轉換成樹狀結構 剖析器需要分析完整份剖析器需要分析完整份 XMLXML 文件後文件後 提供相關介面物件來存取樹狀結構的節點,例如:提供相關介面物件來存取樹狀結構的節點,例如:DOMDOM、、 JDOMJDOM、、 JAXP APIsJAXP APIs 。。

•事件基礎的剖析器(事件基礎的剖析器( Event-based ParseEvent-based Parserr ):):

讀取內容時觸發一系列事件,應用程式提供函數處讀取內容時觸發一系列事件,應用程式提供函數處理這些事件,以便存取理這些事件,以便存取 XMLXML 內容,例如:內容,例如:SAXSAX(( Simple API for XMLSimple API for XML )。)。

Page 4: 第 10 章  XML DOM 物件模型

Parsing EventsParsing Events View the XML document as a stream of View the XML document as a stream of eventsevents::• the document startsthe document starts• a start tag is encountereda start tag is encountered• an end tag is encounteredan end tag is encountered• a namespace declaration is seena namespace declaration is seen• some whitespace is seensome whitespace is seen• character data is encounteredcharacter data is encountered• the document endsthe document ends

The SAX tool The SAX tool observesobserves these events these events It reacts by It reacts by callingcalling corresponding corresponding methods specified by the programmermethods specified by the programmer

Page 5: 第 10 章  XML DOM 物件模型

DOM vs. SAXDOM vs. SAX

Memory consumption:Memory consumption:• The JDOM version: The JDOM version:

java.lang.OutOfMemoryErrorjava.lang.OutOfMemoryError

on 18MB documenton 18MB document• The SAX version handles 1.2GB in The SAX version handles 1.2GB in 51 seconds51 seconds

Tree Navigation is easier for Tree Navigation is easier for DOM; especially when backward DOM; especially when backward traversal is necessary.traversal is necessary.

Page 6: 第 10 章  XML DOM 物件模型

什麼是什麼是 DOMDOM 「「 DOMDOM 」(」( Document Object ModelDocument Object Model )物件)物件

模型可以將一份結構化文件轉換成一棵由節點模型可以將一份結構化文件轉換成一棵由節點(( NodesNodes )組成的樹狀結構,提供節點的相關屬)組成的樹狀結構,提供節點的相關屬性和方法來存取元素內容,或新增、刪除和修改性和方法來存取元素內容,或新增、刪除和修改節點內容,如下圖所示:節點內容,如下圖所示:

Page 7: 第 10 章  XML DOM 物件模型

什麼是什麼是 W3C DOMW3C DOM

DOM DOM 是 是 W3C W3C 建議規格建議規格• Designed with language Designed with language independenceindependence

DOM Level 1 DOM Level 1 在 在 1998 1998 年 年 10 10 月 月 1 1 日成為 日成為 W3C W3C 的建議規格,的建議規格, DOM Level DOM Level 2 2 是在是在 2000 2000 年 年 11 11 月成為建議規格,月成為建議規格,目前最新版本是 目前最新版本是 Level 3Level 3

Page 8: 第 10 章  XML DOM 物件模型

W3C DOMW3C DOM 的特點的特點 跨平台和程式語言的程式介面跨平台和程式語言的程式介面 支援多種結構化文件支援多種結構化文件

• W3C DOM W3C DOM 支援 支援 HTML HTML 和 和 XML XML 文件文件 支援多種程式語言支援多種程式語言

• JavaScriptJavaScript、、 VBScriptVBScript、、 PerlPerl、、 VisuVisual Basical Basic、、 DelphiDelphi、、 C++C++、、 PHP PHP 和 和 Java Java 等程式語言。等程式語言。

支援多種文件驗證支援多種文件驗證• DOM DOM 支援 支援 DTDDTD、、 XML Schema XML Schema 等 等 XML XML 文件驗證。文件驗證。

Page 9: 第 10 章  XML DOM 物件模型

W3C DOMW3C DOM 基礎的文件分析基礎的文件分析 例如:一份例如:一份 XMLXML 文件,如下所示:文件,如下所示:

01: <library>01: <library>

02: <book code="P679">02: <book code="P679">

03: <title>Java 03: <title>Java 22 程式設計範例教本程式設計範例教本 </title></title>

04: <author>04: <author> 陳會安陳會安 </author></author>

05: <price>650</price>05: <price>650</price>

06: </book>06: </book>

07: </library>07: </library>

Page 10: 第 10 章  XML DOM 物件模型

XMLXML的的 DOMDOM 樹樹 以 以 W3C DOM W3C DOM 的角度來看,前頁的 的角度來看,前頁的 XML XML 文件文件

就是一棵樹狀結構的節點資料,以 就是一棵樹狀結構的節點資料,以 Java Java 語言語言來說,就是一個 來說,就是一個 Document Document 物件,如下圖所示:物件,如下圖所示:

Page 11: 第 10 章  XML DOM 物件模型

什麼是什麼是 JAXPJAXP 之前已經說過了,要處理 之前已經說過了,要處理 XML XML 文件,首先這份文文件,首先這份文

件都必須先經過 件都必須先經過 parser parser 來解析。來解析。 XML XML 的 的 parser parser 有非常多種,比較著名的有 有非常多種,比較著名的有 Apache Apache 的 的 XercesXerces、、 Crimson Crimson 等;只可惜這等;只可惜這些 些 parser parser 所提供的 所提供的 APIs APIs 並不相通(這跟當初並不相通(這跟當初設計 設計 DOM APIs DOM APIs 時的想法不同)。時的想法不同)。

Sun’s JAXPSun’s JAXP(( Java API for XML ParsingJava API for XML Parsing ))提供通用介面使得 提供通用介面使得 Java Java 程式使用任意符合 程式使用任意符合 JAXP JAXP 介面的 介面的 parser parser 來處理 來處理 XML XML 文件。文件。• JAXP JAXP 支援 支援 CrimsonCrimson、、 Xerces Xerces 等 等 XML parsersXML parsers• JAXP JAXP 支援 支援 XMLXML、、 SAXSAX、、 XPathXPath、、 XSLTXSLT 等標準等標準

JAXP vs. JDOMJAXP vs. JDOM• JDOM requires extra installationJDOM requires extra installation• JDOM does not directly support XSLTJDOM does not directly support XSLT

Page 12: 第 10 章  XML DOM 物件模型

什麼是什麼是 JAXPJAXP

JAXP API JAXP API 的主要套件是 的主要套件是 javax.xml.parsers javax.xml.parsers 套件提供與開發廠商無套件提供與開發廠商無關的通用 關的通用 API API 來使用 來使用 DOM DOM 和 和 SAX SAX 剖析和剖析和驗證 驗證 XML XML 文件。文件。

在 在 javax.xml.parsers javax.xml.parsers 套件主要包含兩個套件主要包含兩個代理商類別(代理商類別( Factory ClassesFactory Classes ),如下所示:),如下所示:• DocumentBuilderFactory DocumentBuilderFactory 類別:類別:

自動選取某一 自動選取某一 parser parser 類別(類別( ex. Xercesex. Xerces ),來產生 ),來產生 DocumentBuilderFactory DocumentBuilderFactory 的物件的物件

利用現有的 利用現有的 configuration configuration 來產生 來產生 DocumentBuilder DocumentBuilder 實例。實例。

• SAXParserFactorySAXParserFactory 類別:可以取得 類別:可以取得 SAXParser SAXParser 實例來處理 實例來處理 SAX SAX 事件基礎的 事件基礎的 XML XML 剖析。剖析。

Page 13: 第 10 章  XML DOM 物件模型

JAXP API JAXP API 的相關套件的相關套件 JAXP API JAXP API 提供 提供 DOM DOM 和 和 SAX SAX 剖析和剖析和驗證的常用套件,如下表所示:驗證的常用套件,如下表所示:套件 說明

javax.xml.parsers 提供與開發廠商無關的通用 API來使用 DOM和 SAX

剖析和驗證 XML文件javax.xml.transform 提供處理 XSLT轉換的相關類別javax.xml.validation JAXP 1.3版新增的套件,支援 XML Schema驗證 XML

文件org.xml.sax 定義基礎的 SAX API介面,提供事件剖析 XML文件

的 API

org.xml.sax.helpers 提供一些現成類別,可以幫助程式設計者更容易使用SAX API

org.w3c.dom 提供支援 DOM文件的套件,即 Document物件

Page 14: 第 10 章  XML DOM 物件模型

DOM API-DOM API- 說明說明 JAXP API JAXP API 的 的 DOM APIDOM API(( Document Document Object Model APIObject Model API )是使用 )是使用 javax.xml.parsers javax.xml.parsers 套件的 套件的 DocumentBuilderFactory DocumentBuilderFactory 類別來取得類別來取得DocumentBuilder DocumentBuilder 實例,以便建立 實例,以便建立 DOM DOM 樹樹狀結構節點的 狀結構節點的 Document Document 物件,如下圖所示:物件,如下圖所示:

Page 15: 第 10 章  XML DOM 物件模型

DOM API-DOM API- 介面物件介面物件 將 將 XML XML 文件內容視為一個樹狀結構的節文件內容視為一個樹狀結構的節點,其主要的介面物件,如下表所示:點,其主要的介面物件,如下表所示:

DOM介面物件 說明Document 樹狀結構表示整份 XML文件

Node 節點物件,新增、刪除和修改節點的物件NodeList 節點清單物件,就是指定節點子節點的整個樹狀結構Element XML元素物件,也就是元素節點

Text XML元素內容物件,也就是內容節點NamedNodeMap 元素節點的屬性集合

Page 16: 第 10 章  XML DOM 物件模型

載入與剖析載入與剖析 XMLXML 文件檔案文件檔案 在 在 Java Java 程式載入與剖析 程式載入與剖析 XML XML 檔案,首先需檔案,首先需

要匯入 要匯入 JAXP API JAXP API 的相關套件,如下所示:的相關套件,如下所示:import javax.xml.parsers.*;import javax.xml.parsers.*;

import org.xml.sax.*;import org.xml.sax.*;

import org.w3c.dom.*;import org.w3c.dom.*;• 程式碼匯入 程式碼匯入 XML XML 剖析器和 剖析器和 DOM DOM 的相關套件,至於 的相關套件,至於 org.xml.sax.* org.xml.sax.* 套件是剖析錯誤處理的相關套件。套件是剖析錯誤處理的相關套件。此外因為 此外因為 XML XML 檔案是文字檔案,所以需要匯入檔案檔案是文字檔案,所以需要匯入檔案處理套件,如下所示:處理套件,如下所示:

import java.io.*;import java.io.*;

Page 17: 第 10 章  XML DOM 物件模型

載入與剖析載入與剖析 XMLXML 文件檔案文件檔案String filename = String filename = ““Books.xmlBooks.xml””;;DocumentBuilderFactory dbf = DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilderFactory.newInstance();try {try { DocumentBuilder db =DocumentBuilder db = dbf.newDocumentBuilder();dbf.newDocumentBuilder(); Document document = db.parse(new File(filename));Document document = db.parse(new File(filename)); …………} catch(SAXException se) {} catch(SAXException se) { se.printStackTrace();se.printStackTrace();} catch(ParserConfigurationException pe) {} catch(ParserConfigurationException pe) { pe.printStackTrace();pe.printStackTrace();} catch(IOException ie) {} catch(IOException ie) { ie.printStackTrace();ie.printStackTrace();}}

Page 18: 第 10 章  XML DOM 物件模型

設定剖析器的參數設定剖析器的參數 DocumentBuilderFactory DocumentBuilderFactory 類別提供相關方法類別提供相關方法

可以利用 可以利用 configuration configuration 來設定 來設定 XML XML 剖析剖析器的功能或者特性器的功能或者特性• 是否忽略註解文字或空白字元的 是否忽略註解文字或空白字元的 XML XML 元素等元素等• 例如:設定剖析器參數來忽略註解節點、空白字元例如:設定剖析器參數來忽略註解節點、空白字元(需要(需要配合 配合 DTDDTD ))和不轉換 和不轉換 CDATA CDATA 節點,如下所示:節點,如下所示:

// // 設定剖析的參數設定剖析的參數dbf.setIgnoringComments(true);dbf.setIgnoringComments(true);

dbf.setIgnoringElementContentWhitespace(trudbf.setIgnoringElementContentWhitespace(true);e);

dbf.setCoalescing(false);dbf.setCoalescing(false);

Page 19: 第 10 章  XML DOM 物件模型

使用 DTD 驗證 JAXP JAXP 從 從 API 1.1 API 1.1 版就開始支援 版就開始支援 DTD DTD 驗證驗證

,,只需在 DocumentBuilderFactory 物件使用 setValidating() 方法設定參數為 true,就可以驗證 XML文件,如下所示:

dbf.setValidating(true);

• 參數 true 表示 XML 剖析器需要驗證 XML 文件,預設是 DTD 驗證;如果設為 false,剖析器就不會進行文件驗證。

Page 20: 第 10 章  XML DOM 物件模型

Ch10_5_1import javax.xml.parsers.*;import org.xml.sax.*; import java.io.*;public class Ch10_5_1 { public static void main(String[] args) { String filename = "Ch10-5-1.xml"; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { dbf.setValidating(true); // 設定剖析的參數 dbf.setIgnoringComments(false); dbf.setIgnoringElementContentWhitespace(false); dbf.setCoalescing(false); DocumentBuilder db = dbf.newDocumentBuilder(); // 剖析 XML文件 db.parse(new File(filename)); System.out.println("XML文件 : " + filename + "剖析成功 !"); } catch(ParserConfigurationException pe) { System.out.println("剖析器設定錯誤 !"); } catch(IOException ie) { System.out.println("檔案處理錯誤 !"); } catch(SAXException se) { System.out.print(“XML剖析錯誤 "); System.out.println(se.getMessage()); } }}

Page 21: 第 10 章  XML DOM 物件模型

範例:範例: Books.xmlBooks.xml<?xml version="1.0" encoding="Big5"?><!-- 文件範例 : Books.xml --><!DOCTYPE library SYSTEM "Books.dtd"><library><![CDATA[<script type="text/javascript">function hello() { alert("Hello World");}</script>]]> <book code="P716"> <title>PHP 5網頁設計範例教本 </title> <author>陳會安 </author> <price>600</price> <year>2005</year> </book> <book code="P679"> <title>JSP 2.0網頁設計範例教本 </title> <author>陳會安研究室 </author> <price>650</price> <year>2004</year> </book></library>

Page 22: 第 10 章  XML DOM 物件模型

Ch10_3_1 Ch10_3_1 修改版修改版import javax.xml.parsers.*;import org.xml.sax.*; import org.w3c.dom.*;import java.io.*;public class Ch10_3_1 { static Document document; public static void main(String[] args) { String filename = "Books.xml"; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //dbf.setIgnoringElementContentWhitespace(true); try { DocumentBuilder db = dbf.newDocumentBuilder(); // 讀入 XML文件 document = db.parse(new File(filename));

// Document 也是 Node 的一種 System.out.println(getID(document));

// 取得文件的根節點,這兩種方式略有不同! //Node root = document.getDocumentElement(); Node child = (Node)document.getFirstChild();

讀取 Books.xml 的內容,並將每一個節點的節點型態、節點名稱等依照樹狀結構列印出來。

請觀察設定有無的差異!

Page 23: 第 10 章  XML DOM 物件模型

Ch10_3_1 Ch10_3_1 修改版修改版 // 取得這一層的所有節點 for ( ; child != null; child = child.getNextSibling() ) { System.out.print(getID(child)); pChild(child, 0); } } catch(SAXException se) {// 剖析過程錯誤 se.printStackTrace(); } catch(ParserConfigurationException pe) { pe.printStackTrace();// 剖析器設定錯誤 } catch(IOException ie) { ie.printStackTrace();// 檔案處理錯誤 } }

Page 24: 第 10 章  XML DOM 物件模型

Ch10_3_1 Ch10_3_1 修改版修改版 // 練習題:請補上其他的節點型態 // 程設的補充:這就是多型的應用 private static String getID(Node n) { int type = n.getNodeType(); switch(type) { case 1: return "元素: " + n.getNodeName(); case 3: return "內容: " + n.getNodeValue().trim(); case 4: return "CDATA Section: " + n.getNodeValue(); case 6: return "實體名稱: " + n.getNodeName(); case 8: return "註解: " + n.getNodeValue(); case 9: return "Document: " + n.getNodeName(); case 10: return "DOCTYPE: " + ((DocumentType) n).getSystemId(); default: return "尚未定義: " + type; } }

Page 25: 第 10 章  XML DOM 物件模型

Ch10_3_1 Ch10_3_1 修改版修改版 // 顯示子節點的遞迴方法 private static void pChild(Node temp,int pos) { if ( temp.hasChildNodes() ) { NodeList nodes = temp.getChildNodes(); // 取得所有子節點 for (int i=0; i < nodes.getLength(); i++) { int type = nodes.item(i).getNodeType(); printIndent(pos); System.out.println(getID(nodes.item(i))); if(type == Node.ELEMENT_NODE) { pChild(nodes.item(i), pos+1); } } } }

// 顯示縮排所需的字元 private static void printIndent(int num) { System.out.print(" +"); for (int i=0; i<=num; i++) System.out.print("-"); }}

Page 26: 第 10 章  XML DOM 物件模型

NodeNode 節點種類節點種類getNodeType() Node種類 getNodeName() getNodeValue() getAttributes()

2 Attr屬性 屬性名稱 屬性值 null

4 CDATASection #cdata-section CDATA值 null

8 Comment註解 #comment 註解文字內容 null

9 Document文件 #document null null

11 DocumentFragment #document-fragment null null

10 <!DOCTYPE> null null null

1 Element 標籤名稱 null NamedNodeMap

3 Text #text 文字內容 null

5 EntityReference 實體參考名稱 null null

6 Entity 實體名稱 null null

7 PI target 不包含 target的內容 null

12 Notation Notation名稱 null null

Page 27: 第 10 章  XML DOM 物件模型

DocumentDocument 文件物件文件物件 XML XML 文件建立的樹狀結構是 文件建立的樹狀結構是 Document Document 物件物件

(可以想成之前說過的 (可以想成之前說過的 root noderoot node )) 當 當 DOM DOM 載入 載入 XML XML 文件建立 文件建立 Document Document 物物

件後,就可以使用 件後,就可以使用 getDocumentElement() getDocumentElement() 方法取得 方法取得 XML XML 文件的根元素,如下所示:文件的根元素,如下所示:• Node root = Node root = document.getDocumentElement();document.getDocumentElement();

取出的每一個節點都是一個 取出的每一個節點都是一個 Node Node 物物件。件。 Document Document 物件還提供特殊的方法,能夠物件還提供特殊的方法,能夠直接使用標籤名稱取得所有為該名稱的節點,如直接使用標籤名稱取得所有為該名稱的節點,如下所示:下所示:• NodeList tagNodes = NodeList tagNodes = document.getElementsByTagName("book");document.getElementsByTagName("book");

• Note: Document Note: Document 是 是 Node Node 的子類別的子類別

Page 28: 第 10 章  XML DOM 物件模型

Node Node 節點物件節點物件 Node Node 節點物件許多方法:節點物件許多方法:

•程式碼使用 程式碼使用 getNodeName() getNodeName() 方法取得節點方法取得節點的節點名稱的節點名稱

•若一個節點 若一個節點 root root 擁有多個子節點,我們可擁有多個子節點,我們可以取得該節點下的所有子節點:以取得該節點下的所有子節點:

NodeList nodes = NodeList nodes = root.getChildNodes();root.getChildNodes();

•另外,還有 另外,還有 getNodeValue() getNodeValue() 和 和 getAttributes()getAttributes()

Page 29: 第 10 章  XML DOM 物件模型

Node Node 節點物件節點物件 Node Node 節點物件還提供更多方法能夠瀏覽節點物件還提供更多方法能夠瀏覽XML XML 文件來取得指定節點,相關方法的說文件來取得指定節點,相關方法的說明,如下表所示:明,如下表所示:方法 說明

getFirstChild() 取得第一個子節點getLastChild() 取得最後一個子節點

getNextSibling() 取得下一個兄弟節點,兩個節點擁有相同的父節點稱為兄弟節點

getParentNode() 取得父節點

Page 30: 第 10 章  XML DOM 物件模型

NodeList NodeList 節點清單的集合物件節點清單的集合物件 當在 當在 JavaJava 程式呼叫 程式呼叫 getChildNodes()getChildNodes() 方法,方法,

或是 或是 getElementByTagName()getElementByTagName() 方法取得指定節方法取得指定節點時,這些節點是一個 點時,這些節點是一個 NodeListNodeList 集合物件(也集合物件(也就是類似 就是類似 ListList 的結構),而每一個節點包含該節的結構),而每一個節點包含該節點和其子節點的一棵子樹。點和其子節點的一棵子樹。

在 在 NodeList NodeList 物件的 物件的 getLength() getLength() 方法可以方法可以取得共擁有多少個節點。例如:使用 取得共擁有多少個節點。例如:使用 for for 迴圈顯迴圈顯示所有示所有 NodeList NodeList 物件的節點,如下所示:物件的節點,如下所示:

NodeList nodes = root.getChildNodes();NodeList nodes = root.getChildNodes();for (int i=0; i < nodes.getLength(); i++) { for (int i=0; i < nodes.getLength(); i++) { System.out.println("System.out.println(" 元素元素 : " + : " + nodes.item(i).getNodeName());nodes.item(i).getNodeName());}}

Page 31: 第 10 章  XML DOM 物件模型

NodeList NodeList 節點清單的集合物件節點清單的集合物件 NodeNode 節點物件的 節點物件的 getChildNodes() getChildNodes() 方法可以方法可以

在樹狀結構的節點取得所需的子節點,如下所示:在樹狀結構的節點取得所需的子節點,如下所示:

System.out.print(root.getChildNodes().item(1).System.out.print(root.getChildNodes().item(1).

getChildNodes().item(2).getNodeName());getChildNodes().item(2).getNodeName());

• 程式碼在取得根節點 程式碼在取得根節點 root root 物件後,使用物件後,使用getChildNodes() getChildNodes() 方法取得下一層第 方法取得下一層第 2 2 個節點的第 個節點的第 33 個子節點,對應 個子節點,對應 XML XML 元素就是第 元素就是第 2 2 個 個 book book 元素元素的第的第 33 個子元素 個子元素 priceprice 。。

Page 32: 第 10 章  XML DOM 物件模型

ElementElement 元素物件元素物件 Element Element 物件代表樹狀結構的 物件代表樹狀結構的 XML XML 元素節點:元素節點:

• NodeList tagNodes = NodeList tagNodes = document.getElementsByTagName("book");document.getElementsByTagName("book");

• System.out.println(tagNodes.item(i).getTagName(System.out.println(tagNodes.item(i).getTagName());));

• 由於 由於 getElementsByTagName() getElementsByTagName() 回傳一個由 回傳一個由 Element Element 物件所組成的 物件所組成的 NodeListNodeList ,因此可以使用 ,因此可以使用 getTagName() getTagName() 方方法取得標籤名稱法取得標籤名稱

Element Element 物件還提供 物件還提供 getAttribute() getAttribute() 方方法取得法取得 XML XML 元素的指定屬性值,如下所示:元素的指定屬性值,如下所示:• tagNodes.item(i).getAttribute("code")tagNodes.item(i).getAttribute("code")• Note: Element Note: Element 也是 也是 Node Node 的子類別的子類別

Page 33: 第 10 章  XML DOM 物件模型

Text Text 內容節點物件內容節點物件 Text Text 物件指的為 物件指的為 XML XML 元素的文字內容。元素的文字內容。 NOTE:NOTE: Text Text 也是 也是 Node Node 的子類別。的子類別。

Page 34: 第 10 章  XML DOM 物件模型

NamedNodeMap NamedNodeMap 集合物件集合物件 NamedNodeMap NamedNodeMap 集合物件是元素的屬性集合(類似 集合物件是元素的屬性集合(類似 MapMap 的結構)。因為一個的結構)。因為一個 XMLXML元素可以擁有多個屬性,元素可以擁有多個屬性,且每一個屬性名稱都有一個對應的屬性值,可以配合且每一個屬性名稱都有一個對應的屬性值,可以配合forfor迴圈來取出所有屬性,如下所示:迴圈來取出所有屬性,如下所示:

NamedNodeMap atts = NamedNodeMap atts = tagNodes.item(i).getAttributes();tagNodes.item(i).getAttributes();for (int j = 0; j < atts.getLength(); j++) {for (int j = 0; j < atts.getLength(); j++) { Node att = atts.item(j);Node att = atts.item(j); System.out.print(" +-- "+att.getNodeName());System.out.print(" +-- "+att.getNodeName()); System.out.println("/"+att.getNodeValue());System.out.println("/"+att.getNodeValue());}}

Page 35: 第 10 章  XML DOM 物件模型

練習題練習題 請改寫 請改寫 Ch10_3_1.java Ch10_3_1.java 使得元素的屬性輸出會直接使得元素的屬性輸出會直接

出現在元素之後,而且屬性名稱之前多了字元 出現在元素之後,而且屬性名稱之前多了字元 @@ ,範例,範例結果如下:結果如下:

Page 36: 第 10 章  XML DOM 物件模型

新增新增 XMLXML 元素和屬性元素和屬性 -- 建立建立 DOMDOM

XML DOM XML DOM 物件模型除了可以存取 物件模型除了可以存取 XML XML 文件的節文件的節點外,也可以更改樹狀結構點外,也可以更改樹狀結構• 例如:自行新增節點和屬性來建立新的 例如:自行新增節點和屬性來建立新的 XML DOM XML DOM 物件。物件。

我們先以建立新的 我們先以建立新的 DOMDOM 為例為例• 建立新的 建立新的 XML DOM XML DOM 的語法如下:的語法如下:

DocumentBuilder db = dbf.newDocumentBuilder();DocumentBuilder db = dbf.newDocumentBuilder();Document document = db.newDocument();Document document = db.newDocument();

• 程式碼使用 程式碼使用 newDocument() newDocument() 方法建立 方法建立 XML DOM XML DOM 後,後,就可以使用相關方法來新增根元素、子元素和屬性。就可以使用相關方法來新增根元素、子元素和屬性。

• 如果觀念清楚的話,以下的說明也可以用來為某一已經存在如果觀念清楚的話,以下的說明也可以用來為某一已經存在的 的 XML XML 文件新增節點。(只需把 文件新增節點。(只需把 newDocument() newDocument() 換換成 成 parse() parse() 並找到必要的 並找到必要的 context nodecontext node ))

Page 37: 第 10 章  XML DOM 物件模型

新增新增 XMLXML 元素和屬性元素和屬性 -- 步驟一步驟一第一步:建立新節點第一步:建立新節點 使用使用 DocumentDocument 物件的相關方法來建立所需的物件的相關方法來建立所需的

節點物件節點物件 例如:在新建立的 例如:在新建立的 XML DOM XML DOM 新增元素,如下新增元素,如下

所示:所示:(請注意:只是新增節點,該節點與 (請注意:只是新增節點,該節點與 document document 之間暫時還沒有關係)之間暫時還沒有關係)

Element root = (Element) Element root = (Element)

document.createElement("book");document.createElement("book");

• 程式碼使用 程式碼使用 createElement() createElement() 方法建立 方法建立 Element Element 元素物件 元素物件 bookbook ,這就是新文件的根元素。,這就是新文件的根元素。

Page 38: 第 10 章  XML DOM 物件模型

新增新增 XMLXML 元素和屬性元素和屬性 -- 步驟二步驟二第二步:插入指定的位置第二步:插入指定的位置 在建立好 在建立好 XML XML 元素的相關物件後,我們可以使元素的相關物件後,我們可以使

用 用 Node Node 節點物件的相關方法將節點新增到樹節點物件的相關方法將節點新增到樹狀結構的 狀結構的 XML DOM XML DOM 中,相關方法的說明如下中,相關方法的說明如下所示:所示:• appendChild(newnode) appendChild(newnode) ::新增 新增 newnode newnode 節點節點為其最後一個子節點。為其最後一個子節點。

• insertBefore(newnode, befnode) insertBefore(newnode, befnode) ::將 將 newnodenewnode 節點插在 節點插在 befnode befnode 節點前。節點前。

例如:將 例如:將 root root 節點新增成為 節點新增成為 XML DOM XML DOM 的的根節點,如下所示:根節點,如下所示:

document.appendChild(root);document.appendChild(root);

Page 39: 第 10 章  XML DOM 物件模型

新增新增 XMLXML 元素和屬性元素和屬性 -- 步驟三步驟三第三步:新增元素的內容第三步:新增元素的內容 在元素新增內容,就是新增文字值的子節點,在元素新增內容,就是新增文字值的子節點,如下所示:如下所示:

Element node = (Element) Element node = (Element)

document.createElement("code");document.createElement("code");

Text t = (Text) Text t = (Text) document.createTextNode("P761");document.createTextNode("P761");

node.appendChild(t);node.appendChild(t);

root.appendChild(node);root.appendChild(node);

Page 40: 第 10 章  XML DOM 物件模型

新增新增 XMLXML 元素和屬性元素和屬性 -- 步驟四步驟四第四步:新增元素的屬性第四步:新增元素的屬性 在 在 XML XML 節點如果擁有屬性,節點如果擁有屬性, Element Element 元素物件可以使用 元素物件可以使用 setAttribute() setAttribute() 方方法建立屬性,如下所示:法建立屬性,如下所示:

node.setAttribute("instock", node.setAttribute("instock", "Y");"Y");•程式碼新增名為程式碼新增名為 instockinstock 的屬性,第的屬性,第 11 個參數個參數是屬性名稱,第是屬性名稱,第 22 個參數是屬性值。個參數是屬性值。

Page 41: 第 10 章  XML DOM 物件模型

刪除刪除 XMLXML 元素和屬性元素和屬性 如果需要刪除節點或屬性,我們可以使用 如果需要刪除節點或屬性,我們可以使用 Node Node 節點的節點的removeChild() removeChild() 方法從樹狀結構刪除指定的節點,如方法從樹狀結構刪除指定的節點,如下所示:下所示:

// // 取得 取得 node node 的一個子節點 的一個子節點 onechildonechildnode.removeChild(onechild);node.removeChild(onechild);

如果想刪除屬性,則是使用 如果想刪除屬性,則是使用 Element Element 元素物件的元素物件的removeAttribute() removeAttribute() 方法來刪除屬性,如下所示:方法來刪除屬性,如下所示:

// // 取得一個 取得一個 Element Element 節點 節點 deldeldel.removeAttribute("instock");del.removeAttribute("instock");

Page 42: 第 10 章  XML DOM 物件模型

變更變更 XML XML 元素或者屬性內容元素或者屬性內容

如果需要變更節點或屬性內容,我們使用 如果需要變更節點或屬性內容,我們使用 setTextContent() setTextContent() 方法,範例如下:方法,範例如下:

修改元素內容,把修改元素內容,把 code code 的 的 P761 P761 改成改成 XXXXXX ,如下,如下所示:所示:Element element = Element element = document.getDocumentElement().getFirstChild();document.getDocumentElement().getFirstChild();

element.setTextContent("XXX");element.setTextContent("XXX");

修改屬性 修改屬性 instock instock 內容:內容:Element element = Element element = document.getDocumentElement().getFirstChild();document.getDocumentElement().getFirstChild();

Attr attr = elem.getAttributeNode("instock");Attr attr = elem.getAttributeNode("instock");attr.setTextContent("n");attr.setTextContent("n");

Page 43: 第 10 章  XML DOM 物件模型

變更變更 XML XML 元素或者屬性名稱元素或者屬性名稱

如果需要變更節點或屬性名稱,我們可以使用 如果需要變更節點或屬性名稱,我們可以使用 Document Document 節點的節點的 renameNode() renameNode() 方法,語法如下:方法,語法如下:

// // 改變 改變 node node 的名稱為的名稱為 newNamenewNamedocument.renameNode(node, [new namespace], document.renameNode(node, [new namespace], [newName]);[newName]);

如果保留原來的如果保留原來的 namespacenamespace ,把原來的名稱從,把原來的名稱從 library library 改成改成 booksbooks ,如下所示:,如下所示:// // 假設取得一個 假設取得一個 Element Element 節點 節點 elementelementElement element = document.getDocumentElement();Element element = document.getDocumentElement();document.renameNode(element, document.renameNode(element, element.getNamespaceURI(), “books”);element.getNamespaceURI(), “books”);

Page 44: 第 10 章  XML DOM 物件模型

Ch10_4_4import javax.xml.parsers.*;import org.xml.sax.*; import java.io.*;import org.w3c.dom.*;public class Ch10_4_4 { static Document document; public static void main(String[] args) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); // 建立新 XML文件 document = db.newDocument(); // 建立根元素 Element root = document.createElement("book"); document.appendChild(root); // 新增子元素 code Element node = document.createElement("code"); root.appendChild(node); node.appendChild(document.createTextNode("P761")); // 新增子元素 title node = document.createElement("title"); root.appendChild(node); node.appendChild(document.createTextNode("PHP 5網頁設計範例教本 "));

Page 45: 第 10 章  XML DOM 物件模型

Ch10_4_4 // 新增 author元素 Element newNode = document.createElement("author"); root.insertBefore(newNode, root.getFirstChild()); Node newText = document.createTextNode("陳會安 "); root.getFirstChild().appendChild(newText); // 新增屬性 node=(Element)root.getFirstChild().getNextSibling(); node.setAttribute("instock","Y");

System.out.println("建立的 XML文件 : "); printXML(root);

// 刪除 author元素 root.removeChild((Element) root.getElementsByTagName("author").item(0)); // 刪除 code屬性 instock Element del = (Element) root.getFirstChild(); del.removeAttribute("instock"); System.out.println("刪除後的 XML文件 : "); printXML(root); }

Page 46: 第 10 章  XML DOM 物件模型

Ch10_4_4 // 顯示 XML文件 private static void printXML(Node root) { System.out.println("根元素 : "+root.getNodeName()); NodeList nodes = root.getChildNodes(); // 取得所有的子節點 for ( int i=0; i < nodes.getLength(); i++ ) { // 元素和文字節點 System.out.print("元素 : " + nodes.item(i).getNodeName()); System.out.println("/"+nodes.item(i).getFirstChild().getNodeValue()); // 顯示指定元素的屬性值 if (nodes.item(i).hasAttributes()) { NamedNodeMap atts = nodes.item(i).getAttributes(); for (int j = 0; j < atts.getLength(); j++) { Node att = atts.item(j); System.out.print(" +-- "+att.getNodeName()); System.out.println("/"+att.getNodeValue()); } } } }}

Page 47: 第 10 章  XML DOM 物件模型

Ch10_4_4 // 輸出 XML 文件 private static void printXML(Node root) { PrintWriter out = new PrintWriter(new FileWriter("test.xml")); out.println("根元素 : "+root.getNodeName()); NodeList nodes = root.getChildNodes(); for ( int i=0; i < nodes.getLength(); i++ ) { out.print("元素 : " + nodes.item(i).getNodeName()); out.println("/"+nodes.item(i).getFirstChild().getNodeValue()); // 顯示指定元素的屬性值 if (nodes.item(i).hasAttributes()) { NamedNodeMap atts = nodes.item(i).getAttributes(); for (int j = 0; j < atts.getLength(); j++) { Node att = atts.item(j); out.print(" +-- "+att.getNodeName()); out.println("/"+att.getNodeValue()); } } } out.close(); }}

Page 48: 第 10 章  XML DOM 物件模型

練習題練習題 請修改 請修改 Ch10_4_1 Ch10_4_1 並使其能夠產生 並使其能夠產生 Books.xml Books.xml 的 的 XML XML 文件。文件。

Page 49: 第 10 章  XML DOM 物件模型

DTD DTD 驗證驗證 JAXP API 1.1 JAXP API 1.1 版只支援 版只支援 DTD DTD 驗證,驗證,並不支援 並不支援 XML SchemaXML Schema(( 1.21.2 版之後才版之後才支援)。當支援)。當 XML XML 文件指定 文件指定 DTD DTD 檔案,檔案,在 在 XML XML 剖析器載入 剖析器載入 XML XML 文件時,就可文件時,就可以進行以進行 XMLXML 文件的驗證。文件的驗證。• JDK 1.4 supports JAXP API 1.1• JDK 1.5 supports JAXP API 1.3• JDK 1.6 JDK 1.6 supports JAXP API 1.4

Page 50: 第 10 章  XML DOM 物件模型

TestXSD// 驗證 XML Schemaimport java.io.*;import javax.xml.parsers.*;import org.w3c.dom.*;import org.xml.sax.*;

public class TestXSD { public static void main(String[] args) { if(args.length != 1) { System.out.println("Usage: java TestXSD myFile.xml"); System.exit(-1); } String xmlFile = args[0]; try { TestXSD xmlTester = new TestXSD(xmlFile); } catch (Exception e) { System.out.println( e.getClass().getName() +": "+ e.getMessage() ); } }

Page 51: 第 10 章  XML DOM 物件模型

TestXSD public TestXSD(String xmlFile) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); System.out.println("Parser名稱 : "+ factory.getClass().getName()); // 預設為 false ,必須是 true ,因為 xsd:schema factory.setNamespaceAware(true); factory.setValidating(true);

// 明確告知 JAXP 所使用的 Schema 語言 factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); // Specify our own schema - this overrides the schemaLocation in the xml file //factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", "file:./person1.xsd"); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new SimpleErrorHandler() );

// parse 錯誤會引起 SAXException Document document = builder.parse(xmlFile); Node rootNode = document.getFirstChild(); System.out.println("Root node: "+ rootNode.getNodeName()); } }

Page 52: 第 10 章  XML DOM 物件模型

SimpleErrorHandlerimport org.xml.sax.ErrorHandler;import org.xml.sax.SAXParseException; public class SimpleErrorHandler implements ErrorHandler { public void error(SAXParseException exception) { System.out.println("error: "+ exception.getMessage()); } public void fatalError(SAXParseException exception) { System.out.println("fatalError: "+ exception.getMessage()); } public void warning(SAXParseException exception) { System.out.println("warning: "+ exception.getMessage()); }}

Page 53: 第 10 章  XML DOM 物件模型

XPath API JDK 1.5 版之後,提供了一個非常好用的 XPath API,其 package 為 javax.xml.xpath.•步驟一:把 XML 檔案依照之前的方式載入

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();

domFactory.setNamespaceAware(true); // never forget this!

DocumentBuilder builder = domFactory.newDocumentBuilder();

Document doc = builder.parse("Books.xml");

Page 54: 第 10 章  XML DOM 物件模型

XPath API

•步驟二:產生 XPath 物件// 載入 XPathFactoryXPathFactory factory = XPathFactory.newInstance();

// 利用 XPathFactory 產生 XPath 處理器XPath xpath = factory.newXPath();

•步驟三:產生 XPath Expression,執行結果為一個 NodeList 物件// compile XPath 敘述XPathExpression expr = xpath.compile("//book/title/text()");

// 進行 XPath 敘述的執行,並回傳 NODESETObject result = expr.evaluate(doc, XPathConstants.NODESET);

Page 55: 第 10 章  XML DOM 物件模型

TestXPathimport java.io.IOException;import org.w3c.dom.*;import org.xml.sax.SAXException;import javax.xml.parsers.*;import javax.xml.xpath.*;

public class TestXPath { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {

// 跟以前載入文件進行剖析相同 DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); // never forget this! DocumentBuilder builder = domFactory.newDocumentBuilder(); Document doc = builder.parse("Books.xml");

Page 56: 第 10 章  XML DOM 物件模型

TestXPath // 載入 XPathFactory XPathFactory factory = XPathFactory.newInstance();

// 利用 XPathFactory 產生 XPath 物件 XPath xpath = factory.newXPath();

// compile XPath 敘述 XPathExpression expr = xpath.compile("//book/title/text()");

// 進行 XPath 敘述的執行 // 若要回傳字串,則可改成 XPathConstants.STRING Object result = expr.evaluate(doc, XPathConstants.NODESET);

// 或者 // Object result = xpath.evaluate(“//book/title/text()”, // doc, XPathConstants.NODESET);

NodeList nodes = (NodeList) result; for (int i = 0; i < nodes.getLength(); i++) { System.out.println(nodes.item(i).getNodeValue()); } }}

Page 57: 第 10 章  XML DOM 物件模型

練習題練習題 請完成第六章的練習:請找出所有非英文的書籍請完成第六章的練習:請找出所有非英文的書籍

並以條列示的方式列印出書籍的名稱以及價格。並以條列示的方式列印出書籍的名稱以及價格。• 利用產生文件的方式產生一份 利用產生文件的方式產生一份 XHTML XHTML 的文件的文件• 利用 利用 XPath XPath 語法來找到所需的節點語法來找到所需的節點

Page 58: 第 10 章  XML DOM 物件模型

JAXP JAXP 的 的 XSLT APIXSLT API JAXP API JAXP API 的 的 XSLT APIXSLT API(( XML XML Stylesheet Translation APIStylesheet Translation API )是使用)是使用javax.xml.transform javax.xml.transform 套件的套件的TransformerFactory TransformerFactory 類別來建立 類別來建立 Transformer Transformer 實例,以便執行 實例,以便執行 XSLT XSLT 轉換,轉換,如下圖所示:如下圖所示:

Page 59: 第 10 章  XML DOM 物件模型

JAXP JAXP 的 的 XSLT API XSLT API 套件說明套件說明 XSLT API XSLT API 的相關套件說明,如下表所示:的相關套件說明,如下表所示:

套件 說明javax.xml.transform XSLT API的主要套件,定義 TransformerFactory

和 Transformer類別,並且提供 transform()方法執行 XSLT轉換

javax.xml.transform.dom 定義從 DOM輸入或輸出的物件javax.xml.transform.sax 定義 SAX的輸入或輸出物件

javax.xml.transform.stream 定義從檔案串流輸入或輸出的物件

Page 60: 第 10 章  XML DOM 物件模型

XSLTXSLT 轉換轉換 XMLXML 文件文件 在匯入套件後,就可以建立 在匯入套件後,就可以建立 TransformerFactory TransformerFactory 物件物件tff tff 和 和 Transformer Transformer 物件 物件 tftf(( XSLTXSLT 處理器),如下所處理器),如下所示:示:

TransformerFactory tff = TransformerFactory.newInstance();TransformerFactory tff = TransformerFactory.newInstance();Transformer tf = tff.newTransformer(newTransformer tf = tff.newTransformer(new

StreamSource(xsltFile));StreamSource(xsltFile));

接著使用 接著使用 transform() transform() 方法將 方法將 XML XML 文件使用 文件使用 XSLT XSLT 文文件執行轉換,如下所示:件執行轉換,如下所示:

tf.transform(new StreamSource(new StringReader(xmlData)), tf.transform(new StreamSource(new StringReader(xmlData)), new StreamResult(new new StreamResult(new

FileOutputStream(htmlFile)));FileOutputStream(htmlFile)));

Page 61: 第 10 章  XML DOM 物件模型

Ch10_6_2Ch10_6_2import javax.xml.transform.*;import javax.xml.transform.stream.*;import java.io.*;public class Ch10_6_2 { public Ch10_6_2() {}

// 建立 HTML文件 public void buildHTML(String xmlData, String htmlFile, String xsltFile) throws Exception { // 建立 TransformerFactory物件 TransformerFactory tff = TransformerFactory.newInstance(); // 建立 Transformer物件 Transformer tf = tff.newTransformer(new StreamSource(xsltFile)); // 轉換 XML tf.transform(new StreamSource(new StringReader(xmlData)), new StreamResult(new FileOutputStream(htmlFile))); System.out.println("XSLT轉換成功 :"+htmlFile); }

Page 62: 第 10 章  XML DOM 物件模型

Ch10_6_2Ch10_6_2 // 主程式 public static void main(String[] args) throws Exception { String htmlFile = "Ch10-6-2.htm"; String xsltFile = "Books.xslt"; String xmlFile = "Books.xml"; Ch10_6_2 app = new Ch10_6_2(); BufferedReader br = new BufferedReader(new FileReader(xmlFile)); String strLine; StringBuffer strBuffer = new StringBuffer();

// 讀取 XML文件的內容 while ( (strLine = br.readLine()) != null ) { strBuffer.append(strLine+"\n"); }

// 呼叫方法建立轉換輸出的 HTML文件 app.buildHTML(strBuffer.toString(), htmlFile, xsltFile); }}

Page 63: 第 10 章  XML DOM 物件模型

Ch10PrintCh10Printimport javax.xml.transform.*;import javax.xml.transform.stream.*;import java.io.*;

public class Ch10Print { public Ch10Print() {}

// HTML 的結果由螢幕輸出 public void buildHTML(String xmlData, String xsltFile) throws Exception { // 建立 TransformerFactory物件 TransformerFactory tff = TransformerFactory.newInstance(); // 建立 Transformer物件 // 若不指定任何 xsltFile,則不做任何轉換,而直接輸出 //Transformer tf = tff.newTransformer(); Transformer tf = tff.newTransformer(new StreamSource(xsltFile)); // 轉換 XML tf.transform(new StreamSource(new StringReader(xmlData)), new StreamResult(new OutputStreamWriter(System.out))); }

Page 64: 第 10 章  XML DOM 物件模型

Ch10PrintCh10Printimport javax.xml.transform.*;import javax.xml.transform.stream.*;import java.io.*;

public class Ch10Print { public Ch10Print() {}

// HTML 的結果由螢幕輸出 public void buildHTML(String xmlData, String xsltFile) throws Exception { // 建立 TransformerFactory物件 TransformerFactory tff = TransformerFactory.newInstance(); // 建立 Transformer物件 // 若不指定任何 xsltFile,則不做任何轉換,而直接輸出 //Transformer tf = tff.newTransformer(); Transformer tf = tff.newTransformer(new StreamSource(xsltFile)); // 轉換 XML tf.transform(new StreamSource(new StringReader(xmlData)), new StreamResult(new OutputStreamWriter(System.out))); }

Page 65: 第 10 章  XML DOM 物件模型

Ch10PrintCh10Print

// HTML 的結果由螢幕輸出 public void buildHTML(String xmlData, String xsltFile) throws Exception { // 建立 TransformerFactory物件 TransformerFactory tff = TransformerFactory.newInstance();

// 建立 Transformer物件 // 若不指定任何 xsltFile,則不做任何轉換,而直接輸出 Transformer tf = tff.newTransformer(); //Transformer tf = tff.newTransformer(new StreamSource(xsltFile));

// 轉換 XML,若 XML 的資料來源是 Document 物件 tf.transform(new DOMSource(document)), new StreamResult(new OutputStreamWriter(System.out))); }

Page 66: 第 10 章  XML DOM 物件模型

Ch10PrintCh10Print // 主程式 public static void main(String[] args) throws Exception { String xsltFile = "Books.xslt"; String xmlFile = "Books.xml"; Ch10Print app = new Ch10Print(); BufferedReader br = new BufferedReader(new FileReader(xmlFile)); String strLine; StringBuffer strBuffer = new StringBuffer(); // 讀取 XML文件的內容 while ( (strLine = br.readLine()) != null ) { strBuffer.append(strLine+"\n"); } // 呼叫方法建立轉換輸出的 HTML文件 app.buildHTML(strBuffer.toString(), xsltFile); }}

Page 67: 第 10 章  XML DOM 物件模型

作業作業 利用 利用 JSP JSP 來完成之前的 來完成之前的 XML XML 以及 以及 XLST XLST 的轉換,但是結果是由網頁呈現的轉換,但是結果是由網頁呈現•後端的程式是以 後端的程式是以 JSP JSP 開發開發•伺服器可以由 伺服器可以由 Tomcat Tomcat 來擔任來擔任•允許使用者選定 允許使用者選定 XML XML 和 和 XSLT XSLT 檔。檔。

Page 68: 第 10 章  XML DOM 物件模型

TomcatTomcat

Tomcat Tomcat 是一個兼具 是一個兼具 Web Server Web Server 以以及 及 JSP/Java Servlet JSP/Java Servlet 的 的 engineengine•雖然可以被用來當作 雖然可以被用來當作 web serverweb server ,但是一,但是一般都不建議這樣子使用,因為 般都不建議這樣子使用,因為 Apache Apache 的效的效能以及功能都比 能以及功能都比 Tomcat Tomcat 強強

•請參考如何將 請參考如何將 Apache Apache 以及 以及 Tomcat Tomcat 結合結合使用的方法使用的方法

•我們以下說明的指針對架設 我們以下說明的指針對架設 Tomcat Tomcat (在 (在 Windows Windows 的環境)並寫出一個簡單的 的環境)並寫出一個簡單的 JSP JSP 為例。為例。

Page 69: 第 10 章  XML DOM 物件模型

安裝 安裝 TomcatTomcat 安裝 安裝 JDK 8.x JDK 8.x 版版

• 設定環境變數 設定環境變數 JAVA_HOME JAVA_HOME 指向 指向 JDK JDK 的安裝目錄的安裝目錄• ex. set JAVA_HOME=c:\jdkex. set JAVA_HOME=c:\jdk

安裝 安裝 Tomcat 8.xTomcat 8.x• 下載點 下載點 http://tomcat.apache.org/download-80.cgi

• 請下載請下載 windows windows 版的 版的 zip zip 檔檔並將它解壓縮到 並將它解壓縮到 d:\d:\ (或者 (或者 c:\c:\ ))

• 為了減少 為了減少 typingtyping ,將目錄名稱從 ,將目錄名稱從 apache-apache-tomcat-8.0.x tomcat-8.0.x 改成 改成 tomcattomcat

Page 70: 第 10 章  XML DOM 物件模型

測試 測試 TomcatTomcat 開啟開啟””命令提示字元命令提示字元””,,

並 並 cd cd 到 到 d:\d:\tomcat\bintomcat\bin

執行 執行 .\.\startup.batstartup.bat• 你將會看到一連串的訊你將會看到一連串的訊

息息 開啟你喜歡的瀏覽器,開啟你喜歡的瀏覽器,

並輸入並輸入• http://127.0.0.1:8080/

如果你的結果如右圖,如果你的結果如右圖,表示你的安裝成功表示你的安裝成功• 你也可以在進一步測試你也可以在進一步測試

一下 一下 tomcat tomcat 提供的 提供的 JSP JSP 和 和 servlet servlet 的的範例範例

Page 71: 第 10 章  XML DOM 物件模型

JSP JSP 的架構的架構

Client

Client

Client

Internet

Web Server

Tomcat(ServletEngine)

HttpServletRequest

HttpServletResponse

Servlet/JSP

request

out

Page 72: 第 10 章  XML DOM 物件模型

JSP JSP 程式環境設定程式環境設定•建立一個目錄建立一個目錄

mkdir d:\tomcat\webapps\xmlmkdir d:\tomcat\webapps\xml

xml xml 為為 project project 名稱名稱 JSP JSP 程式和程式和 xml xml 檔都放在這個目錄檔都放在這個目錄

JDBC JDBC 等共用程式庫可以放在等共用程式庫可以放在 d:\d:\tomcat\libtomcat\lib ,或者,或者

給給 xml xml 這個專案用的,可以放在這個專案用的,可以放在 d:\d:\tomcat\webapps\xml\WEB-INF\lib tomcat\webapps\xml\WEB-INF\lib

Page 73: 第 10 章  XML DOM 物件模型

第一個 第一個 JSPJSP<!-- hello1.jsp --><html><head><title>Hello World</title></head>

<!-- HTML 碼與程式碼交叉出現;程式碼 <% %> 成對 --><body>

<!-- 宣告變數 s --><% String s = "Eric"; %>

<!-- 使用變數 s --><h1>Hello <%=s%></h1></body></html>

Page 74: 第 10 章  XML DOM 物件模型

第一個 第一個 JSPJSP Tomcat Tomcat 會自動會自動 parsing parsing 語法,並將程式自語法,並將程式自

動轉換為動轉換為 Java ServletJava Servlet ,然後進行,然後進行 compile.compile.

compile compile 完了以後,完了以後, Tomcat Tomcat 把 把 .class .class 安裝到適當的目錄並執行該安裝到適當的目錄並執行該 servletservlet

請在 請在 browser browser 執行執行• http://localhost:8080/xml/hello1.jsp

Page 75: 第 10 章  XML DOM 物件模型

第二個 第二個 JSPJSP<html><head><meta http-equiv="Content-Type" content="text/html;charset=Big5"><title>Hello Form</title></head>

<body><form method="post" action="http://localhost:8080/xml/hello2.jsp"><input type="text" value="老呂 " name="data"><input type="submit"></form></body></html>

Page 76: 第 10 章  XML DOM 物件模型

第二個 第二個 JSPJSP<%@ page language="java" contentType="text/html;charset=Big5" %><html><head><title>Greetings</title></head>

<body><% String s = new String(request.getParameter("data").getBytes("ISO-8859-1"), "Big5");%>

<h1>Hello <%=s%></h1>

<% out.println("<h1>試試看 out 物件 </h1>"); // 可以加上 System.out.println("Standard Output");%></body></html>

Page 77: 第 10 章  XML DOM 物件模型

第二個 第二個 JSPJSP

Page 78: 第 10 章  XML DOM 物件模型

第三個 第三個 JSPJSP 在在 JSP JSP 內使用我們已經定義好的類別內使用我們已經定義好的類別

• 以我們最熟悉的以我們最熟悉的 Worker.class Worker.class 為例為例

很不方便的,很不方便的, JSP JSP 的的 import import 只允許有只允許有 package package 名稱的類別(好吧,這也是好的寫作方式)名稱的類別(好吧,這也是好的寫作方式)• 假設假設 package package 名稱是名稱是 xmlxml• 請在請在 Worker.java Worker.java 的第一行加上的第一行加上 package xml; package xml; 並重新並重新 compilecompile

• 請把請把 Worker.class Worker.class 放到放到 d:\tomcat\webapps\xml\d:\tomcat\webapps\xml\WEB-INF\classes\xml WEB-INF\classes\xml 目錄內目錄內

Page 79: 第 10 章  XML DOM 物件模型

第三個 第三個 JSPJSP<html><head><meta http-equiv="Content-Type" content="text/html;charset=Big5"><title>Hello Form</title></head>

<body><form method="post" action="http://localhost:8080/xml/worker2.jsp">Hours: <input type="text" value="45" name="data"><input type="submit"></form></body></html>

Page 80: 第 10 章  XML DOM 物件模型

第三個 第三個 JSPJSP<%@ page language="java" contentType="text/html;charset=Big5” import="xml.Worker"%><html><head><title>Calculate Salary</title></head>

<body><% String s = new String(request.getParameter("data").getBytes("ISO-8859-1"), "Big5");%><h1>Calcuate Salary</h1><% int h = Integer.parseInt(s); Worker w = new Worker(h); out.println("<h3>"+ w.computeSalary() +"</h1>");%></body></html>

Page 81: 第 10 章  XML DOM 物件模型

JSP and DOMJSP and DOM

首先將我們的 首先將我們的 XML XML 的測試檔 的測試檔 Books.xml Books.xml 置放於 置放於 d:\tomcat\d:\tomcat\webapps\xml webapps\xml 的目錄內。的目錄內。

將 將 Ch10_3_1.java Ch10_3_1.java 改成如下頁的 改成如下頁的 DOMServ.jsp DOMServ.jsp 並將它放於 並將它放於 d:\d:\tomcat\webapps\xmltomcat\webapps\xml

在瀏覽器內執行在瀏覽器內執行• http://localhost:8080/xml/http://localhost:8080/xml/DOMServ.jspDOMServ.jsp

Page 82: 第 10 章  XML DOM 物件模型

JSP and DOMJSP and DOM<%@page contentType="text/html" pageEncoding="Big5" import="java.lang.*,java.util.*,javax.xml.parsers.*,org.xml.sax.*,org.w3c.dom.*,java.io.*" %><%! String filename = "Books.xml"; StringBuffer buf = new StringBuffer(""); private void pChild(Node temp,int pos, StringBuffer buf) { if ( temp.hasChildNodes() ) { NodeList nodes = temp.getChildNodes(); for (int i=0; i < nodes.getLength(); i++) { int type = nodes.item(i).getNodeType(); if ( type == Node.ELEMENT_NODE ) { printIndent(pos, buf); buf.append(" 元素 : " + nodes.item(i).getNodeName()+"<br/>"); pChild(nodes.item(i), pos+1, buf); } if ( type == Node.TEXT_NODE ) { String val = nodes.item(i).getNodeValue(); if ( val != null ) { printIndent(pos, buf); buf.append(" 元素 : " + nodes.item(i).getNodeName());

Page 83: 第 10 章  XML DOM 物件模型

JSP and DOMJSP and DOM buf.append("/元素值 : "); if ( val.trim().equals("") ) buf.append("WS"+"<br/>"); else buf.append(val+"<br/>"); } } } } }

private void printIndent(int num, StringBuffer buf) { buf.append("&nbsp;&nbsp;+"); for (int i=0; i<=num; i++) buf.append("-"); }%>

<% buf.append("<html><head><title>\n"); buf.append("DOM and JSP\n"); buf.append("</title></head><body>\n"); Document document; DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); dbf.setIgnoringElementContentWhitespace(true);

Page 84: 第 10 章  XML DOM 物件模型

JSP and DOMJSP and DOM try {

DocumentBuilder db = dbf.newDocumentBuilder();// 讀取 Books.xml

File file = new File(getServletContext().getRealPath("/")+"/"+filename);

document = db.parse(file);System.out.println("read file succeed.");Node child = (Node)document.getFirstChild();for ( ; child != null; child = child.getNextSibling() ) { //<br/> 給 browser 用的, \n 給檢視原始碼用的

buf.append("<b>元素 :</b>"+child.getNodeName()+"<br/>\n"); buf.append("/型態 :"+child.getNodeType()+"<br/>\n"); pChild(child, 0, buf); }

buf.append("</body></html>\n");out.println(buf.toString());out.close();

}catch(SAXException se) {System.out.println("error");}catch(ParserConfigurationException pce){ System.out.println("errorfffff");}catch(Exception ee){

ee.printStackTrace();}

%>

Page 85: 第 10 章  XML DOM 物件模型

練習題練習題 請先把之前的範例跟著做一次請先把之前的範例跟著做一次 請把兩個範例改成可以由使用者輸入的方式來進請把兩個範例改成可以由使用者輸入的方式來進

行行• 改 改 DOMServ.java DOMServ.java 使得使用者可以輸入一個 使得使用者可以輸入一個 XML XML 檔,並由 檔,並由 DOMServ DOMServ 來輸出結果(提示在下一頁)來輸出結果(提示在下一頁)

• 改 改 XSLTServ.java XSLTServ.java 使得使用者可以輸入一個 使得使用者可以輸入一個 XML XML 和 和 XSL XSL 檔,並由 檔,並由 XSLTServ XSLTServ 來輸出結果來輸出結果

tf.transform(new DOMSource(document), tf.transform(new DOMSource(document), new StreamResult(new new StreamResult(new

PrintWriter("out.xml")));PrintWriter("out.xml")));

Page 86: 第 10 章  XML DOM 物件模型

練習題練習題 請製作一個 請製作一個 web-based web-based 的 的 XPath XPath 處理器處理器

• 先由使用者輸入 先由使用者輸入 XML XML 檔案檔案• 然後另一個畫面讓使用者輸入 然後另一個畫面讓使用者輸入 XPath XPath 的路徑,然後的路徑,然後把結果呈現出來。把結果呈現出來。