Documentazione di PostgreSQL 9.0 > Il linguaggio SQL > Funzioni e Operatori > Funzioni XML
PrecedenteFunzioni e operatori per ricerca testoFunzioni di manipolazione sequenzeSuccessivo

9.14. Funzioni XML

Le funzioni e le espressioni descritte in questa sezione agiscono sui valori di tipo xml. Consultare Sezione 8.13, «Tipo XML» per informazioni circa il tipo xml. Le espressioni xmlparse e xmlserialize per conversioni a e da xml non sono ripetute quì. L'utilizzo per molte di queste funzioni richiede che PostgreSQL™ sia stato compilato con configure --with-libxml.

9.14.1. Produrre contenuti XML

Un insieme di funzioni e di espressioni sono disponibili per produrre contenuti XML da dati SQL. Come tali, esse sono particolarmente adatte per formattare i risultati delle query nei documenti XML per la trattazione in applicazioni client.

9.14.1.1. xmlcomment

xmlcomment(text)

La funzione xmlcomment crea un valore XML contenente un commento XML con il testo specificato come contenuto. Il testo non deve contenere -- o finire con un - in modo che il costrutto risultante sia un valido commento XML. Se l'argomento è null, il risultato è null.

Esempio:

SELECT xmlcomment('hello');

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

9.14.1.2. xmlconcat

xmlconcat(xml[, ...])

La funzione xmlconcat concatena una lista di valori individuali XML per creare un singolo valore contenente un frammento di contenuto XML. I valori null sono omessi; il risultato è null solo se non ci sono argomenti non-null.

Esempio:

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

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

Le dichiarazioni XML, se presenti, sono combinate come segue. Se tutti i valori degli argomenti hanno la stessa dichiarazione di versione XML, nel risultato viene utilizzata quella versione, altrimenti non viene usata nessuna versione. Se tutti i valori degli argomenti hanno il valore autonomo di dichiarazione «yes», allora quel valore viene utilizzato nel risultato. Se tutti i valori degli argomenti hanno un valore autonomo di dichiarazione e al massimo uno di questi è «no», allora quello viene utilizzato nel risultato. Altrimenti il risultato non avrà una dichiarazione autonoma. Se il risultato è determinato per richiedere una dichiarazione autonoma ma non una dichiarazione di versione, sarà usata una dichiarazione di versione con la versione 1.0 in quanto XML richiede che una dichiarazione XML contenga una dichiarazione di versione. Le dichiarazioni di codifica in tutti i casi vengono ignorate e rimosse.

Esempio:

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

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

9.14.1.3. xmlelement

xmlelement(name name [, xmlattributes(value [AS attname] [, ... ])] [, content, ...])

L'espressione xmlelement produce un elemento XML con il nome fornito, gli attributi ed il contenuto.

Esempio:

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>

I nomi degli elementi e degli attributi che non sono nomi validi XML vengono sottoposti ad escape sostituendo i caratteri non validi con la sequenza _xHHHH_, dove HHHH è il codice del carattere Unicode in notazione esadecimale. Per esempio:

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

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

Un esplicito nome di attributo non deve essere specificato se il valore dell'attributo è un riferimento di colonna, in questo caso deve essere usato il nome predefinito della colonna come attributo. In nessun altro caso, dovrà essere fornito un nome esplicito all'attributo. Per cui questo esempio è valido:

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

Ma questi non lo sono:

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

Il contenuto dell'elemento, se specificato, sarà formattato in funzione del tipo di dato. Se il contenuto è esso stesso di tipo xml, potrà essere costruito un documento XML complesso. Per esempio:

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

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

Contenuti di altri tipi saranno formattati in dati carattere VALIDI XML. Questo significa, in particolare, che i caratteri <, >, e & saranno convertiti in entità. I dati binari (tipi dati bytea) saranno rappresentati in base64 o in codifica esadecimale, in dipendenza dell'impostazione del parametro di configurazione xmlbinary. Il comportamento particolare per gli individuali tipi di dati si dovrebbe evolvere in modo da allineare i tipi di dati SQL e PostgreSQL con la specificha di XML Schema, a quel punto verrà visualizzata una descrizione più precisa.

9.14.1.4. xmlforest

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

L'espressione xmlforest produce una foresta (sequenza) di elementi XML che utilizza nome e contenuto dati.

Esempi:

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>
 ...

Come si è visto nel secondo esempio, il nome di elemento può essere omesso se il valore del contenuto è un riferimento di colonna, in questo caso il nome della colonna viene usato in maniera predefinita. Altrimenti, deve essere specificato un nome.

I nomi degli elementi che non sono nomi validi XML vengono sottoposti ad escape come visto sopra per xmlelement. In modo simile, il dato contenuto viene escaped per renderlo un contenuto valido XML, a meno che esso non sia già di tipo xml.

Notare che le foreste XML non sono documenti XML validi se consistono di più di un elemento. Per cui potrebbe essere utili racchiudere espressioni xmlforest dentro xmlelement.

9.14.1.5. xmlpi

xmlpi(name target [, content])

