PostgreSQL XML 函數(shù)

2021-08-27 10:06 更新
9.15.1. 產(chǎn)生 XML 內(nèi)容
9.15.2. XML 謂詞
9.15.3. 處理 XML
9.15.4. 將表映射到 XML

本節(jié)中描述的函數(shù)以及類函數(shù)的表達(dá)式都在類型xml的值上操作。類型xml的詳細(xì)信息請(qǐng)參見第 8.13 節(jié)。用于在值和類型xml之間轉(zhuǎn)換的類函數(shù)的表達(dá)式xmlparsexmlserialize記錄在這里,而不是在本節(jié)中。

使用大部分這些函數(shù)要求PostgreSQL使用了configure --with-libxml進(jìn)行編譯。

9.15.1. 產(chǎn)生 XML 內(nèi)容

有一組函數(shù)和類函數(shù)的表達(dá)式可以用來從 SQL 數(shù)據(jù)產(chǎn)生 XML 內(nèi)容。它們特別適合于將查詢結(jié)果格式化成 XML 文檔以便于在客戶端應(yīng)用中處理。

9.15.1.1. xmlcomment

xmlcomment ( text ) → xml

函數(shù)xmlcomment創(chuàng)建了一個(gè) XML 值,它包含一個(gè)使用指定文本作為內(nèi)容的 XML 注釋。 該文本不包含--或者也不會(huì)以一個(gè)-結(jié)尾,否則該結(jié)果的結(jié)構(gòu)不是一個(gè)合法的 XML 注釋。如果參數(shù)為空,結(jié)果也為空。

例子:

SELECT xmlcomment('hello');

  xmlcomment
--------------
 <!--hello-->

9.15.1.2. xmlconcat

xmlconcat ( xml [, ...] ) → xml

函數(shù)xmlconcat將由單個(gè) XML 值組成的列表串接成一個(gè)單獨(dú)的值,這個(gè)值包含一個(gè) XML 內(nèi)容片斷。空值會(huì)被忽略,只有當(dāng)沒有參數(shù)為非空時(shí)結(jié)果才為空。

例子:

SELECT xmlconcat('<abc/>', '<bar>foo</bar>');

      xmlconcat
----------------------
 <abc/><bar>foo</bar>

如果 XML 聲明存在,它們會(huì)按照下面的方式被組合。如果所有的參數(shù)值都有相同的 XML 版本聲明,該版本將被用在結(jié)果中,否則將不使用版本。如果所有參數(shù)值有獨(dú)立聲明值yes,那么該值將被用在結(jié)果中。如果所有參數(shù)值都有一個(gè)獨(dú)立聲明值并且至少有一個(gè)為no,則no被用在結(jié)果中。否則結(jié)果中將沒有獨(dú)立聲明。如果結(jié)果被決定要要求一個(gè)獨(dú)立聲明但是沒有版本聲明,將會(huì)使用一個(gè)版本 1.0 的版本聲明,因?yàn)?XML 要求一個(gè) XML 聲明要包含一個(gè)版本聲明。編碼聲明會(huì)被忽略并且在所有情況中都會(huì)被移除。

例子:

SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone="no"?><bar/>');

             xmlconcat
-----------------------------------
 <?xml version="1.1"?><foo/><bar/>

9.15.1.3. xmlelement

xmlelement ( NAME name [, XMLATTRIBUTES ( attvalue [ AS attname ] [, ...] ) ] [, content [, ...]] ) → xml

表達(dá)式xmlelement使用給定名稱、屬性和內(nèi)容產(chǎn)生一個(gè) XML 元素。 語法中顯示的nameattname項(xiàng)是簡(jiǎn)單的標(biāo)識(shí)符,而不是值。 attvaluecontent項(xiàng)是表達(dá)式,它們可以生成任何 PostgreSQL數(shù)據(jù)類型。 XMLATTRIBUTES的參數(shù)生成XML元素的屬性;將content值連接起來形成其內(nèi)容。

例子:

SELECT xmlelement(name foo);

 xmlelement
------------
 <foo/>

SELECT xmlelement(name foo, xmlattributes('xyz' as bar));

    xmlelement
------------------
 <foo bar="xyz"/>

SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');

             xmlelement
-------------------------------------
 <foo bar="2007-01-26">content</foo>

不是合法 XML 名字的元素名和屬性名將被逃逸,逃逸的方法是將違反的字符用序列_xHHHH _替換,其中HHHH是被替換字符的 Unicode 代碼點(diǎn)的十六進(jìn)制表示。例如:

