SQL zum Lesen von XML aus einer Datei in eine PostgreSQL-Datenbank

12

Wie kann ich SQL schreiben, um eine XML-Datei in einen PostgreSQL- XMLWert zu lesen ?

PostgreSQL hat einen nativen XML-Datentyp mit der XMLPARSEFunktion, eine Textzeichenfolge auf diesen Typ zu analysieren. Es gibt auch Möglichkeiten, Daten aus dem Dateisystem zu lesen. die COPYAussage unter anderem.

Ich sehe jedoch keine Möglichkeit, native PostgreSQL-SQL-Anweisungen zu schreiben, um den Inhalt eines Dateisystemeintrags zu lesen und damit einen XMLWert aufzufüllen. Wie kann ich das machen?

große Nase
quelle

Antworten:

10

Ähnlich wie bei dieser Antwort auf eine vorherige Frage, und wenn Sie die Einschränkungen vonpg_read_file() nicht möchten (kurz gesagt: pg_read_fileKann keine Dateien außerhalb des Datenbankverzeichnisses lesen und liest Text in der Zeichencodierung der aktuellen Sitzung).

Diese Funktion funktioniert für jeden Pfad, muss jedoch als Superuser erstellt werden:

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 wurde in 9.4 eingeführt, daher benötigen Sie für ältere Versionen:

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;$$;

dann:

select convert_from(stack.bytea_import('/tmp/test.xml'), 'utf8')::xml;
Jack sagt, versuchen Sie es mit topanswers.xyz
quelle
1
+1, danke, dass Sie darauf hingewiesen haben, dass die Funktionen zum Lesen von Dateien Beschränkungen unterliegen.
Bignose
1
+1 netter Trick zu umgehen pg_read_file(). Dasselbe kann auch mit einer temporären Tabelle erreicht werden und COPY- nur 1 Spalte von 1 Zeile ausfüllen.
Erwin Brandstetter
4

Die pg_read_binary_fileFunktion kann dies tun.

Es gibt Einschränkungen: Neu in PostgreSQL 9.1 oder höher; muss eine Sitzung sein, die dem Datenbank-Superuser gehört; muss eine Datei innerhalb des Datenbankverzeichnisses oder darunter lesen. Diese sind in meinem Anwendungsfall akzeptabel.

Das Folgende funktioniert also, um einen nativen XMLWert aus einer Datei zu erstellen :

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

In PostgreSQL 8.3 - 9.0 kann die pg_read_fileFunktion verwendet werden, mit der zusätzlichen Einschränkung, dass Sie keine dateispezifische Codierung angeben können (die Datei wird als Text in der Codierung der aktuellen Sitzung gelesen).

-- PostgreSQL earlier than 9.1.
SELECT
    XMLPARSE(DOCUMENT pg_read_file('foo.xml'));
große Nase
quelle
3

Ich habe eine vollständige Implementierung dessen, wonach Sie fragen, in einer aktuellen Antwort auf SO veröffentlicht .

Die Hauptmerkmale sind die xpath()Funktion pg_read_file(), Array-Handling, plpgsql-Funktionen, ..

Erwin Brandstetter
quelle
Eher anders (und schwerer) als das, was ich in diesem Fall brauche. Aber +1 für die gute Richtung, danke.
Großnase
Es ist nicht so schwergewichtig, mein Beispiel ist nur sehr vollständig mit redundanten Elementen, um Syntaxvarianten zu demonstrieren.
Erwin Brandstetter