15. Oktober 2008

PDF und andere Binärformate in HTML umwandeln: Mit der Datenbank

English title: Convert PDF or other binary documents into HTML - with the database!

Der in der Datenbank enthaltene Volltextindex Oracle TEXT (dazu gibt es ein eigenes Blog) kann neben einfachen ASCII Texten auch gängige Dokumentformate indizieren. So werden Formate wie Microsoft Office, das PDF-Format und andere unterstützt. Technisch wird dies durch einen Filter-Mechanismus realisiert; der Filter wandelt die Binärformate in HTML um - dieses wird dann indiziert.
Oracle TEXT, the fulltext indexing engine inside the Oracle Database, can not only index ASCII or HTML documents but also common (binary) document formats like Microsoft Office, PDF or others. This is achieved with a document filter which converts the binary content to HTML - which is then being indexed.
Das Schöne ist nun, dass man den Filter auch separat (also losgelöst vom Volltextindex) nutzen kann. So kann man sich eine PL/SQL-Funktion schreiben, die einen BLOB entgegennimmt und HTML zurückgibt. In einer Webanwendungen kann man so ein Preview des Dokumentes im Browser anzeigen - der Endanwender muss die Desktop-Applikation gar nicht starten.
The cool bit is now that this filter can be called separately and completely independent from an Oracle TEXT index. So we can write a simple PL/SQL function which takes a binary document (as BLOB) and returns the filtered result (as a CLOB). In a web application this could be used to display a preview of the document directly in the browser - the end user does not have to open the desktop application.
Um das folgende Skript starten zu können, benötigt Ihr die Rolle CTXAPP
.
To execute the following script you need the CTXAPP role.
begin
  ctx_ddl.drop_policy(
    policy_name => 'filter_policy'
  );
end;
/
sho err

begin
  ctx_ddl.create_policy(
    policy_name => 'filter_policy',
    filter      => 'CTXSYS.AUTO_FILTER'
  );
end;
/
sho err

create or replace function filter_document(
  p_document in blob
) return clob
is
  l_data clob;
begin
  dbms_lob.createtemporary(
    lob_loc => l_data, 
    cache   => true, 
    dur     => dbms_lob.call
  );
  ctx_doc.policy_filter(
    policy_name => 'filter_policy',
    document    => p_document, 
    restab      => l_data
  );
  return l_data;
end;
/
sho err
Diese Funktion dient eigentlich nur der Bequemlichkeit - sie legt nur einen temporären CLOB an und riuft danach CTX_DOC.POLICY_FILTER auf (diese tut die eigentliche Arbeit).
This function does not do too much - it's just for convenience: It first createas a temporary CLOB to hold the filter results and then calls the procedure CTX_DOC.POLICY_FILTER. This one does the actual work.
Für die Experten: Wenn man CTX_DOC.IFILTER genutzt hätte, könnte man das gleiche auch ohne das etwas umständliche Erzeugen einer Policy und damit auch ohne die Rolle CTXAPP erreichen. Allerdings rät die Dokumentation davon ab - wir halten uns also an den offiziell empfohlenen Weg.
One remark for the experts: If we would use CTX_DOC.IFILTER we were not required to create the Policy object. We then also would not need the CTXAPP role. So why are we doing those things? Because the documentation recommends it: Applications should use POLICY_FILTER instead of IFILTER - and we want to follow that rule.
Testen ist nun ganz einfach. Für diesen Test wird ein PDF-Dokument direkt aus dem Dateisystem geholt - dazu nutze ich meine API zum Zugriff auf das Dateisystem ...
Testing is now easy: For this simple test I grab the PDF document directly from the file system. I use my API for file system interaction for that ...
select filter_document(file_type.get_file('/pfad/zu/einem/PDF-Dokument.pdf').get_content_as_blob())
from dual
/

<HTML><BODY>
:
HTML ...
Der Filter ist übrigens nicht Teil des Datenbankkerns: es wird ein Callout auf ein Executable gemacht: Das Executable $ORACLE_HOME/ctx/bin/ctxhx macht die eigentliche Arbeit. Und man kann es auch direkt von der Kommandozeile ausführen ... Probiert es mal aus ...
BTW: The actual filter engine is not part of the database kernel - the database does a callout instead. The executable called is $ORACLE_HOME/ctx/bin/ctxhx - and you can also call it directly - just give it a try ...

Kommentare:

Jürgen H. Moch hat gesagt…

Die Konvertierung in HTML erscheint für PDFs recht dürftig und kann meiner Meinung nach nicht als wirkliche Vorschau eingesetzt werden. Ich habe ein mehrseitiges PDF (generiert aus Open Office) auf diese Weise konvertiert. Es sind viele Zeilen "verhüpft", auch mitten in einem einfachen Absatz ohne weitere Formatierungen.
Es sieht so aus, als wenn grundsätzlich alle Elemente über position:absolute
gesetzt werden. Wie man das beeinflussen/verbessern kann, habe ich nicht rausbekommen.

Carsten Czarski hat gesagt…

Hallo,

das geht gar nicht; der Filter lässt sich nicht konfigrieren. Die Umwandlungsfunktion ist ursprünglich für den Volltextindex gedacht; die Layoutdetails sind für diesen ja nicht wichtig. Diese Funktion nutzen wir hier einfach aus ... und es gibt natürlich Einschränkungen ...

Viele Grüße und ein gutes Neues Jahr 2009!

Beliebte Postings