SELECT xmlelement(name "foo$bar", xmlattributes('xyz' as "a&b"));

            xmlelement
----------------------------------
 <foo_x0024_bar a_x0026_b="xyz"/>

如果屬性值是一個(gè)列引用,則不需要指定一個(gè)顯式的屬性名,在這種情況下列的名字將被默認(rèn)用于屬性的名字。在其他情況下,屬性必須被給定一個(gè)顯式名稱。因此這個(gè)例子是合法的:

CREATE TABLE test (a xml, b xml);
SELECT xmlelement(name test, xmlattributes(a, b)) FROM test;

但是下面這些不合法:

SELECT xmlelement(name test, xmlattributes('constant'), a, b) FROM test;
SELECT xmlelement(name test, xmlattributes(func(a, b))) FROM test;

如果指定了元素內(nèi)容,它們將被根據(jù)其數(shù)據(jù)類型格式化。如果內(nèi)容本身也是類型xml,就可以構(gòu)建復(fù)雜的 XML 文檔。例如:

SELECT xmlelement(name foo, xmlattributes('xyz' as bar),
                            xmlelement(name abc),
                            xmlcomment('test'),
                            xmlelement(name xyz));

                  xmlelement
----------------------------------------------
 <foo bar="xyz"><abc/><!--test--><xyz/></foo>

其他類型的內(nèi)容將被格式化為合法的 XML 字符數(shù)據(jù)。這意味著字符 <, >, 和 & 將被轉(zhuǎn)換為實(shí)體。二進(jìn)制數(shù)據(jù)(數(shù)據(jù)類型bytea)將被表示成 base64 或十六進(jìn)制編碼,具體取決于配置參數(shù)xmlbinary的設(shè)置。為了使PostgreSQL的映射與SQL:2006及以后的SQL:2006中指定的映射保持一致,個(gè)別數(shù)據(jù)類型的特殊行為將不斷發(fā)展,正如 第 D.3.1.3 節(jié)中討論的那樣。

9.15.1.4. xmlforest

xmlforest ( content [ AS name ] [, ...] ) → xml

表達(dá)式xmlforest使用給定名稱和內(nèi)容產(chǎn)生一個(gè)元素的 XML 森林(序列)。 對(duì)于xmlelement,每個(gè)name都必須是一個(gè)簡(jiǎn)單的標(biāo)識(shí)符,而content表達(dá)式可以有任何數(shù)據(jù)類型。

例子:

SELECT xmlforest('abc' AS foo, 123 AS bar);

          xmlforest
------------------------------
 <foo>abc</foo><bar>123</bar>


SELECT xmlforest(table_name, column_name)
FROM information_schema.columns
WHERE table_schema = 'pg_catalog';

                                xmlforest
------------------------------------?-----------------------------------
 <table_name>pg_authid</table_name>?<column_name>rolname</column_name>
 <table_name>pg_authid</table_name>?<column_name>rolsuper</column_name>
 ...

如我們?cè)诘诙€(gè)例子中所見,如果內(nèi)容值是一個(gè)列引用,元素名稱可以被忽略,這種情況下默認(rèn)使用列名。否則,必須指定一個(gè)名字。

如上文xmlelement所示,非法 XML 名字的元素名會(huì)被逃逸。相似地,內(nèi)容數(shù)據(jù)也會(huì)被逃逸來產(chǎn)生合法的 XML 內(nèi)容,除非它已經(jīng)是一個(gè)xml類型。

注意如果 XML 森林由多于一個(gè)元素組成,那么它不是合法的 XML 文檔,因此在xmlelement中包裝xmlforest表達(dá)式會(huì)有用處。

9.15.1.5. xmlpi

xmlpi ( NAME name [, content ] ) → xml

表達(dá)式xmlpi創(chuàng)建一個(gè) XML 處理指令。 對(duì)于xmlelement,name必須是一個(gè)簡(jiǎn)單的標(biāo)識(shí)符,而content表達(dá)式可以有任何數(shù)據(jù)類型。如果存在,content不能包含字符序列 ?>。

例子:

SELECT xmlpi(name php, 'echo "hello world";');

            xmlpi
-----------------------------
 <?php echo "hello world";?>

9.15.1.6. xmlroot

xmlroot ( xml, VERSION {text|NO VALUE} [, STANDALONE {YES|NO|NO VALUE} ] ) → xml

