xpath_table and namespaces

Hallo,

ich würde gerne die Funtkion xpath_table verwenden, allerding hat mein XML Namespaces und ich verstehe nicht wo ich für die XPATH Expressions die Namespaces angeben kann.

In der Doku finde ich leider nichts: https://www.postgresql.org/docs/9.1/static/xml2.html#AEN145365

Kennt jemand eine Möglichkeit die Namespaces anzugeben?

Danke,
Tobias

Kannst Du mal ein Beispiel Deines XML zeigen? (bitte mit ... tags formatieren, damit es lesbar ist)

Verwendest Du wirklich noch Postgres 9.1?

Hier ist ein Beispiel:

<TestSequence 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns="http://www.company.com/product/specification"
  Name="new sequence.001" 
  ID="0999fbaf-c696-4b06-b4b1-489bcc123b9a" 
  InternalId="0" 
  RepeatCounter="1" />  
    <TestBlockLink Id="fff6f74e-0ee4-4c70-9cf8-f1f27e5f4391" Name="Reset" InternalId="1" 
                           IdLinkedBlock="b71c0f05-00b5-4086-a1e8-574094565986" RepeatCounter="123" />
    <TestBlockLink Id="f8c6b3a5-0491-4969-bab7-3cf606217e67" Name="Switch_1" InternalId="2" 
                           IdLinkedBlock="1b5e0458-a383-468d-ab44-1468d783aab0" />
    <TestBlockLink Id="80ffd8c7-90c2-4b99-bc3c-bffa37827784" Name="1234" InternalId="3" 
                           IdLinkedBlock="c889b9b9-a5f6-4388-8d87-8fff6734bcbc" />
</TestSequence>

versucht habe ich es mit

SELECT * FROM
xpath_table('id',
            'xmldata',
            'tpa.testelement',
            '//TestBlockLink/@Id|//TestBlockLink/@Name|//TestBlockLink/@RepeatCounter|//TestBlockLink/@IdLinkedBlock',
            'true')
AS t(id uuid, linkid uuid, name text, loops integer, idlinkedblock uuid);

Nein ich verwende nicht mehr 9.1, das war nur das Ergebnis der Google-Suche, als ich nach der Doku gesucht habe.

Ich glaube nicht, dass man mit xpath_table namespaces übergeben kann, aber mit Postgres 10 kannst Du das so machen:

select x.*
from testelement, 
     xmltable(
        xmlnamespaces('http://www.company.com/product/specification' as ps), 
        '//ps:TestBlockLink' passing xmldata
        columns id uuid path '@Id', 
                name text path '@Name', 
                loops int path '@RepeatCounter', 
                id_linked_block uuid path '@IdLinkedBlock') as x

Online Beispiel: https://dbfiddle.uk/?rdbms=postgres_10&fiddle=71f26ea23e0d0f86e58b2d8ac5f57b17

Mit 9.6 oder früher, wird es etwas hässlicher:

with namespaces (nsp) as (
  values ( array[array['ps', 'http://www.company.com/product/specification']] )
)
select (xpath('//ps:TestBlockLink/@Id', t.xmldata, nsp))[1]::text::uuid as id, 
       (xpath('//ps:TestBlockLink/@Name', t.xmldata, nsp))[1]::text as name,
       (xpath('//ps:TestBlockLink/@RepeatCounter', t.xmldata, nsp))[1]::text::int as loops,
       (xpath('//ps:TestBlockLink/@IdLinkedBlock', t.xmldata, nsp))[1]::text::uuid as id_linked_block
from testelement t,  
     namespaces

Die xpath() Funktion liefert ein Array mit allen gefundenen XML Elementen zurück. Man kann da aber nicht mit | arbeiten, weil das resultierende array nur die gefundenen Elemente enthält, nicht etwa einen “NULL” Wert für Element die über den XPATH Ausdruck nicht gefunden wurden. Die CTE mit dem Namespace array ist nur eine Vereinfachung, damit man das nicht bei jedem xpath() Aufruf wieder hinschreiben muss.

Schade, dass ich im Moment nicht auf PG10 wechseln kann. Aber auch das Beispiel mit den CTEs ist sehr hilfreich. Vielen Dank. So komme ich weiter.