DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 准備 XML 及相關技術認證,第 3 部分: XML 處理(2)
准備 XML 及相關技術認證,第 3 部分: XML 處理(2)
編輯:XML詳解     

用 SAXEcho 驗證

  現在來看看驗證。注釋掉 XML 文檔中 Life as a House dvd 的 price,再看看結果如何,分別使用 DTD 和 XSD 文件進行驗證。清單 6 顯示了輸出結果。

  清單那 6. 執行 SAXEcho 的輸出

=== Parsing catalogDTD.XML ===
<catalog><dvd><title>Terminator 2</title><description>
   A shape-shifting cyborg is sent back from the future to kill the leader of the resistance.
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
  </description><price>19.95</price><year>1991</year></dvd><dvd><title>The Matrix</title><price>10.95</price><year>1999</year></dvd><dvd><title>Life as a House</title><description>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
   When a man is diagnosed with terminal cancer,
   he takes custody of his misanthropic teenage son.
  </description><year>2001</year>
*** Failed validation ***
* The content of element type "dvd" must match "(title,description?,price,year)".
*************************
</dvd><dvd><title>Raiders of the Lost Ark</title><price>14.95</price><year>1981</year></dvd></catalog>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
=== Parsing catalogXSD.XML ===
<catalog>
  <dvd>
    <title>Terminator 2</title>
  <description>
   A shape-shifting cyborg is sent back from the future to kill the leader of the resistance.
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
  </description>
    <price>19.95</price>
    <year>1991</year>
  </dvd>
  <dvd>
    <title>The Matrix</title>
    <price>10.95</price>
    <year>1999</year>
  </dvd>
  <dvd>
    <title>Life as a House</title>
  <description>
   When a man is diagnosed with terminal cancer,
   he takes custody of his misanthropic teenage son.
  </description>
  
    
*** Failed validation ***
* cvc-complex-type.2.4.a: Invalid content was found starting with element 'year'. One of '{"":price}' is expected.
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
*************************
<year>2001</year>
  </dvd>
  <dvd>
    <title>Raiders of the Lost Ark</title>
    <price>14.95</price>
    <year>1981</year>
  </dvd>
</catalog>

  使用 XML 模式驗證

  您也許會奇怪,既然可以用 DTD 保證文檔結構和內容的有效性,為何需要驗證文檔的其他 方式呢?下面給出幾個理由:

  對元素和屬性值的控制粒度:XML Schema 允許指定格式、長度和數據類型。

  復雜數據類型:XML Schema 支持從已有類型創建新的數據類型和規范。

  元素頻次:使用 XML Schema,可以在更細的粒度上控制元素。

  名稱空間:XML Schema 使用名稱空間,名稱空間對於和其他組織打交道的組織來說越來越重要。

  XML Schema 語言比 DTD 語言更強大,因此也更復雜。好的方面是 XML Schemas 用 XML 編寫,而 DTD 不是。

  我們來驗證一下 DTD 驗證所用的同一個 XML 實例文檔(如 清單 1 所示)。清單 7 顯示了 XML Schema:

  清單 7. Catalog XML Schema