L'espressione xmlpi crea una istruzione di elaborazione XML. Il contenuto, se presente, non dovrà contenere la sequenza di caratteri ?>.

Esempio:

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

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

9.14.1.6. xmlroot

xmlroot(xml, version text | no value [, standalone yes|no|no value])

L'espressione xmlroot altera la proprietà del nodo radice di un valore XML. Se una versione è specificata, questa sostituisce il valore nella dichiarazione di versione, se è specificato un valore autonomo, questa sostituisce il valore nella dichiarazione autonoma.

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.14.1.7. xmlagg

xmlagg(xml)

La funzione xmlagg è, a differenza delle altre funzioni descritte qui, una funzione aggregata. Essa concatena i valori in input alla chiamata della funzione aggregata, come fa xmlconcat, ad eccezione che la concatenazione viene fatta attraverso le righe piuttosto che attraverso le espressioni in una singola righa. Vedere Sezione 9.18, «Funzioni aggregate» per informazioni aggiuntive sulle funzioni aggregate.

Esempio:

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/>

Per determinare l'ordine della concatenazione, una clausola ORDER BY può essere aggiunta alla chiamata come descritto in Sezione 4.2.7, «Espressioni aggregate». Per esempio:

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

Il seguente approccio non standard veniva raccomandato nelle versioni precedenti, e può ancora tornare utile in specifici casi:

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

9.14.2. Predicati XML

Le espressioni descritte in questa sezione controllano le proprietà dei valori xml.

9.14.2.1. IS DOCUMENT

xml IS DOCUMENT

L'espressione IS DOCUMENT restituisce true se il valore dell'argomento XML è un documento XML corretto, false se non lo è (che vuol dire che si tratta di un frammento di XML), o null se l'argomento è null. Vedere Sezione 8.13, «Tipo XML» per la differenza tra documenti e frammenti di contenuto.

9.14.2.2. XMLEXISTS

XMLEXISTS(text PASSING [BY REF] xml [BY REF])

La funzione xmlexists restituisce true se l'espressione XPath nel primo argomento restituisce qualche nodo, altrimenti false. (Se o l'uno o l'altro argomento è null, il risultato sarà null).

Esempio:

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

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

Le clausole BY REF non ha effetto in PostgreSQL, ma sono permesse per conformità SQL e compatibilità con altre implementazioni. Per lo standard SQL, la prima BY REF è richiesta, la seconda è opzionale. Notare inoltre che lo standard SQL specifica il costrutto xmlexists possa prendere un espressione XQuery come primo argomento, ma PostgreSQL attualmente supporta solo XPath, che è un sottoinsieme di XQuery.

9.14.2.3. xml_is_well_formed

xml_is_well_formed(text)
xml_is_well_formed_document(text)
xml_is_well_formed_content(text)

Queste funzioni controllano se una stringa text è XML ben formato, e ritornano un risultato booleano. xml_is_well_formed_document controlla se un documento è ben formato, mentre xml_is_well_formed_content controlla se un contenuto è ben formato. xml_is_well_formed esegue il precedente se il parametro di configurazione xmloption è impostato a DOCUMENT, o l'ultimo se è impostata a CONTENT. Questo significa che xml_is_well_formed è utile per vedere se una semplice conversione di tipo xml avrà successo, dal momento che altre due funzioni sono utili per vedere se le varianti corrispondenti di XMLPARSE avranno successo.

Esempi:

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)

The last example shows that the checks include whether namespaces are correctly matched.

9.14.3. Elaborazione XML

Per elaborare valori di tipo dato xml, PostgreSQL offre le funzioni xpath e xpath_exists, la quale valuta le espressioni XPath 1.0.

xpath(xpath, xml [, nsarray])

La funzione xpath valuta le espressioni XPath xpath (un valore text) in confronto al valore XML xml. Essa restituisce un array di valori XML corrispondenti all'insieme di nodi prodotto dall'espressione XPath.

Il secondo argomento dev'essere un documento XML ben formato. In particolare, deve avere un singolo elemento radice.

Il terzo, opzionale, argomento della funzione è un array di mappature di namespace. Questo array dovrebbe essere un array di text bi-dimensionale con la lunghezza del secondo asse uguale a 2 (per es., dovrebbe essere un array di array, ognuno dei quali consiste di esattamente 2 elementi). Il primo elemento di ogni elemento array è il nome del namespace (alias), il secondo è l'URI del namespace. Non è richiesto che gli alias forniti in questo array siano gli stessi usati nel documento XML stesso (in altre parole, sia nel documento XML sia nel contesto della funzione xpath, gli alias sono locali).

Esempio:

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)

Per lavorare con il namespace di default (anonimo), fare qualcosa tipo questo:

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

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

xpath_exists(xpath, xml [, nsarray])

La funzione xpath_exists è una forma specializzata della funzione xpath. Invece di ritornare i valori XML individuali che soddisfano XPath, questa funzione ritorna un booleano che indica se la query è soddisfatta o meno. Questa funzione è equivalente al predicato standard XMLEXISTS, ad eccezione che offre anche supporto per un argomento di mappatura di namespace.

