跳轉到內容

XML - 資料交換管理/XQL

來自華夏公益教科書



上一章 下一章
XML 加密 XQuery



學習目標

[編輯 | 編輯原始碼]
  • 什麼是 XQL?
  • 什麼是 XQL 查詢?
  • 教程
  • XQL 的不同組成部分是什麼?

隨著越來越多的資訊儲存在 XML 中、以 XML 交換或透過各種介面以 XML 形式呈現,智慧查詢我們的 XML 資料來源的能力變得越來越重要。XML 文件是結構化文件——它們模糊了資料和文件之間的界限,允許將文件視為資料來源,並將傳統資料來源視為文件。

XQL 是一種專門為 XML 設計的查詢語言。與 SQL 是關係表查詢語言和 OQL 是面向物件資料庫中儲存的物件的查詢語言相同,XQL 是 XML 文件的查詢語言。XQL 的基本結構直接對應於 XML 的基本結構,並且 XQL 與 XPath 密切相關,XPath 是 XSL 和 XPointers 使用的通用定位器語法。由於查詢、轉換模式和連結都基於可能 XML 文件中找到的結構模式,因此這三種應用程式中使用的模式語言的通用模型既是可能的,也是可取的,並且表達該模型表達的模式的通用語法簡化了必須掌握各種 XML 相關技術的使用者的任務。雖然 XQL 出現早於 XSL 模式,但兩種語言之間存在很強的相似性,我們已將 XPath 語法用於不同的結構。XPath 中並非所有結構都需要用於查詢,並且 XQL 中使用的一些結構在 XPath 中找不到,但兩種語言共享一個共同的子集。

本章描述的 XQL 語言包含幾個以前釋出的語言版本中沒有的功能,包括聯接、連結、文字包含和可擴充套件函式。這些新功能在很大程度上受到 W3C QL '98 研討會討論的啟發,並使人們能夠以強大的方式組合來自異構資料來源的資訊。我們非常小心地保持了 XQL 的基本簡單性,同時添加了這些功能。

本章旨在作為即將到來的 W3C 查詢語言活動的輸入,以及 XPath 的進一步發展。

XML 查詢語言

[編輯 | 編輯原始碼]

傳統上,結構化查詢主要用於關係型資料庫或面向物件的資料庫,而文件則使用相對非結構化的全文查詢進行查詢。雖然相當複雜的結構化文件查詢引擎已經存在了一段時間,但它們還沒有成為主流應用。在過去的一年中,人們提出了許多非常不同的 XML 查詢方法,對構成查詢的不同視角。來自半結構化資料庫社群的一些特別有趣的提案包括 XML-QL 和 Lorel,並採用半結構化方法來處理 XML。本提案將這些語言中的幾個想法整合到 XQL 中。

XQL 被設計用於許多不同的 XML 環境,使用一種可以在 XML 屬性中使用、嵌入程式語言或併入 URI 的語法。從一開始,我們就努力使語言保持簡單和精煉,並且我們一直小心地不要新增會使 XQL 難以實現的功能。在過去的一年中,我們被說服添加了幾個強大的新功能,這些功能允許使用者組合來自多個來源的資訊,使用連結中表達的關係作為查詢的一部分,並根據文字包含進行搜尋。能夠使用多個文件中的資訊的查詢允許這些文件中包含的資訊以建立原始文件的人員沒有預見到的方式被重用。當許多文件或資料來源可能各自包含給定主題所需的部分資訊時,這非常有用。例如,假設一個文件包含針對特定學習課程的一組推薦書籍,另一個文件列出了商店的書籍和價格,第三個文件包含一組書籍評論。可以構建一個查詢來列出推薦的書籍、它們的價格以及它們收到的評論。

XQL 與 XPath 密切相關,我們希望能夠在 XPath 發展過程中保持與 XPath 的相容性。我們認為 XQL 是 XSLT 的補充,XSLT 可用於對查詢結果進行復雜的重塑和格式化。

XML 作為資料模型

[編輯 | 編輯原始碼]

XQL 設計的一個重要動機是認識到 XML 有其自己的隱含資料模型,既不是傳統關係型資料庫的資料模型,也不是面向物件或面向物件關係型資料庫的資料模型。在 XQL 中,文件是有序的、標記的樹,節點代表文件實體、元素、屬性、處理指令和註釋。該模型與 XML 資訊集 (http://www.w3.org/XML/Group/1999/04/WD-xml-infoset-19990428.html) 相容。

重要的是要注意,資料之間的關係包含文件中很大一部分的資訊,這是 XML 等結構化文件格式首先有用的原因之一。XQL 的最初公式完全基於 XML 文件的樹狀結構

  1. 層次結構

    1. 父/子

    2. 祖先/後代

  2. 序列(在同級列表中或在文件順序中)

  3. 位置(在同級列表中或在文件順序中)

    1. 絕對

    2. 相對

    3. 範圍

這些關係長期以來一直是 XPointer 模型的基礎,現在透過軸的形式反映在 XPath 中。在 XQL 中,所有查詢都使用子軸,因此我們將以父/子關係和祖先/後代關係的形式進行討論,而不是使用 XPath 工作草案中的定位器路徑一詞。

當前草案將此模型擴充套件以支援以下內容

  1. 透過聯接建立的臨時關係

  2. 連結的取消引用

聯接允許在查詢中組合文件的子樹;連結允許查詢支援引用以及樹結構。

什麼是 XML 查詢?

[編輯 | 編輯原始碼]

在 XQL 中,查詢從一個或多個 XML 文件中返回 XML 文件節點。為了檢查 XQL 查詢的特徵,考慮查詢發生的環境的四個基本問題是有用的

  1. 什麼是資料庫?
  2. 查詢語言是什麼?
  3. 查詢的輸入是什麼?
  4. 查詢的結果是什麼?

下表提供了對每個問題的簡要回答,包括與 SQL 查詢語言的比較,SQL 查詢語言廣泛用於查詢關係資料庫

SQL XQL
資料庫是一組表。 資料庫是一組一個或多個 XML 文件。
查詢在 SQL 中完成,SQL 是一種查詢語言,它使用表的結構作為基本模型。 查詢在 XQL 中完成,XQL 是一種查詢語言,它使用 XML 文件的結構作為基本模型。
FROM 子句確定查詢檢查的表。 查詢會得到來自一個或多個文件的輸入節點列表。
查詢的結果是一個包含一組行的表;此表可以作為進一步查詢的基礎。 查詢的結果是一個 XML 文件節點列表,它可以作為進一步查詢的基礎。

從上表可以看出,文件節點在 XQL 查詢中起著核心作用。這些節點是一種抽象。任何實際的 XQL 實現都會找到一些具體的實現查詢中使用的節點的方法。例如,XQL 引擎可以透過 DOM 節點、XSL 節點、索引結構或 XML 文字表示查詢的輸入。這些方法中的任何一種都可以用來表示查詢的結果;此外,還可以使用指向原始文件的超連結或其他引用,建立新的虛擬文件,或使用 DOM 二級 TreeWalkers 或 Iterators。

構成查詢輸入的節點可能來自各種不同的來源。它們可能是先前查詢的結果,文件庫的內容,來自文件物件模型節點列表的節點,或任何其他標識一個或多個文件中節點的來源。XQL 不會指定如何將這些節點帶到查詢中。當前的 XQL 實現採用了多種方法,包括:使用文件物件模型子樹作為查詢的基礎,查詢作為 UNIX 風格管道輸入提供的整個文件,從命令列讀取文件,使用資料字典或儲存庫目錄結構來標識要查詢的節點,以及使用 URL 標識文件。此提案增加了對使用連接合並來自異構資料來源的資訊的支援。

在 XQL 中,節點具有標識,並且它們在查詢結果中保留其標識、包含關係和順序。分組運算子允許省略樹的級別,同時保留查詢返回的節點的相對順序和包含關係。連線允許將來自一個數據源的子樹插入到另一個文件子樹中,前提是滿足連線條件。連結函式類似於連線,允許將文件中的超文字連結替換為它引用的節點。XQL 中的一些函式返回可能為布林值、整數或字串的值。這些值在查詢模型中也被視為節點。

XQL 教程

[edit | edit source]

在深入研究之前,我們認為展示一些典型的 XQL 查詢將有助於傳達對該語言的直觀感受。本教程將討論最簡單的 XQL 查詢,這些查詢也可能是最常見的。在本教程中,我們將對 XQL 進行快速概述,而不花時間進行精確描述。

一個簡單的字串被解釋為一個元素名稱。例如,此查詢規範返回所有 <table> 元素

table

子運算子(“/”)表示層次結構。此查詢規範返回 <front> 元素的子元素 <author> 元素

front/author

文件的根可以使用前導 “/” 運算子表示

/novel/front/author

編者注: 在 XQL 中,文件的根指的是文件實體,在技術上,XML 意義上的文件實體,它基本上等同於文件本身。它與根元素不同,根元素是包含文件中其餘元素的元素。文件根始終包含根元素,但它也可能包含文件型別、處理指令和註釋。在這個例子中,<novel> 將是根元素。

路徑始終從上到下描述,除非另有說明,否則路徑上最右邊的元素將被返回。例如,在上面的例子中,將返回 <author> 元素。

元素的內容或屬性的值可以使用等號運算子(“=”)指定。以下返回所有 <front> 元素的子元素,其名稱為 “Theodore Seuss Geisel” 的作者

front/author='Theodore Seuss Geisel'

屬性名稱以 “@” 開頭。它們被視為它們所屬元素的子元素

front/author/address/@type='email'

後代運算子(“//”)表示任意數量的中間級別。以下顯示了 <front> 中的任何位置的地址

front//address

當後代運算子出現在路徑的開頭時,它表示從文件開始的所有節點。此查詢將查詢文件中的任何地址

//address

過濾器運算子(“[ ]”)根據括號內的條件過濾其左側的節點集。以下查詢返回地址;這些地址中的每一個必須有一個名為 “type” 的屬性,其值為 “email”

front/author/address[@type='email']

請注意,“address[@type='email']” 返回地址,而 “address/@type='email'” 返回 type 屬性。

可以使用布林運算子組合多個條件。

front/author='Theodore Seuss Geisel'[@gender='male' and @shoesize='9EEEE']

括號也用於下標,它表示文件中的位置。以下指的是第 1、3、4、5 和 8 節,以及最後一節

section[1,3 to 5, 8, -1]

條件和下標不能同時出現在同一個括號中,但括號的兩種用法可以出現在同一個查詢中。以下指的是前三個 level 屬性值為 “3” 的節;換句話說,它返回前三個 “level3” 節

section[@level='3'][1 to 2]

現在我們已經瞭解了基礎知識,讓我們看一下文件,並嘗試對其進行一些 XQL 查詢。以下是發票文件。傳統上,發票通常儲存在資料庫中,但發票既是文件又是資料。XQL 被設計為可以處理文件和資料,前提是它們透過某種介面以 XML 的形式表示。此文件將作為以下示例查詢的基礎

<?xml version="1.0"?>
<invoicecollection>
  <invoice>
    <customer>       
	     Wile E. Coyote, Death Valley, CA
    </customer>  
	<annotation>        
	 	Customer asked that we guarantee return rights 
		if these items should fail in desert conditions. 
		This was approved by Marty Melliore, general
        manager.  
    </annotation>  
   	<entries n="2">     
	     <entry quantity="2"  total_price="134.00">      
	       <product maker="ACME" prod_name="screwdriver" price="80.00"/>
      </entry>     
	     <entry quantity="1" total_price="20.00">        
	       <product maker="ACME" prod_name="power wrench" price="20.00"/>
      </entry>
    </entries>
  </invoice>
  
  <invoice>  
    <customer> Camp Mertz  </customer>  
	<entries n="2">     
	   <entry quantity="2" total_price="32.00">        
		  <product maker="BSA" prod_name="left-handed smoke shifter" price="16.00"/>
	   </entry>     
	   <entry quantity="1" total_price="13.00">
		  <product maker="BSA" prod_name="snipe call" price="13.00"/>     
	   </entry>
    </entries>
  </invoice>
</invoicecollection>

現在讓我們看看一些示例查詢。對於這些示例,我們將使用文字形式呈現查詢結果,使用 “查詢結果和序列化” 部分中描述的序列化方法。通常,XQL 查詢返回節點列表,這些節點列表可以用任何方便查詢執行環境的方式表示,例如 DOM 節點、序列化的 XML 文字、XPointers、超連結,或透過建立一個迭代器來遍歷結果。由於 XML 文字易於閱讀,我們發現它適合作為我們的示例中表示結果的一種方式。

假設我們想檢視資料庫中的所有客戶。我們可以執行以下查詢

查詢

//customer

結果

<xql:result>
  <customer> Wile E. Coyote, Death Valley, CA </customer>
  <customer> Camp Mertz </customer>
</xql:result>

我們可能想檢視 BSA 製造的所有產品。此查詢將完成此任務

查詢

//product[@maker='BSA']

結果

<xql:result>      
  <product maker="BSA" prod_name="left-handed smoke shifter" price="16.00"/>      
  <product maker="BSA" prod_name="snipe call" price="13.00"/>
</xql:result>

當在與返回結果不同的路徑上指定條件時,過濾器特別有用。例如,以下查詢返回 Camp Mertz 訂購的產品

查詢

//invoice[customer='Wile E. Coyote, Death Valley, CA']//product

結果

<xql:result>
  <product maker="ACME" prod_name="screwdriver" price="80.00"/> 
  <product maker="ACME" prod_name="power wrench" price="20.00"/>
</xql:result>

這是本教程的結尾,它只涵蓋了 XQL 的最基本功能。有關說明更新或更高階功能(例如返回運算子、序列、連線、引用和使用者定義函式)的示例,請參閱下一部分的相應部分。

XQL 表示式

[edit | edit source]

XQL 查詢始終針對上下文進行求值,上下文是一個文件節點列表。查詢的初始上下文稱為起始上下文。在 XQL 中,起始上下文中的節點可能來自不同的文件,即使它們在同一個文件中,也沒有假設它們來自文件的連續部分。一些 XQL 運算子建立一個新的上下文,在該上下文中將對子表示式進行求值;例如,在表示式 “author/name” 中,在起始上下文中對 “author” 進行求值。對於每個作者,"/" 運算子建立一個新的上下文,該上下文包含該作者的子元素,並在該上下文中對 “name” 進行求值。建立新上下文的運算子是 /、// 和 []。

編者注: 在 XSL 中,表示式針對稱為上下文節點的節點進行求值。我們使用 “上下文” 一詞的目的是為了與 XSL 模式保持語義一致性,而不會對查詢語言施加不必要的限制。因此,XSL 模式是根據上下文節點的子節點定義的,而 XQL 查詢是根據上下文節點本身定義的。我們透過構建一個包含上下文中節點的虛構上下文節點,並允許 XSL 術語 "." 對映到該上下文節點,來維護 XSL 模式定義和 XQL 定義的對應關係。

術語

[edit | edit source]

以下表達式是術語,它們根據節點的型別或名稱從上下文中選擇特定的節點

n 元素名稱 上下文中所有節點型別為元素且節點名稱為 “n” 的節點。
* 帶萬用字元的元素名稱 在節點型別為元素的上下文中,所有節點。
@n 屬性名稱 在節點型別為屬性且節點名稱為“n”的上下文中,所有節點。
@* 帶萬用字元的屬性名稱 在節點型別為屬性的上下文中,所有節點。
text() 文字節點 在節點型別為文字的上下文中,所有節點。
comment() 註釋 在節點型別為註釋的上下文中,所有節點。
pi() 處理指令 在節點型別為處理指令的上下文中,所有節點。
pi("v") 帶有目標的處理指令 在節點型別為處理指令且目標為“v”的上下文中,所有節點。
. 上下文節點 上下文節點的父節點 - 此節點可能是真實的或虛構的。

名稱空間和名稱

[edit | edit source]

在 XML 表示式中,名稱可以與名稱空間字首相關聯。可以使用變數宣告來宣告名稱空間字首。在以下查詢中,第一行將“b”宣告為一個變數,等效於名稱空間 URL "http://www.TwiceSoldTales.com"。查詢的第二行搜尋屬於此名稱空間的所有 <book> 元素。

b := "http://www.TwiceSoldTales.com";
//b:book

XML 文件可能使用不同的名稱空間字首來表示相同的名稱空間 URI。匹配是根據名稱空間 URI 進行的,而不是根據文件或 XQL 查詢中與之關聯的字首進行的。

XQL 表示式可以明確指定在匹配節點名稱時是否應考慮名稱空間。

table 任何名為 <table> 的元素,無論它屬於哪個名稱空間。
html:table 任何名為 <table> 且屬於字首“html”指示的名稱空間的元素。
* 任何元素,無論它屬於哪個名稱空間。
:table 任何名為 <table> 且未宣告名稱空間的元素。
*:table 任何名為 <table> 且已宣告名稱空間的元素。
html:* 任何屬於與字首“html”關聯的名稱空間的元素。
:* 任何未宣告名稱空間的元素。
*:* 任何已宣告名稱空間的元素。

相同的約定適用於屬性名稱。在屬性名稱中,屬性字首位於名稱空間字首之前。

@lib:isbn

名稱空間在查詢的輸出中保留。要更改輸出中節點的名稱空間,請使用重新命名運算子。

比較

[edit | edit source]

比較根據節點的內容或值新增約束。考慮以下示例。

author="Washington Irving"

@id="id-sec-0203"

text() = "Whan that Aprille with his shoures soughte"

無論比較左側的節點型別是什麼,它都與右側的值進行比較。對於使用支援資料型別的模式的系統,這些資料型別在比較中使用。

books[pub_date < date("1990-01-01")]

由於某些使用 XQL 的環境具有受限的字元集,例如 URI 或儲存在屬性值中的查詢,因此許多比較具有滿足這些環境的語法約束的替代語法。例如,以下兩個查詢是等效的。

books[pub_date < date("1990-01-01")]

books[pub_date lt date("1990-01-01")]

以下比較運算子在 XQL 中可用。

相等 n="value"
n eq "value"
不區分大小寫的比較 n ieq "value"
不相等 n !="value"
n ne "value"
文字包含 n contains "value"
不區分大小寫的文字包含 n icontains "value"

文字比較支援萬用字元“*”和“?”。考慮以下示例。

資料

<editor>   
  <name>
    <first> Ramesh </first> 
	 <last> Lekshmynarayanan </last> 
  </name> 
</editor></customer>

查詢

//(editor contains "Leksh*")

值“Leksh*”匹配名稱“Lekshmynarayanan”,並返回 <editor> 元素。

以下運算子可能在支援資料型別的 XQL 環境中定義。

小於 n < value
n lt value
小於或等於 n <=value
n lte value
大於 n > value
n gt value
大於或等於 n >=value
n gte value

層次結構和過濾器

[edit | edit source]

這些運算子建立一個新的搜尋上下文,並在該上下文中評估子表示式。在本表中,Q1 和 Q2 用於表示任意 XQL 表示式。

Q1/Q2 父/子 在當前上下文中評估的滿足 Q1 的節點的子節點,這樣

子節點滿足 Q2。Q2 對 Q1 中每個節點的子節點列表分別進行評估;每個子節點列表評估到的節點進行聯合

在一起。
Q1//Q2 祖先/後代 在當前上下文中評估的滿足 Q1 的節點的後代節點,

這樣後代節點滿足 Q2。Q2 對 Q1 中每個節點的每個子節點列表分別進行評估,並對每個子節點列表中的每個節點遞迴地進行評估;

每個子節點列表評估到的節點進行聯合在一起。
Q1[Q2] 過濾器 在當前上下文中評估的滿足 Q1 的節點,包含

滿足 Q2 的子節點。Q2 對 Q1 中每個節點的子節點列表分別進行評估;每個子節點列表評估到的節點進行聯合在一起。

Q1[poslist] 下標 在當前上下文中評估的滿足 Q1 的節點,其在評估列表中的位置包含在 poslist 中。

布林運算子和集合運算子

[edit | edit source]

可以使用布林運算子集合運算子組合術語或其他 XQL 表示式。

not(q) 否定 上下文中所有表示式 q 評估為 null 的節點。
q1 union q2 聯合 在上下文中評估的 q1 和 q2 的聯合。
q1 intersect q2 交集 在上下文中評估的 q1 和 q2 的交集。
q1 | q2 聯合 在上下文中評估的 q1 和 q2 的聯合。
q1 ~ q2 兩者 如果 q1 和 q2 都非空,則返回 q1 聯合 q2;如果任何一個為空,則返回空列表。
q1 or q2 (布林值) 如果在上下文中評估的 q1 和 q2 的聯合非空,則返回 true;否則返回 false。
q1 and q2 (布林值) 如果在上下文中評估的 q1 和 q2 的交集非空,則返回 true;否則返回 false。

引入“兩者”運算子是因為我們發現許多查詢使用過濾器對要在過濾器之外返回的相同資料表達約束,從而導致表示式非常冗餘。例如,以下查詢使用過濾器來表達只有名為“Wile E. Coyote”的客戶的賬單包含產品才是我們感興趣的,並且應返回客戶姓名和產品集。

//invoice[customer[name='Wile E. Coyote'] and .//product]/(customer | .//product)

使用“兩者”運算子,可以更簡潔地表達相同的查詢。

//invoice/(customer[name='Wile E. Coyote'] ~ .//product)

請注意,“兩者”運算子既不是布林“或”運算子,也不是集合交集運算子。表示式“customer intersect product”始終返回空結果,因為沒有任何元素同時是 <customer> 元素和 <product> 元素。“兩者”運算子用於指定必須同時滿足的條件以建立上下文。

分組運算子

[edit | edit source]

使用原始文件的結構對結果進行分組通常很有用。例如,列出賬單上產品的查詢可能希望按賬單對產品進行分組,將每組產品放置在賬單標籤中。XQL 提供了一個分組運算子,提供了 exactly 此功能。在以下查詢中,花括號左側的元素(分組元素)用於將花括號內查詢的結果進行分組。

//invoice { .//product }

對於查詢匹配的每個分組元素,分組運算子都會建立一個具有相同名稱的空元素。然後,花括號內查詢的結果將作為子節點附加到此新節點。如果我們將此查詢應用於教程中提供的賬單資料,我們將獲得以下結果。

<xql:result>   
  <invoice>     
    <product maker="ACME" prod_name="screwdriver" price="80.00"/>      
    <product maker="ACME" prod_name="power wrench" price="20.00"/>    
  </invoice>   
  <invoice>    
    <product maker="BSA" prod_name="left-handed smoke shifter" price="16.00"/>     
    <product maker="BSA" prod_name="snipe call" price="13.00"/>   
  </invoice>
</xql:result> 

使用分組運算子的複雜查詢可以透過適當使用空格來提高可讀性,例如。

invoice {
	.//customer[name contains "Coyote"] { 
		name | address
	} ~
   entries {
	   .//product[@maker="ACME"]
	}	
}

序列

[edit | edit source]

XQL 為序列定義了以下運算子。

之前 a before b 返回所有位於“b”之前的“a”。
之後 a after b 返回所有位於“b”之後的“a”。
列表串聯 a, b 返回一個列表,其中包含所有“a”,然後是所有“b”。對指定返回列表中的順序很有用。

列表串聯運算子用於在返回列表中指定順序。通常,XQL 運算子會維護文件順序;串聯運算子允許在返回列表中指定順序。例如,以下查詢指定返回結果的順序應為作者、標題、然後是 isbn。

//book//(author, title, isbn)

如果有多個作者,則所有作者都將在標題之前列出。

在主要使用 XML 表示來自面向物件系統或關係資料庫的資料的系統中,順序可能並不特別重要。但是,順序在文件中很重要,並且在資料導向的應用程式中也很有用,在這些應用程式中,標記沒有清楚地指示每個元素的作用。考慮以下表格,其中列出了某項虛構運動的最新得分。

西部聯賽
土豚 12 黃鼠狼 10
蚊子 17 鼻涕蟲 2

南部聯賽

龜 25 野兔 0
鴨嘴獸 17 變形蟲 16

該表的標記如下所示

<table width="50%" border="1">
  <tbody>
    <tr>
      <td colspan="2"><emph>Western League</emph> </td>
    </tr>
    <tr>
      <td Aardvarks 12</td>
      <td>Weasels 10</td>
    </tr>
    <tr>
      <td Mosquitos 17</td>
      <td>Bulls 2</td>
    </tr>
    <tr>
      <td colspan="2"><emph>Southern League</emph></td>
    </tr>
    <tr>
      <td Tortoises 25</td>
      <td>Hares 0</td>
    </tr>
    <tr>
      <td Platypii 17</td>
      <td>Amoebae 16</td>
    </tr>
  </tbody>
</table>

純粹主義者可能會反對說這不是特別好的標記,因為它沒有清楚地區分聯賽和得分。我們同意,當我們編寫自己的文件時,我們會用不同的方式編寫它們;但是,現實世界中存在許多平庸的標記,在查詢文件時,我們沒有先重寫它們的奢侈。因此,我們認為查詢語言應該能夠管理上面顯示的類似資料。

要查詢西部聯賽的所有最新得分,我們可以使用以下查詢

table//((tr after (tr contains "Western League")) before (tr contains "Southern League"))

編者注: 順序由 XPath 中的軸處理。我們認為 XML 查詢語言應該提供一些方法來允許查詢中的順序,並且應該考慮各種方法。這裡討論的方法在表達多個節點之間的關係方面具有優勢,尤其是在僅在特定節點的後代內進行比較時。


函式

[edit | edit source]

XQL 的大多數函式直接來自 XSL 模式語言。添加了一些函式,省略了許多函式,因為我們發現它們在純查詢環境中比在通用轉換環境中更不相關。

集合函式
attribute(),attribute('name') 返回上下文中的屬性。如果提供了名稱引數,則返回具有給定名稱的屬性。
comment() 返回上下文中的註釋。
element(),element('name') 返回上下文中的元素。如果提供了名稱引數,則返回具有給定名稱的元素。
entity-ref() 返回上下文中的實體引用。XQL 在所有實體引用都已擴充套件的文件檢視上執行;此函式是

在 XQL 中定位實體引用的唯一

方法。
node() 返回上下文中的所有節點。
pi(),pi('target') 返回上下文中的處理指令。如果提供了目標引數,則返回具有給定目標的處理指令。
text() 返回上下文中的文字節點。為了文字節點,XQL

假設 CDATA 部分被視為文字,相鄰的文字節點被

合併,並且實體引用被擴充套件。


count()
id()
idref()
position()

可擴充套件函式

[edit | edit source]

許多 XQL 實現是程式設計環境的一部分。在這些環境中,允許使用者編寫自己的函式很有用,這些函式可以在查詢中使用。這必須以與語言無關的方式完成,因為 XQL 實現已使用多種語言完成,包括 C++、Java、Haskell 和 Perl。為了允許編寫使用者定義的函式,XQL 提供了一個名為“function()”的函式。

假設使用者想要新增一個計算一組值的平均值的函式。使用者可以編寫一個名為“average”的函式,並在 XQL 查詢中呼叫它,如下所示

average(property//price)

使用者定義的函式通常在 XQL 實現的語言環境中編寫;例如,如果 XQL 實現是用 Java 編寫的,使用者定義的函式通常被寫成 Java 函式。所有 XQL 函式都會傳遞當前上下文中節點的列表。如果函式有引數,則這些引數將作為字串傳遞給 XQL 函式。通常,該函式將評估這些引數作為針對當前上下文的查詢;例如,實現“average”函式的使用者程式碼可能會首先執行查詢“property//price”以獲取當前上下文的 <price> 元素集,然後計算這些元素的平均值。

函式呼叫的結果也是節點列表。如果要返回單個值,例如字串或數字,則應將其作為該型別的元素節點返回

<xql:number> 112,000.47 </xql:number>

函式可以返回的可用型別集在“查詢結果和序列化”部分中描述,該部分位於當前部分之後。如果函式使用錯誤的引數呼叫,可以透過在結果中返回 <xql:warning> 元素來傳達此資訊

<xql:warning> "average" 需要被平均節點的數字值 </xql:warning>

編者注: 一些供應商要求也提供可擴充套件運算子。這將是一個有用的功能;到目前為止,我們還沒有在 XQL 中找到可擴充套件運算子的乾淨設計。

問題(function-namespace): 關於名稱空間在供應商和使用者向 XQL 新增函式時是否會增加顯著價值,存在不同的觀點。

參考

[edit | edit source]

編者注: 本節中的想法是探索性的,尚未包含在 XQL 中。

目前 XQL 中沒有用於取消引用連結的語法,但這在許多應用程式中顯然是需要的。XSL 提供了“id()”函式,它返回包含給定 ID 的元素。例如,以下內容將評估為 <A> 元素中的 HREF 屬性指向的節點

A/id(@HREF)

從 XQL 的角度來看,這實際上是一種聯接。但是,上面的語法比等效的聯接語法更簡單

A/id[$h = @HREF]/(//*[id=$h])

我們需要類似於 id() 的功能,將此功能擴充套件到包含任何型別的連結,而不僅僅是 ID/IDREF。讓我們建立一個名為 ref() 的函式,它返回 XPointer 或 HTML HREF 指向的節點或節點

A/ref(@HREF)

聯接語法的一個優點是它允許指定引用節點的型別。能夠將其指定為函式的另一個引數可能很有用。讓我們允許將引用節點的型別指定為函式的第二個引數。例如,以下內容將僅在引用節點是“table”元素時返回該節點;否則,它將返回 null

A/ref(@HREF, "table")

指定其他引數也可能很有用,例如將引用的範圍限制為當前文件、本地儲存庫或其他可識別的範圍。

能夠識別其他節點對特定節點的引用通常很有用。例如,如果我們正在考慮從文件中刪除某些內容,我們可能想知道它是否被引用。為此,引入另一個函式可能很有用,該函式返回引用特定節點的所有節點。如果我們稱此函式為“backref()”,它可能看起來像這樣

A/backref(table[0])

問題(ref-scope): 反向引用也需要以某種方式進行範圍限定,並非所有系統都希望支援它們,因為實現開銷。

引用也可以用於指定查詢中使用的文件的 URL

ref("http://www.amazon.com")//book[.//title contains "Alhambra"]

聯接

[edit | edit source]

編者注: 聯接是 XQL 中的一項新功能。本節中討論的聯接方法主要來自 GMD-IPSI 的 Peter Fankhauser 和 Software AG 的 Harald Schöning。GMD-IPSI 的 Gerald Huck 在完善初始模型方面特別有幫助。這種方法有一些初步的實現經驗。

在許多環境中,能夠組合來自多個來源的資訊以建立一個統一的檢視很有用。例如,假設我們有書籍來源和評論來源

<book>
  <isbn> 84-7169-020-9 </isbn>
  <title> Tales of the Alhambra </title>
  <author> Washington Irving </author>
</book>

<review>
  <isbn> 84-7169-020-9 </isbn>
  <title> Tales of the Alhambra </title>
  <reviewer> Ricardo Sanchez </reviewer>
  <comments>
	A romantic and humorous account of the time that
	the author of "The Legend of Sleepy Hollow" lived
	in an Arabian palace in Spain.
  </comments>
</review>

我們可能想將它們組合起來建立一個包含評論中找到的評論的書籍檢視

<book>
  <isbn> 84-7169-020-9 </isbn>
  <title> Tales of the Alhambra </title>
  <author> Washington Irving </author>

  <review>
     <reviewer> Ricardo Sanchez </reviewer>
     <comments>
	      A romantic and humorous account of the time that
	      the author of "The Legend of Sleepy Hollow" lived
	      in an Arabian palace in Spain.
     </comments>
  </review>
</book>

這相當於將資訊從評論插入到書籍中。如果我們有一個數據庫,它只包含這本書和這條評論,我們可以透過以下查詢獲得期望的結果

/book {
		isbn | title | author | //review { reviewer | comments }
}

如果我們使用包含許多書籍和許多評論的資料庫,上面的查詢將在每本書中包含整個評論列表,而不僅僅是關於這本書的評論。我們需要一些方法來將評論限制在與這本書具有相同 ISBN 號碼的評論。我們將透過引入相關變數來做到這一點。在以下示例中,“$i := isbn”將變數“$i”分配給每本書上下文中 isbn 的評估。表示式“//review[isbn=$i]”將評論限制在與“$i”匹配的評論

/book[$i:=isbn] {
	  isbn | title | author | //review[isbn=$i] { reviewer | comments }
}

編者注: 雖然過濾器和變數繫結都使用方括號表示法,但變數繫結不會過濾結果。例如,表示式“/book”和“/book[$i:=isbn]”將始終返回相同的一組書籍,無論是否存在任何 <isbn> 元素。

變數繫結會隨著新搜尋上下文的建立而傳播;當建立新上下文時,例如作為子運算子或後代運算子的結果,它將繼承所有活動的變數繫結。這允許在文件層次結構中宣告較高的繫結用於在較低位置執行的聯接。

如果一個關聯變數繫結到一個求值為多個結果的子表示式,則結果列表中的任何值都將用作連線的基礎。更準確地說,“list1 relop list2” 評估為“list1 中的所有 e1,只要 list2 中存在某個 e2,滿足 e1 relop e2”。

以下查詢返回圖書,無論它們是否具有 ISBN;評論只有在具有匹配的 ISBN 時才會返回。

/book[$i:=isbn] {
    $i  | title  | author
    | //review[isbn=$i] { reviewer | comments }
}

編輯說明: 在這個例子中,直觀地說,你不能在空值上連線 - 沒有 ISBN 的書不匹配所有沒有 ISBN 的評論。在 XQL 郵件列表中,關於是否應該允許在空值上連線存在一些不同的意見。

在 XQL 中,方括號用於三種不同的不能混合的東西:下標、過濾器和變數繫結。如果你想要過濾器和變數繫結,你必須使用單獨的方括號。

/book[isbn][$i:=isbn] {
    $i  | title  | author
    | //review[isbn=$i] { reviewer | comments }
}


重新命名運算子

[編輯 | 編輯原始碼]

可以使用重新命名運算子“->”重新命名列表中的節點。在連線中,這可以用來反映一個有意義的名稱,描述合成的結果。

/book[isbn][$i:=isbn] -> BookWithReviews {
    $i  | title  | author
    | //review[isbn=$i] { reviewer | comments }
}

重新命名運算子也可以用來調整查詢結果中的名稱空間。由於重新命名會更改節點的名稱,因此它也會更改名稱空間。例如,假設 <book> 位於 "http://www.TwiceSoldTales.com" 的名稱空間中,我們將 <book> 元素重新命名為 <livre>

//book->livre

我們可以假設 <livre> 未在與 "http://www.TwiceSoldTales.com" 關聯的名稱空間中定義。由於重新命名通常會建立原始名稱空間中不存在的元素名稱,因此 XQL 中的重新命名不會保留原始節點名稱的名稱空間。重新命名運算子的這個屬性可以用來刪除名稱空間;例如,以下查詢將 <book> 元素放置在預設名稱空間中,無論它們的原始名稱空間是什麼。

//book->book

可以使用重新命名運算子顯式應用新的名稱空間字首。

//book->a:book


運算子優先順序

[編輯 | 編輯原始碼]

XQL 表示式從左到右計算。下表顯示了 XQL 中運算子的優先順序。

按優先順序遞減排列的查詢運算子
分組 ()
過濾器 []
重新命名 ->
分組 { }
路徑 / //
比較、賦值 = != < <= > >= eq  ne  lt  le gt ge contains ieq ine ilt ile igt ige icontains :=
交集 intersect
並集 union |
否定 not()
合取
析取
序列 before after
語句結束 ;

括號可以用來分組。

(author | editor)/name
author | (editor/name)

查詢結果和序列化

[編輯 | 編輯原始碼]

在某些環境中,查詢的結果以 XML 文字形式返回。XQL 定義了一種序列化格式,允許查詢結果以格式良好的 XML 文件的形式返回。名稱空間用於區分屬於序列化格式的標籤和查詢返回的標籤。當查詢結果被序列化時,它們會被包裝在 <xql:result> 元素中。

<xql:result xmlns:xql="http://www.metalab.unc/xql/serialization">
  <customer> Wile E. Coyote, Death Valley, CA </customer>
  <customer> Camp Mertz </customer>
</xql:result>

這樣做的原因是格式良好的 XML 文件可能只有一個根元素,而查詢可能返回任意數量的結果。其他 XQL 序列化元素用於從函式返回的值,提供有關查詢的附加資訊,或指示錯誤或警告。以下元素在 XQL 序列化名稱空間中定義。

<xql:result> 圍繞查詢的序列化結果。
<xql:query> 可選。包含原始查詢字串。這對除錯很有用。
<xql:true> 由布林函式返回。
<xql:false> 由布林函式返回。
<xql:number> 由數字函式返回。
<xql:text> 由文字函式返回。
<xql:attribute name="attributeName" value="attributeValue"> 用於在屬性返回在元素的屬性列表之外時返回屬性。
<xql:declaration> 用於在查詢中返回 XML 宣告時返回它。
<xql:error> 用於指示查詢中的錯誤。此元素的內容解釋了錯誤。
<xql:warning> 用於指示警告。此元素的內容解釋了警告。



華夏公益教科書