<?XML version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualifIEd" XML:lang="EN"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
  
  <!-- Our DVD catalog contains four or more DVDs -->
 <xs:element name="catalog">
    <xs:complexType>
      <xs:sequence minOccurs="4" maxOccurs="unbounded">
        <xs:element ref="dvd"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  
  <!-- DVDs have a title, an optional description, a price, and a release year -->
  <xs:element name="dvd">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="title"    type="xs:string"/>
        <xs:element name="description" type="descriptionString"
        minOccurs="0"/>
        <xs:element name="price"    type="priceValue"/>
        <xs:element name="year"    type="yearString"/>
      </xs:sequence>
      <xs:attribute name="code" type="xs:ID"/> <!-- requires a unique ID -->
      <xs:attribute name="genre">  <!-- default = optional -->
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="Drama"/>
            <xs:enumeration value="Comedy"/>
            <xs:enumeration value="SciFi"/>
            <xs:enumeration value="Action"/>
            <xs:enumeration value="Romance"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
  
  <!-- Descriptions must be between 10 and 120 characters long -->
  <xs:simpleType name="descriptionString">
    <xs:restriction base="xs:string">
      <xs:minLength value="10"/>
      <xs:maxLength value="120"/>
    </xs:restriction>
  </xs:simpleType>
  
  <!-- Price must be < 100.00 -->
  <xs:simpleType name="priceValue">
    <xs:restriction base="xs:decimal">
      <xs:totalDigits  value="4"/>
      <xs:fractionDigits value="2"/>
      <xs:maxExclusive  value="100.00"/>
    </xs:restriction>
  </xs:simpleType>
  <!-- Year must be 4 digits, between 1900 and 2099 -->
  <xs:simpleType name="yearString">
    <xs:restriction base="xs:string">
      <xs:pattern value="(19|20)dd"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

  要注意,XML Schema 與對應的 DTD 相比要長得多。事實上,即便去掉注釋和空白,這個模式仍然超過了 50 行,而 DTD 模式只有九行。(當然,這個模式檢查的細節要比 DTD 多。)因此,控制的粒度越精細,代碼也越復雜,而且復雜得多。這意味著,如果驗證不需要 XML Schema,則使用 DTD。

  除了和前面 DTD 中所用的可比較的約束以外,看看 XML Schemas 增加了什麼以及為 DVD catalog 文檔帶來了哪些好處:

  對元素和屬性值控制的粒度大小:和允許任何字符值的 DTD 不同,XSD 約束了 descriptions(20 到 120 個字符)、prices(0.00 到 100.00)和 years(1900 到 2999)的值。

  復雜數據類型: 創建了將來可重用、可擴展的新數據類型:dvd、descriptionString、priceValue 和 yearString。

  元素出現頻次:因為本教程使用的例子文檔很小,我把 DVD 的數量設置為四個或更多以便使該文檔有效。實際上,最小值可能是一個很大的數,不過通過這個例子可以看到這種約束是可能的。

  名稱空間:僅對 XML Schema 類型使用了名稱空間,但是由於 XML Schemas 是名稱空間感知的,因而可以增加更多名稱空間來控制名稱沖突。

  我們更詳細地討論一下 XML Schema 以便理解其內容:

  xs:complexType 和 xs:simpleType。complexType 元素可以包含其他元素或屬性:

<xs:element name="dvd">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="title" type="xs:string"/>
 ...

  simpleType 元素只能包含文本和它自己的屬性值:

<xs:simpleType name="yearString">
  <xs:restriction base="xs:string">
    <xs:pattern value="(19|20)dd"/>
  </xs:restriction>
</xs:simpleType>

  這個具體的例子中定義了一種新類型 yearString,它必須包含四位數字,並且最高兩位是 “19” 或 “20”。使用 xs:restriction 元素從已有的(基)類型派生新的、受限制的類型。使用 xs:pattern 刻面元素來比較值,檢查是否和指定的表達式匹配(請參閱 刻面)。

  xs:sequence. 孩子元素必須按照所列順序出現(雖然 minOccurs 可以把元素變成可選的,如前所述):

<xs:sequence>
  <xs:element name="title"    type="xs:string"/>
  <xs:element name="description" type="descriptionString" minOccurs="0"/>
  <xs:element name="price"    type="priceValue"/>
  <xs:element name="year"    type="yearString"/>
</xs:sequence>

  sequence 聲明,有效文檔中的 dvd 必須有一個 title,後面可以跟 10 到 120 個字符長的 description,後跟小於 US$100 形如 “nn.nn” 的 price,最後是 year。

  注意:XML Schemas 驗證需要 XMLBuddy Pro。

  現在做一些修改看看約束是否生效了。 為 Adventure 增加 genre,輸入長度超過 120 字符的 description、設置重復的 dvd code(如 圖 9 所示)。

  圖 9. XSD 錯誤

  准備 XML 及相關技術認證,第 3 部分: XML 處理

  可以發現 genre、惟一的 ID 和 description 長度都是強制性的。

  XML Schema 還能做更多。下面強調幾點:

  xs:choice:必須出現其中的一個孩子。

  xs:all:列出的每個孩子都必須出現一次,但是對順序沒有要求。

  xs:group:可以定義和引用一組元素的組名(通過 ref=groupName)。

  xs:attributeGroup:和用於元素的 xs:group 一樣,這個相對應的指示符用於屬性。

  xs:date:這是 ISO 8601 定義的格裡高利歷法日期,格式為 YYYY-MM-DD。

  xs:time:hh:mm:ss 形式的時間,用 "Z" 表示 UTC 相對時間。

  xs:duration:一定數量的年、月、日、時、分。

  可以看到,編寫 XML Schema 時可以利用很多內建的強大功能。如果找不到需要的類型,可以創建新的類型。

  數據類型

  XML Schema 的一個強大特性是能夠創建新的數據類型。在 catalog.xsd 文件中可以看到使用了大量新建數據類型,包括 yearString 和 priceValue 類型。在該例中,這些類型只在 dvd 類型中使用,但是可以文檔中出現 year 或 price 的任何地方使用。

  這些類型擴展原有的小數和字符串類型:

  <!-- Price must be < 100.00 -->
  <xs:simpleType name="priceValue">
    <xs:restriction base="xs:decimal">
      <xs:totalDigits  value="4"/>
      <xs:fractionDigits value="2"/>
      <xs:maxExclusive  value="100.00"/>
    </xs:restriction>
  </xs:simpleType>
  <!-- Year must be 4 digits, between 1900 and 2099 -->
  <xs:simpleType name="yearString">
    <xs:restriction base="xs:string">
      <xs:pattern value="(19|20)dd"/>
    </xs:restriction>
  </xs:simpleType>

  如前所述,可以結合使用 restriction 元素和一種或更多刻面來實現已有類型的特化。如果有多個刻面,可結合起來確定哪些值有效,哪些值無效。

  范式匹配

  pattern 刻面元素支持一種類似 Perl 的豐富的表達式語法。前面在 yearString 中用到了它,范式 “ (19|20)dd” 應讀作 “字符串必須以 19 或 20 開始並且後跟兩位數字”。表 1 列出了幾個范式。

  表 1. XML Schema 范式匹配表達式

  