Esempio:

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.14.4. Tabelle di mappatura a XML

Le seguenti funzioni mappano il contenuto di tabelle relazionali a valori XML. Esse possono essere pensate come funzionalità di esportazione di XML:

table_to_xml(tbl regclass, nulls boolean, tableforest boolean, targetns text)
query_to_xml(query text, nulls boolean, tableforest boolean, targetns text)
cursor_to_xml(cursor refcursor, count int, nulls boolean, 
              tableforest boolean, targetns text)

Il tipo di ritorno di ogni funzione è xml.

La funzione table_to_xml mappa il contenuto della tabella nominata, passata come parametro tbl. Il tipo regclass accetta le stringhe che identificano tabelle usando la notazione normale, compresa la qualificazione con schema opzionale ed i doppi apici. La funzione query_to_xml eseque la query il cui testo viene passato come parametro query e mappa l'insieme risultato. La funzione cursor_to_xml ottiene il numero di righe indicato dal cursore specificato con il parametro cursor. Questa variabile è raccomandate se si devono mappare grandi tabelle, in quanto il risultato è accumulato in memoria da ogni funzione.

Se tableforest è false, allora il documento XML risultante sarà simile a questo:

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

  <row>
    ...
  </row>

  ...
</tablename>

Se tableforest è true, il risultato è un frammento di contenuto XML che sarà simile a questo:

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

<tablename>
  ...
</tablename>

...

Se il nome della tabella non è disponibile, mappando una query o un cursore, è stata usata le stringa table nel primo formato, la stringa row nel secondo formato.

La scelta tra questi formati dipende dall'utente. Il primo formato è un documento XML corretto, che sarà importante in molte applicazioni. Il secondo tende ad essere più utile nella funzione cursor_to_xml se i valori risultanti devono essere in seguito riassemblati in un documento. Le funzioni per produrre i contenuti XML discussi sopra, in particolare xmlelement, possono essere usate per provare ad alterare i risultati.

I valori dei dati vengono mappati nella stessa maniera descritta sopra per la funzione xmlelement.

Il parametro nulls determina se i valori null devono essere inclusi in output. Se è true, i valori null nelle colonne sono rappresentati come:

<columnname xsi:nil="true"/>

dove xsi è il prefisso del namespace per XML Schema Instance. Una adeguata dichiarazione del nomespace deve essere aggiunta al valore del risultato. Se è falso, le colonne contenenti valori null sono semplicemente omesse dall'output.

Il parametro targetns specifica il namespace del risultato XML desirato. Se nessun particolare namespace è voluto, verrà passata una stringa vuota.

Le seguenti funzioni restituiscono il documento XML Schema che descrive le mappature prodotte dalle corrispondenti funzioni viste sopra:

table_to_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text)
query_to_xmlschema(query text, nulls boolean, tableforest boolean, targetns text)
cursor_to_xmlschema(cursor refcursor, nulls boolean, tableforest boolean, targetns text)

È essenziale che gli stessi parametri siano passati in modo da ottenere corrispondenza tra la mappatura dati XML e il documento XML Schema.

Le seguenti funzioni producono la mappatura dei dati XML ed il corrispondente XML Schema, uniti insieme, in un documento (o foresta). Possono essere utili dove si desiderano risultati auto-contenuti ed auto-descritti:

table_to_xml_and_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text)
query_to_xml_and_xmlschema(query text, nulls boolean, tableforest boolean, targetns text)

Inoltre, sono disponibili le seguenti funzioni per produrre analoghe mappature di un intero schema o l'intero datatbase corrente:

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

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

Notare che queste potenzialmente producono una grande quantità di dati, che devono essere costruiti in memoria. Quando è richiesto la mappatura di grandi schemi o database, può essere utile considerare la possibilità di mappare, invece, le tabelle separatamente, eventualmente anche tramite un cursore.

Il risultato contenuto in uno schema di mappatura sarà simile a questo:

<schemaname>

table1-mapping

table2-mapping

...

</schemaname>

dove il formato di mappatura di una tabella dipende dal parametro tableforest come spiegato sopra.

Il risultato contenuto in uno schema di mappatura sarà simile a questo:

<dbname>

<schema1name>
  ...
</schema1name>

<schema2name>
  ...
</schema2name>

...

</dbname>

dove lo schema di mappatura è come quello visto sopra.

Come esempio per l'utilizzo dell'output prodotto da queste funzioni, la Figura 9.1, «Foglio di stile XSLT per convertire l'uscita SQL/XML in HTML» mostra un foglio di stile XSLT che converte l'uscita di table_to_xml_and_xmlschema in un documento HTML contenente una rappresentazione tabulare dei dati di tabella. In modo simile, i dati risultanti di queste funzioni possono essere convertiti in altri formati basati-XML.

Figura 9.1. Foglio di stile XSLT per convertire l'uscita SQL/XML in HTML

<?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="//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>

Documentazione di PostgreSQL 9.0 > Il linguaggio SQL > Funzioni e Operatori > Funzioni XML
PrecedenteFunzioni e operatori per ricerca testoFunzioni di manipolazione sequenzeSuccessivo