表達(dá)式xmlroot修改一個(gè) XML 值的根結(jié)點(diǎn)的屬性。如果指定了一個(gè)版本,它會(huì)替換根節(jié)點(diǎn)的版本聲明中的值;如果指定了一個(gè)獨(dú)立設(shè)置,它會(huì)替換根節(jié)點(diǎn)的獨(dú)立聲明中的值。

SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
               version '1.0', standalone yes);

                xmlroot
----------------------------------------
 <?xml version="1.0" standalone="yes"?>
 <content>abc</content>

9.15.1.7. xmlagg

xmlagg ( xml ) → xml

和這里描述的其他函數(shù)不同,函數(shù)xmlagg是一個(gè)聚集函數(shù)。它將聚集函數(shù)調(diào)用的輸入值串接起來,非常像xmlconcat所做的事情,除了串接是跨行發(fā)生的而不是在單一行的多個(gè)表達(dá)式上發(fā)生。聚集表達(dá)式的更多信息請(qǐng)見第 9.21 節(jié)。

例子:

CREATE TABLE test (y int, x xml);
INSERT INTO test VALUES (1, '<foo>abc</foo>');
INSERT INTO test VALUES (2, '<bar/>');
SELECT xmlagg(x) FROM test;
        xmlagg
----------------------
 <foo>abc</foo><bar/>

為了決定串接的順序,可以為聚集調(diào)用增加一個(gè)ORDER BY子句,如第 4.2.7 節(jié)中所述。例如:

SELECT xmlagg(x ORDER BY y DESC) FROM test;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

我們推薦在以前的版本中使用下列非標(biāo)準(zhǔn)方法,并且它們?cè)谔囟ㄇ闆r下仍然有用:

SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

9.15.2. XML 謂詞

這一節(jié)描述的表達(dá)式檢查xml值的屬性。

9.15.2.1. IS DOCUMENT

xml IS DOCUMENTboolean

如果參數(shù) XML 值是一個(gè)正確的 XML 文檔,則IS DOCUMENT返回真,如果不是則返回假(即它是一個(gè)內(nèi)容片斷),或者是參數(shù)為空時(shí)返回空。文檔和內(nèi)容片斷之間的區(qū)別請(qǐng)見第 8.13 節(jié)。

9.15.2.2. IS NOT DOCUMENT

xml IS NOT DOCUMENTboolean

如果參數(shù)中的XML值是一個(gè)正確的XML文檔,那么表達(dá)式IS NOT DOCUMENT返回假,否則返回真(也就是說它是一個(gè)內(nèi)容片段),如果參數(shù)為空則返回空。

9.15.2.3. XMLEXISTS

XMLEXISTS ( text PASSING [BY {REF|VALUE}] xml [BY {REF|VALUE}] ) → boolean

函數(shù)xmlexists評(píng)價(jià)一個(gè)XPath 1.0表達(dá)式(第一個(gè)參數(shù)),以傳遞的XML值作為其上下文項(xiàng)。 如果評(píng)價(jià)的結(jié)果產(chǎn)生一個(gè)空節(jié)點(diǎn)集,該函數(shù)返回false,如果產(chǎn)生任何其他值,則返回true。 如果任何參數(shù)為空,則函數(shù)返回null。 作為上下文項(xiàng)傳遞的非空值必須是一個(gè)XML文檔,而不是內(nèi)容片段或任何非XML值。

例子:

SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY VALUE '<towns><town>Toronto</town><town>Ottawa</town></towns>');

 xmlexists
------------
 t
(1 row)

BY REFBY VALUE子句在PostgreSQL中被接受,但在第 D.3.2 節(jié)中被忽略。

在SQL標(biāo)準(zhǔn)中,xmlexists函數(shù)評(píng)估XML查詢語言中的表達(dá)式,但PostgreSQL只允許使用XPath 1.0表達(dá)式,在第 D.3.1 節(jié)中討論過。

9.15.2.4. xml_is_well_formed

xml_is_well_formed ( text ) → boolean
xml_is_well_formed_document ( text ) → boolean
xml_is_well_formed_content ( text ) → boolean

這些函數(shù)檢查一個(gè)text串是不是一個(gè)良構(gòu)的 XML,返回一個(gè)布爾結(jié)果。xml_is_well_formed_document檢查一個(gè)良構(gòu)的文檔,而xml_is_well_formed_content檢查良構(gòu)的內(nèi)容。如果xmloption配置參數(shù)被設(shè)置為 DOCUMENT,xml_is_well_formed會(huì)做第一個(gè)函數(shù)的工作;如果配置參數(shù)被設(shè)置為CONTENT,xml_is_well_formed會(huì)做第二個(gè)函數(shù)的工作。這意味著xml_is_well_formed對(duì)于檢查一個(gè)到類型xml的簡(jiǎn)單造型是否會(huì)成功非常有用,而其他兩個(gè)函數(shù)對(duì)于檢查 XMLPARSE的對(duì)應(yīng)變體是否會(huì)成功有用。