范式 匹配 (A|B) 匹配 A 或 B 的字符串 A? 和 A 匹配的字符串出現零次或一次 A* 和 A 匹配的字符串出現零次或多次 A+ 和 A 匹配的字符串出現一次或多次 [abcd] 和指定字符之一匹配的單個字符 [^abc] 和指定字符之外的字符匹配的單個字符 t 制表符 反斜槓 c XML 名稱字符 s 空格、制表符、回車換行或者新行字符 . 回車換行或新行字符外的任何字符

  更多表達式請參閱 XML in a Nutshell, Third Edition 的第 427-429 頁或者閱讀 XML Bible, Second Edition 在線版(請參閱 參考資料)第 24 章的表 24-5。

  XSD 異常處理

  為了處理 XML Schema 操作異常,必須啟用驗證。對於 Xerces 只要將模式驗證特性設置為 true:

parser.setFeature(
  "http://apache.org/XML/features/validation/schema",  
  true );

  可以通過 apache Software Foundation 網站(請參閱 參考資料)了解 Xcerse 解析器的各種特性。

  前面討論過由於操縱問題可能造成的 DOMException。DOMException 的 code 表明發生了什麼類型的問題。

  回顧 DOMEcho

  改變 DOMEcho.Java 邏輯引發一個 DOMException。新的邏輯如下:

//---- find parent Node
Element indianaJones = document.getElementById("_7755522");
//---- insert a description before the price
//  (anywhere else would be invalid)
NodeList years = indianaJones.getElementsByTagName("price");
Node desc = document.createTextNode(
    "Indiana Jones is hired to find the Ark of the Covenant");
    // This change will now fail validation.
indianaJones.insertBefore( desc, indianaJones );

  從而執行下列代碼:

short code = e.code;
...
} else if( code == DOMException.NOT_FOUND_ERR ) {
 //take action when element or attribute not found
 echo( "*** Element not found" );
 System.exit(code);
}

  關於 XML Schemas 驗證的更多信息,請閱讀 XML in a Nutshell, Third Edition 的第 17 章、W3Schools 或者 “Interactive XML tutorials”(請參閱 參考資料)。

  使用 XQuery

  XML Query(XQuery)是一種用於編寫表達式的語言,表達式從 XML 數據(通常是數據庫)中返回匹配的結果。其功能類似於操作非 XML 內容的 SQL:

  “與 SQL 相似,XQuery 包括從多個數據集中提取、匯總、聚合和連接數據的功能。”

  —— “Java theory and practice: Screen-scraping with XQuery”,Brian Goetz(請參閱 參考資料)

  XQuery 擴展了 XPath 表達式,後者將在本系列教程的第四部分 XML 轉換 中詳細討論。XPath 表達式也是有效的 XQuery 表達式。那麼為什麼要用 XQuery 呢?XQuery 的價值在於它在表達式中增加的子句,從而能夠實現和 SQL 中的 SELECT 語句功能類似的更復雜的表達式。

  XQuery 子句

  XQuery 包含多個子句,用縮寫詞 FLWOR 表示:for、let、where、order by、return。表 2 說明了各個部分。

  表 2. FLWOR 子句

  

