ISO/IEC 9075-14 (SQL/XML) 中與 XML 相關的規範在 SQL:2006 中引入了重大修訂。PostgreSQL 的 XML 資料類型和相關函數的實作,主要遵循早期 2003 年的版本,並從後來的版本借鑒了一些內容。特別是
當前標準提供了一系列 XML 資料類型,用於以未類型化或 XML Schema 類型化的變體來保存「文件」或「內容」,以及一個 XML(SEQUENCE)
類型來保存任意片段的 XML 內容時,PostgreSQL 提供單一的 xml
類型,它可以保存「文件」或「內容」。沒有與標準的「序列」類型等效的類型。
PostgreSQL 提供了在 SQL:2006 中引入的兩個函數,但它們的變體使用 XPath 1.0 語言,而不是標準中為它們指定的 XML Query。
PostgreSQL 不支援 RETURNING CONTENT
或 RETURNING SEQUENCE
子句,規格中定義為具有這些子句的函數會隱式地傳回內容。
本節介紹您可能會遇到的一些由此產生的差異。
PostgreSQL 特定的函數 xpath()
和 xpath_exists()
使用 XPath 語言查詢 XML 文件。PostgreSQL 還提供了標準函數 XMLEXISTS
和 XMLTABLE
的僅 XPath 變體,它們正式使用 XQuery 語言。對於所有這些函數,PostgreSQL 依賴於 libxml2 程式庫,該程式庫僅提供 XPath 1.0。
XQuery 語言和 XPath 2.0 及更高版本之間存在著強烈的關聯:任何在語法上有效並在兩者中成功執行的運算式都會產生相同的結果(對於包含數字字元參考或預定義實體參考的運算式,XQuery 會將其替換為相應的字元,而 XPath 會保持不變,這是一個小小的例外)。但這些語言與 XPath 1.0 之間沒有這種關聯;它是一種較早的語言,並且在許多方面都不同。
需要記住兩個方面的限制:對於 SQL 標準中指定的函數,從 XQuery 到 XPath 的限制,以及對於標準函數和 PostgreSQL 特定函數,XPath 限制為 1.0 版。
XPath 以外的 XQuery 功能包括
除了所有可能的 XPath 值之外,XQuery 運算式還可以建構並傳回新的 XML 節點。XPath 可以建立並傳回原子類型(數字、字串等等)的值,但只能傳回已存在於作為運算式輸入提供的文件中的 XML 節點。
XQuery 具有用於疊代、排序和分組的控制結構。
XQuery 允許宣告和使用區域函數。
最近的 XPath 版本開始提供與這些重疊的功能(例如函數式 for-each
和 sort
、匿名函數,以及從字串建立節點的 parse-xml
),但在 XPath 3.0 之前,這些功能不可用。
對於熟悉 XQuery 和 XPath 2.0 或更高版本的開發人員來說,XPath 1.0 呈現出許多需要處理的差異
XQuery/XPath 運算式的基本類型 sequence
(可以包含 XML 節點、原子值或兩者),在 XPath 1.0 中不存在。1.0 運算式只能產生節點集(包含零個或多個 XML 節點)或單一原子值。
與可以包含任何所需項目且以任何所需順序排列的 XQuery/XPath 序列不同,XPath 1.0 節點集沒有保證的順序,並且像任何集合一樣,不允許同一項目多次出現。
libxml2 程式庫似乎總是將其成員以與它們在輸入文件中相同的相對順序,將節點集傳回給 PostgreSQL。它的文件並未承諾此行為,並且 XPath 1.0 運算式無法控制它。
雖然 XQuery/XPath 提供了 XML Schema 中定義的所有類型,以及許多對這些類型的運算子和函數,但 XPath 1.0 僅具有節點集和三個原子類型 boolean
、double
和 string
。
XPath 1.0 沒有條件運算子。像 if ( hat ) then hat/@size else "no hat"
這樣的 XQuery/XPath 運算式沒有 XPath 1.0 等效項。
XPath 1.0 沒有字串的排序比較運算子。"cat" < "dog"
和 "cat" > "dog"
都是 false,因為每一個都是兩個 NaN
的數字比較。相反,=
和 !=
會將字串作為字串進行比較。
XPath 1.0模糊了值比較和一般比較之間的區別,而XQuery/XPath則明確定義了它們。 例如,sale/@hatsize = 7
和 sale/@customer = "alice"
都是存在量化的比較,如果存在任何 sale
具有給定屬性值,則為 true。但是 sale/@taxable = false()
是一個對整個節點集合的有效布林值進行的值比較。 只有在沒有任何 sale
具有 taxable
屬性的情況下,它才為 true。
在 XQuery/XPath 資料模型中,一個文件節點可以有文件形式(即,恰好一個頂層元素,並且只有註解和處理指令在其外部),或者內容形式(這些約束條件被放寬)。 它在 XPath 1.0 中的等價物,即根節點,只能是文件形式。 這也是為什麼作為上下文項目傳遞給任何基於 PostgreSQL 的 XPath 函式的 xml
值必須是文件形式的原因之一。
這裡強調的差異並非全部。 在 XQuery 和 2.0 及更高版本的 XPath 中,有一個 XPath 1.0 相容模式,並且 W3C 列出了在該模式下應用的函式庫變更和語言變更,提供了更完整(但仍然不詳盡)的差異說明。 相容模式不能使後來的語言與 XPath 1.0 完全等效。
在 SQL:2006 及更高版本中,標準 SQL 資料類型和 XML Schema 類型之間的雙向轉換都有精確的規定。 然而,這些規則是使用 XQuery/XPath 的類型和語義表達的,並且不直接適用於 XPath 1.0 的不同資料模型。
當 PostgreSQL 將 SQL 資料值對應到 XML(如在 xmlelement
中),或將 XML 對應到 SQL(如在 xmltable
的輸出欄位中)時,除了少數特殊處理的情況外,PostgreSQL 僅僅假設 XML 資料類型的 XPath 1.0 字串形式將作為 SQL 資料類型的文字輸入形式有效,反之亦然。 這個規則的優點是簡單,同時對於許多資料類型,產生的結果與標準中規定的對應關係相似。
如果與其他系統的互通性是一個考量因素,對於某些資料類型,可能有必要明確地使用資料類型格式化函式(例如 第 9.8 節 中的那些)來產生標準對應關係。
本節涉及的限制並非 libxml2 函式庫所固有的,而是適用於 PostgreSQL 中的當前實作。
BY VALUE
傳遞機制 #SQL 標準定義了兩種傳遞機制,當將 XML 引數從 SQL 傳遞到 XML 函式或接收結果時適用:BY REF
,其中特定的 XML 值保留其節點身份; 以及 BY VALUE
,其中 XML 的內容被傳遞,但節點身份不被保留。 可以在引數列表之前指定一種機制,作為所有引數的預設機制,也可以在任何引數之後指定,以覆蓋預設值。
為了說明它們之間的區別,如果 x
是一個 XML 值,則在 SQL:2006 環境中,這兩個查詢將分別產生 true 和 false:
SELECT XMLQUERY('$a is $b' PASSING BY REFx
AS a,x
AS b NULL ON EMPTY); SELECT XMLQUERY('$a is $b' PASSING BY VALUEx
AS a,x
AS b NULL ON EMPTY);
PostgreSQL 將接受 BY VALUE
或 BY REF
在 XMLEXISTS
或 XMLTABLE
結構中,但它會忽略它們。 xml
資料類型包含一個字串序列化的表示,因此沒有節點身份需要保留,並且傳遞始終有效地是 BY VALUE
。
基於 XPath 的函式支援傳遞一個引數來作為 XPath 表達式的上下文項目,但不支援傳遞額外的可用於表達式作為命名引數的值。
XML(SEQUENCE)
類型 #PostgreSQL xml
資料類型只能保存 DOCUMENT
或 CONTENT
形式的值。 XQuery/XPath 表達式上下文項目必須是單個 XML 節點或原子值,但 XPath 1.0 進一步將其限制為僅是 XML 節點,並且沒有允許 CONTENT
的節點類型。 結果是,格式正確的 DOCUMENT
是 PostgreSQL 可以作為 XPath 上下文項目提供的唯一形式的 XML 值。
如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的地方,請使用此表格來報告文件問題。