例子:

SET xmloption TO DOCUMENT;
SELECT xml_is_well_formed('<>');
 xml_is_well_formed 
--------------------
 f
(1 row)

SELECT xml_is_well_formed('<abc/>');
 xml_is_well_formed 
--------------------
 t
(1 row)

SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
 xml_is_well_formed 
--------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
 xml_is_well_formed_document 
-----------------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
 xml_is_well_formed_document 
-----------------------------
 f
(1 row)

最后一個(gè)例子顯示了這些檢查也包括名字空間是否正確地匹配。

9.15.3. 處理 XML

要處理數(shù)據(jù)類型xml的值, PostgreSQL 提供了函數(shù)xpathxpath_exists,它們計(jì)算 XPath 1.0 表達(dá)式以及XMLTABLE表函數(shù)。

9.15.3.1. xpath

xpath ( xpath text, xml xml [, nsarray text[] ] ) → xml[]

函數(shù)xpath根據(jù) XML 值xml計(jì)算 XPath 1.0 表達(dá)式xpath (以文本形式給出)。 它返回一個(gè) XML 值的數(shù)組,該數(shù)組對(duì)應(yīng)于該 XPath 表達(dá)式產(chǎn)生的結(jié)點(diǎn)集合。 如果該 XPath 表達(dá)式返回一個(gè)標(biāo)量值而不是一個(gè)結(jié)點(diǎn)集合,將會(huì)返回一個(gè)單一元素的數(shù)組。

第二個(gè)參數(shù)必須是一個(gè)良構(gòu)的 XML 文檔。特殊地,它必須有一個(gè)單一根結(jié)點(diǎn)元素。

該函數(shù)可選的第三個(gè)參數(shù)是一個(gè)名字空間映射的數(shù)組。這個(gè)數(shù)組應(yīng)該是一個(gè)二維text數(shù)組,其第二軸長(zhǎng)度等于2(即它應(yīng)該是一個(gè)數(shù)組的數(shù)組,其中每一個(gè)都由剛好 2 個(gè)元素組成)。每個(gè)數(shù)組項(xiàng)的第一個(gè)元素是名字空間的名稱(別名),第二個(gè)元素是名字空間的 URI。并不要求在這個(gè)數(shù)組中提供的別名和在 XML 文檔本身中使用的那些名字空間相同(換句話說,在 XML 文檔中和在xpath函數(shù)環(huán)境中,別名都是 本地的 )。

例子:

SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
             ARRAY[ARRAY['my', 'http://example.com']]);

 xpath  
--------
 {test}
(1 row)

要處理默認(rèn)(匿名)命名空間,做這樣的事情:

SELECT xpath('//mydefns:b/text()', '<a xmlns="http://example.com"><b>test</b></a>',
             ARRAY[ARRAY['mydefns', 'http://example.com']]);

 xpath
--------
 {test}
(1 row)

9.15.3.2. xpath_exists

xpath_exists ( xpath text, xml xml [, nsarray text[] ] ) → boolean

函數(shù)xpath_existsxpath函數(shù)的一種特殊形式。這個(gè)函數(shù)不是返回滿足 XPath 1.0 表達(dá)式的單一 XML 值,它返回一個(gè)布爾值表示查詢是否被滿足(具體來說,它是否產(chǎn)生了空節(jié)點(diǎn)集以外的任何值)。這個(gè)函數(shù)等價(jià)于標(biāo)準(zhǔn)的XMLEXISTS謂詞,不過它還提供了對(duì)一個(gè)名字空間映射參數(shù)的支持。

例子:

SELECT xpath_exists('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
                     ARRAY[ARRAY['my', 'http://example.com']]);

 xpath_exists  
--------------
 t
(1 row)

9.15.3.3. xmltable

XMLTABLE (    [ XMLNAMESPACES ( namespace_uri AS namespace_name [, ...] ), ]    row_expression PASSING [BY {REF|VALUE}] document_expression [BY {REF|VALUE}]    COLUMNS name { type [PATH column_expression] [DEFAULT default_expression] [NOT NULL | NULL]                  | FOR ORDINALITY }            [, ...]) → setof record