子句 說明 for 使用這種循環結構將值賦給其他子句中使用的變量。變量使用美元符號聲明,比如 $name,然後從搜索結果中獲得賦給它們的值。 let 使用 let 將值賦給 for 以外的變量。 where 和 SQL 相似,使用 where 子句根據某種條件對結果進行篩選。 order by 使用該子句確定如何對結果集進行排序(ascending 或 descending)。 return 使用 return 子句確定查詢要輸出的內容。內容可以包括文字、XML 文檔內容、Html 標記或者其他任何東西。

  XQuery 包含由結果為 true 或 false 的條件組成 FLWOR 子句中的檢索條件。下面看一些例子。可用 清單 8 中所示的 dvd.xml 作為 XML 實例文檔。

  清單 8. dvd.XML

<?XML version="1.0"?>
<!-- DVD inventory -->
<catalog>
  <dvd code="1234567">
    <title>Terminator 2</title>
    <price>19.95</price>
    <year>1991</year>
  </dvd>
  <dvd code="7654321">
    <title>The Matrix</title>
    <price>12.95</price>
    <year>1999</year>
  </dvd>
  <dvd code="2255577">
    <title>Life as a House</title>
    <price>15.95</price>
    <year>2001</year>
  </dvd>
  <dvd code="7755522">
    <title>Raiders of the Lost Ark</title>
    <price>14.95</price>
    <year>1981</year>
  </dvd>
</catalog>

  為了試驗,我使用了 Saxon XQuery 工具。所有文件都放到解壓 Saxon 的目錄中。為了使用 XQuery 創建一個 Html 頁面按升序列出所有 DVD 的標題,我使用 清單 9 中所示的 dvdTitles.xq 文件,其中也顯示了輸出結果。執行該查詢使用了下面的命令:

Java -cp saxon8.jar net.sf.saxon.Query -t dvdTitles.xq > dvdTitles.Html

  清單 9. 按升序列出 DVD 標題的 XQuery

          dvdTitles.xq:
<Html>
<body>
 Available DVDs:
 <br/>
 <ol>
 {
 for $title in doc("dvd.XML")/catalog/dvd/title
  order by $title
  return <li>{data($title)}</li>
 }
 </ol>
</body>
</Html>
          dvdTitles.Html:
<?XML version="1.0" encoding="UTF-8"?>
<Html>
  <body>
 Available DVDs:
 <br/>
   <ol>
     <li>Life as a House</li>
     <li>Raiders of the Lost Ark</li>
     <li>Terminator 2</li>
     <li>The Matrix</li>
   </ol>
  </body>
</Html>

  仔細觀察 清單 9 中的 XQuery 邏輯。首先,查詢必須用花括號(“{}”)包圍起來。可以看到,該例中使用了三個子句(for、order by 和 return)。使用 doc() 函數打開一個 XML 文檔。$title 是一個變量,在循環中設置為每個搜索結果。具體到該例中,它表示 /catalog/dvd/title 表達式的結果,即 DVD 的標題。返回子句中的 data() 函數輸出 XML 中的值而不包含標記。如果僅僅使用 $title,就會得到 “<title>value</title>”,這不是希望出現在 HTML 輸出中的結果。要注意 XQuery 包圍在完成該網頁所需要的全部 Html 代碼中。

  現在,假設需要按降序輸出超過 15 美元的 DVD 的價格。清單 10 顯示了 XQuery 及輸出。

  清單 10. 按降序輸出超過 15 美元的 DVD 價格

          dvdPriceThreshold.hq
<Html>
<body>
 DVDs prices below $15.00:
 <br/>
 <ol>
 {
 for $price in doc("dvd.XML")/catalog/dvd/price
  where $price < 15.00
  order by $price descending
          return <li>{data($price)}</li>
 }
 </ol>
</body>
</Html>
          dvdPrices.Html
<?XML version="1.0" encoding="UTF-8"?>
<Html>
  <body>
  DVDs prices below $15.00:
 <br/>
   <ol>
     <li>14.95</li>
     <li>12.95</li>
   </ol>
  </body>
</Html>

  該查詢中主要的區別是指定了 where 子句。僅僅為了好玩一點兒而改變了排列順序。

  顯然,還可以做很多實驗來學習 XQuery 的強大功能,不過我已經介紹得夠多了。如果想進一步了解,請參閱 “XQuery” 和 “Five Practical XQuery Applications”(請參閱 參考資料)。

  結束語

  XML 的核心是解析和驗證。了解如何充分利用這些功能對於在項目中能否成功地引入 XML 至關重要。

  結束語

  本教程介紹了 XML 處理,主要涉及:

  使用 SAX2 和 DOM2 解析器解析 XML 文檔

  用 DTD 和 XML Schemas 驗證 XML 文檔

  使用 XQuery 從數據庫中訪問 XML 內容

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved