SQL per leggere XML da file nel database PostgreSQL


12

Come posso scrivere SQL per leggere un file XML in un XMLvalore PostgreSQL ?

PostgreSQL ha un tipo di dati XML nativo con la XMLPARSEfunzione di analizzare una stringa di testo per quel tipo. Ha anche modi per leggere i dati dal filesystem; la COPYdichiarazione, tra gli altri.

Ma non vedo un modo per scrivere istruzioni SQL PostgreSQL native per leggere il contenuto da una voce del filesystem e usarlo per popolare un XMLvalore. Come posso fare questo?

Risposte:


10

Simile a questa risposta a una domanda precedente e se non si desidera le restrizioni dipg_read_file() (in breve: pg_read_fileimpossibile leggere i file al di fuori della directory del database e legge il testo nella codifica dei caratteri della sessione corrente).

Questa funzione funziona per qualsiasi percorso, ma deve essere creata come superutente:

create or replace function stack.bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
begin
  select lo_import(p_path) into l_oid;
  select lo_get(l_oid) INTO p_result;
  perform lo_unlink(l_oid);
end;$$;

lo_get è stato introdotto in 9.4, quindi per le versioni precedenti sarebbe necessario:

create or replace function stack.bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
  r record;
begin
  p_result := '';
  select lo_import(p_path) into l_oid;
  for r in ( select data 
             from pg_largeobject 
             where loid = l_oid 
             order by pageno ) loop
    p_result = p_result || r.data;
  end loop;
  perform lo_unlink(l_oid);
end;$$;

poi:

select convert_from(stack.bytea_import('/tmp/test.xml'), 'utf8')::xml;

1
+1, grazie per aver sottolineato che ci sono limiti alle funzioni di lettura dei file.
Bignose,

1
+1 bel trucco per aggirare pg_read_file(). Lo stesso può essere ottenuto anche con una tabella temporanea e COPY- popolare solo 1 colonna di 1 riga.
Erwin Brandstetter,

4

La pg_read_binary_filefunzione può farlo.

Presenta limitazioni: novità in PostgreSQL 9.1 o versioni successive; deve essere una sessione di proprietà del superutente del database; deve leggere un file nella directory del database o in basso. Quelli sono accettabili nel mio caso d'uso.

Quindi il seguente funzionerà per creare un XMLvalore nativo da un file:

-- PostgreSQL 9.1 or later.
SELECT
    XMLPARSE(DOCUMENT convert_from(
        pg_read_binary_file('foo.xml'), 'UTF8'));

In PostgreSQL 8.3 - 9.0, la pg_read_filefunzione può essere utilizzata, con l'ulteriore limitazione che non è possibile specificare una codifica specifica del file (legge il file come testo nella codifica della sessione corrente).

-- PostgreSQL earlier than 9.1.
SELECT
    XMLPARSE(DOCUMENT pg_read_file('foo.xml'));

3

Ho pubblicato un'implementazione completa di ciò che stai chiedendo in una recente risposta su SO .

Le caratteristiche principali sono la xpath()funzione, la pg_read_file()gestione dell'array, le funzioni plpgsql, ..


Piuttosto diverso (e più pesante) di quello di cui ho bisogno in questo caso. Ma +1 per la buona direzione, grazie.
Bignose,

Non è così pesante, il mio esempio è solo molto completo con elementi ridondanti per dimostrare varianti di sintassi.
Erwin Brandstetter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.