xmltable表達(dá)式基于給定的XML值產(chǎn)生一個(gè)表、一個(gè)抽取行的XPath過濾器以及一個(gè)列定義集合。 雖然它在語法上類似于函數(shù),但它只能作為一個(gè)表出現(xiàn)在查詢的FROM子句中。

可選的XMLNAMESPACES子句是一個(gè)逗號(hào)分隔的名字空間定義列表。 其中每個(gè)namespace_uri是一個(gè)text表達(dá)式,每個(gè)namespace_name是一個(gè)簡(jiǎn)單的標(biāo)識(shí)符。 它指定文檔中使用的XML名字空間極其別名。當(dāng)前不支持默認(rèn)的名字空間說明。

所需的row_expression參數(shù)是一個(gè)求值的XPath 1.0表達(dá)式(以text形式給出),通過傳遞XML值document_expression作為其上下文項(xiàng),得到一組XML節(jié)點(diǎn)。 這些節(jié)點(diǎn)就是xmltable轉(zhuǎn)換為輸出行的內(nèi)容。如果 document_expression 為空,或者row_expression產(chǎn)生空節(jié)點(diǎn)集或節(jié)點(diǎn)集以外的任何值,則不會(huì)產(chǎn)生行。

document_expression提供了上下文。row_expression的項(xiàng)。 它必須是一個(gè)格式良好的XML文檔;不接受片段/森林。BY REFBY VALUE子句 如上文所討論的那樣,被接受但被忽略了,正如在 第 D.3.2 節(jié)中所討論的。

在SQL標(biāo)準(zhǔn)中,xmltable函數(shù) 評(píng)估XML查詢語言中的表達(dá)式。 但PostgreSQL只允許使用XPath 1.0的 表達(dá)式,正如在 第 D.3.1 節(jié)所討論的。

需要的COLUMNS子句指定將在輸出表中生成的列。有關(guān)格式,請(qǐng)參閱上面的語法摘要。 每個(gè)列都需要一個(gè)名稱,作為一個(gè)數(shù)據(jù)類型(除非指定了 FOR ORDINALITY,在這種情況下類型 integer是隱式的)。 路徑、默認(rèn)值以及為空性子句是可選的。

被標(biāo)記為FOR ORDINALITY的列將按照從row_expression的結(jié)果節(jié)點(diǎn)集中檢索到的節(jié)點(diǎn)的順序,從1開始,填充行號(hào)。最多只能有一個(gè)列被標(biāo)記為FOR ORDINALITY。

注意

XPath 1.0 并沒有為節(jié)點(diǎn)集中的節(jié)點(diǎn)指定順序,因此依賴特定結(jié)果順序的代碼將取決于實(shí)現(xiàn)。 詳情請(qǐng)參見 第 D.3.1.2 節(jié)

列的column_expression是一個(gè)XPath 1.0表達(dá)式,它對(duì)每一行都要進(jìn)行求值,并以row_expression結(jié)果中的當(dāng)前節(jié)點(diǎn)作為其上下文項(xiàng),以找到列的值。 如果沒有給出column_expression,那么列名被用作隱式路徑。

如果一個(gè)列的XPath表達(dá)式返回一個(gè)非XML值(在XPath 1.0中僅限于string、boolean或double),而該列的PostgreSQL類型不是xml,那么該列將被設(shè)置為將值的字符串表示法分配給PostgreSQL類型。 (如果值是布爾值,如果輸出列的類型類別是數(shù)字,那么它的字符串表示方式將被認(rèn)為是10,否則 truefalse。)

如果一個(gè)列的XPath表達(dá)式返回一個(gè)非空的XML節(jié)點(diǎn)集,并且該列的PostgreSQL類型是xml,那么如果該列是文檔或內(nèi)容形式的,那么該列將被精確地分配表達(dá)式結(jié)果。 [7]

分配給xml輸出列的非XML結(jié)果會(huì)產(chǎn)生內(nèi)容,一個(gè)帶有結(jié)果字符串值的單個(gè)文本節(jié)點(diǎn)。分配給任何其他類型的列的XML結(jié)果不能有一個(gè)以上的節(jié)點(diǎn),否則會(huì)產(chǎn)生錯(cuò)誤。如果正好有一個(gè)節(jié)點(diǎn),則該列將被設(shè)置為將該節(jié)點(diǎn)的字符串值(如XPath 1.0 string函數(shù)定義的那樣)分配給PostgreSQL類型。

一個(gè)XML元素的字符串值是字符串值的協(xié)整,按文檔的順序。該元素中包含的所有文本節(jié)點(diǎn)及其子節(jié)點(diǎn)。字符串 元素的值是一個(gè)沒有下級(jí)文本節(jié)點(diǎn)的元素的值是一個(gè) 空字符串(不是NULL)。任何xsi:nil屬性都會(huì)被忽略。請(qǐng)注意,兩個(gè)非文本之間的text()節(jié)點(diǎn)只用空格,而兩個(gè)非文本 元素,并且保留了text()上的前導(dǎo)白格。節(jié)點(diǎn)不被扁平化。XPath 1.0中的string函數(shù)可以參考XPath 1.0中的 定義其他XML節(jié)點(diǎn)類型和非XML值的字符串值的規(guī)則。

這里介紹的轉(zhuǎn)換規(guī)則并不完全是SQL標(biāo)準(zhǔn)中的轉(zhuǎn)換規(guī)則,如第 D.3.1.3 節(jié)中討論的那樣。

如果路徑表達(dá)式為給定行返回一個(gè)空節(jié)點(diǎn)集(通常情況下,當(dāng)它不匹配時(shí)),該列將被設(shè)置為NULL,除非指定了default_expression;然后使用評(píng)價(jià)該表達(dá)式產(chǎn)生的值。

default_expression,而不是在調(diào)用xmltable時(shí)立即被評(píng)價(jià),而是在每次需要列的默認(rèn)值時(shí),都會(huì)被評(píng)價(jià)。 如果表達(dá)式符合穩(wěn)定或不可更改的條件,則可以跳過重復(fù)評(píng)價(jià)。 這意味著,你可以在default_expression中使用像nextval這樣的不穩(wěn)定函數(shù)。

列可能會(huì)被標(biāo)記為NOT NULL。如果一個(gè)NOT NULL列的column_expression不匹配任何東西并且沒有DEFAULT或者default_expression也計(jì)算為空,則會(huì)報(bào)告一個(gè)錯(cuò)誤。

例子:

CREATE TABLE xmldata AS SELECT
xml $$
<ROWS>
  <ROW id="1">
    <COUNTRY_ID>AU</COUNTRY_ID>
    <COUNTRY_NAME>Australia</COUNTRY_NAME>
  </ROW>
  <ROW id="5">
    <COUNTRY_ID>JP</COUNTRY_ID>
    <COUNTRY_NAME>Japan</COUNTRY_NAME>
    <PREMIER_NAME>Shinzo Abe</PREMIER_NAME>
    <SIZE unit="sq_mi">145935</SIZE>
  </ROW>
  <ROW id="6">
    <COUNTRY_ID>SG</COUNTRY_ID>
    <COUNTRY_NAME>Singapore</COUNTRY_NAME>
    <SIZE unit="sq_km">697</SIZE>
  </ROW>
</ROWS>
$$ AS data;

SELECT xmltable.*
  FROM xmldata,
       XMLTABLE('//ROWS/ROW'
                PASSING data
                COLUMNS id int PATH '@id',
                        ordinality FOR ORDINALITY,
                        "COUNTRY_NAME" text,
                        country_id text PATH 'COUNTRY_ID',
                        size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
                        size_other text PATH
                             'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
                        premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified');

 id | ordinality | COUNTRY_NAME | country_id | size_sq_km |  size_other  | premier_name  
----+------------+--------------+------------+------------+--------------+---------------
  1 |          1 | Australia    | AU         |            |              | not specified
  5 |          2 | Japan        | JP         |            | 145935 sq_mi | Shinzo Abe
  6 |          3 | Singapore    | SG         |        697 |              | not specified

接下來的例子展示了多個(gè)text()節(jié)點(diǎn)的串接、列名用作XPath過濾器的用法以及對(duì)空格、XML注釋和處理指令的處理:

CREATE TABLE xmlelements AS SELECT
xml $$
  <root>
   <element>  Hello<!-- xyxxz -->2a2<?aaaaa?> <!--x-->  bbb<x>xxx</x>CC  </element>
  </root>
$$ AS data;

SELECT xmltable.*
  FROM xmlelements, XMLTABLE('/root' PASSING data COLUMNS element text);
         element         
-------------------------
   Hello2a2   bbbxxxCC  

下面的例子展示了如何使用XMLNAMESPACES子句指定用在XML文檔以及XPath表達(dá)式中的名字空間列表:

WITH xmldata(data) AS (VALUES ('
<example xmlns="http://example.com/myns" xmlns:B="http://example.com/b">
 <item foo="1" B:bar="2"/>
 <item foo="3" B:bar="4"/>
 <item foo="4" B:bar="5"/>
</example>'::xml)
)
SELECT xmltable.*
  FROM XMLTABLE(XMLNAMESPACES('http://example.com/myns' AS x,
                              'http://example.com/b' AS "B"),
             '/x:example/x:item'
                PASSING (SELECT data FROM xmldata)
                COLUMNS foo int PATH '@foo',
                  bar int PATH '@B:bar');
 foo | bar
-----+-----
   1 |   2
   3 |   4
   4 |   5
(3 rows)

9.15.4. 將表映射到 XML

下面的函數(shù)將會(huì)把關(guān)系表的內(nèi)容映射成 XML 值。它們可以被看成是 XML 導(dǎo)出功能:

table_to_xml ( table regclass, nulls boolean,
               tableforest boolean, targetns text ) → xml
query_to_xml ( query text, nulls boolean,
               tableforest boolean, targetns text ) → xml
cursor_to_xml ( cursor refcursor, count integer, nulls boolean,
                tableforest boolean, targetns text ) → xml

table_to_xml映射由參數(shù)table傳遞的命名表的內(nèi)容。regclass類型接受使用常見標(biāo)記標(biāo)識(shí)表的字符串,包括可選的模式限定和雙引號(hào)。query_to_xml執(zhí)行由參數(shù)query傳遞的查詢并且映射結(jié)果集。 cursor_to_xmlcursor指定的游標(biāo)中取出指定數(shù)量的行。如果需要映射一個(gè)大型的表,我們推薦這種變體,因?yàn)槊恳粋€(gè)函數(shù)都是在內(nèi)存中構(gòu)建結(jié)果值的。

如果tableforest為假,則結(jié)果的 XML 文檔看起來像這樣:

<tablename>
  <row>
    <columnname1>data</columnname1>
    <columnname2>data</columnname2>
  </row>
  <row>    ...  </row>  ...
</tablename>

如果tableforest為真,結(jié)果是一個(gè)看起來像這樣的 XML 內(nèi)容片斷:

<tablename>
  <columnname1>data</columnname1>
  <columnname2>data</columnname2>
</tablename>

<tablename>
  ...
</tablename>

...

如果沒有表名可用,在映射一個(gè)查詢或一個(gè)游標(biāo)時(shí),在第一種格式中使用串table,在第二種格式中使用row。

這幾種格式的選擇由用戶決定。第一種格式是一個(gè)正確的 XML 文檔,它在很多應(yīng)用中都很重要。如果結(jié)果值要被重組為一個(gè)文檔,第二種格式在cursor_to_xml函數(shù)中更有用。前文討論的產(chǎn)生 XML 內(nèi)容的函數(shù)(特別是xmlelement)可以被用來把結(jié)果修改成符合用戶的要求。

數(shù)據(jù)值會(huì)被以前文的函數(shù)xmlelement中描述的相同方法映射。

參數(shù)nulls決定空值是否會(huì)被包含在輸出中。如果為真,列中的空值被表示為:

<columnname xsi:nil="true"/>

其中xsi是 XML 模式實(shí)例的 XML 名字空間前綴。一個(gè)合適的名字空間聲明將被加入到結(jié)果值中。如果為假,包含空值的列將被從輸出中忽略掉。

參數(shù)targetns指定想要的結(jié)果的 XML 名字空間。如果沒有想要的特定名字空間,將會(huì)傳遞一個(gè)空串。

下面的函數(shù)返回 XML 模式文檔,這些文檔描述上述對(duì)應(yīng)函數(shù)所執(zhí)行的映射:

table_to_xmlschema ( table regclass, nulls boolean,
                     tableforest boolean, targetns text ) → xml
query_to_xmlschema ( query text, nulls boolean,
                     tableforest boolean, targetns text ) → xml
cursor_to_xmlschema ( cursor refcursor, nulls boolean,
                      tableforest boolean, targetns text ) → xml

最重要的是相同的參數(shù)被傳遞來獲得匹配的 XML 數(shù)據(jù)映射和 XML 模式文檔。

下面的函數(shù)產(chǎn)生 XML 數(shù)據(jù)映射和對(duì)應(yīng)的 XML 模式,并把產(chǎn)生的結(jié)果鏈接在一起放在一個(gè)文檔(或森林)中。在要求自包含和自描述的結(jié)果是它們非常有用:

table_to_xml_and_xmlschema ( table regclass, nulls boolean,
                             tableforest boolean, targetns text ) → xml
query_to_xml_and_xmlschema ( query text, nulls boolean,
                             tableforest boolean, targetns text ) → xml

另外,下面的函數(shù)可用于產(chǎn)生相似的整個(gè)模式或整個(gè)當(dāng)前數(shù)據(jù)庫的映射:

schema_to_xml ( schema name, nulls boolean,
                tableforest boolean, targetns text ) → xml
schema_to_xmlschema ( schema name, nulls boolean,
                      tableforest boolean, targetns text ) → xml
schema_to_xml_and_xmlschema ( schema name, nulls boolean,
                              tableforest boolean, targetns text ) → xml

database_to_xml ( nulls boolean,
                  tableforest boolean, targetns text ) → xml
database_to_xmlschema ( nulls boolean,
                        tableforest boolean, targetns text ) → xml
database_to_xml_and_xmlschema ( nulls boolean,
                                tableforest boolean, targetns text ) → xml

這些函數(shù)會(huì)忽略當(dāng)前用戶不可讀的表。數(shù)據(jù)庫范圍的函數(shù)還會(huì)忽略當(dāng)前用戶沒有USAGE (查找)權(quán)限的模式。

請(qǐng)注意,這可能會(huì)產(chǎn)生大量數(shù)據(jù),這些數(shù)據(jù)需要在內(nèi)存中構(gòu)建。 當(dāng)請(qǐng)求大型模式或數(shù)據(jù)庫的內(nèi)容映射時(shí),可能值得考慮單獨(dú)映射表,甚至可能通過游標(biāo)。

一個(gè)模式內(nèi)容映射的結(jié)果看起來像這樣:

<schemaname>
table1-mapping
table2-mapping
...
</schemaname>

其中一個(gè)表映射的格式取決于上文解釋的tableforest參數(shù)。

一個(gè)數(shù)據(jù)庫內(nèi)容映射的結(jié)果看起來像這樣:

<dbname>
<schema1name>
  ...
</schema1name>
<schema2name>
  ...
</schema2name>
...
</dbname>

其中的模式映射如上所述。

作為一個(gè)使用這些函數(shù)產(chǎn)生的輸出的例子,例 9.1展示了一個(gè) XSLT 樣式表,它將table_to_xml_and_xmlschema的輸出轉(zhuǎn)換為一個(gè)包含表數(shù)據(jù)的扁平轉(zhuǎn)印的 HTML 文檔。以一種相似的方式,這些函數(shù)的結(jié)果可以被轉(zhuǎn)換成其他基于 XML 的格式。

例 9.1. 轉(zhuǎn)換 SQL/XML 輸出到 HTML 的 XSLT 樣式表

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
>

  <xsl:output method="xml"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
      doctype-public="-//W3C/DTD XHTML 1.0 Strict//EN"
      indent="yes"/>

  <xsl:template match="/*">
    <xsl:variable name="schema" select="http://xsd:schema"/>
    <xsl:variable name="tabletypename"
                  select="$schema/xsd:element[@name=name(current())]/@type"/>
    <xsl:variable name="rowtypename"
                  select="$schema/xsd:complexType[@name=$tabletypename]/xsd:sequence/xsd:element[@name='row']/@type"/>

    <html>
      <head>
        <title><xsl:value-of select="name(current())"/></title>
      </head>
      <body>
        <table>
          <tr>
            <xsl:for-each select="$schema/xsd:complexType[@name=$rowtypename]/xsd:sequence/xsd:element/@name">
              <th><xsl:value-of select="."/></th>
            </xsl:for-each>
          </tr>

          <xsl:for-each select="row">
            <tr>
              <xsl:for-each select="*">
                <td><xsl:value-of select="."/></td>
              </xsl:for-each>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>



[7] 在頂層包含一個(gè)以上的元素節(jié)點(diǎn)的結(jié)果,或者在元素之外的非空格文本,就是內(nèi)容形式的一個(gè)例子。一個(gè)XPath結(jié)果可以是這兩種形式的,例如,如果它返回的是一個(gè)從包含它的元素中選擇的屬性節(jié)點(diǎn)。這樣的結(jié)果將被放到內(nèi)容形式中,每個(gè)不允許的節(jié)點(diǎn)都會(huì)被替換為它的字符串值,就像XPath 1.0string 函數(shù)定義的那樣。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)