PDFPreParser
Gruppe |
|
Funktion |
Preparser, der dazu dient einige wenige Angaben aus einem PDF-Dokument zu extrahieren. |
Konfigurationsdatei |
./conf/samples/PDFPreParser.xml |
Beschreibung
Obwohl das PDF-Format kein maschinell verarbeitbares Datenformat ist, gibt es einen Preparser, der dazu dient einige wenige Angaben aus einem PDF-Dokument zu extrahieren und so einem Profil z. B. zu ermöglichen, anhand einer Kundennummer das PDF-Dokument auf einen von mehreren Ausgangswegen zu schicken. Sein Einsatzzweck ist nicht, komplexe Daten aus PDF-Dokumenten zu lesen, wie dies bei anderen, für die maschinelle Verarbeitung gedachten, Datenformaten der Fall ist.
Zuerst werden aus dem PDF alle enthaltenen Texte extrahiert. Dabei gehen sämtliche Formatierungen und auch ein Großteil der Anordnung verloren. In dem entstandenen, einfachen Text wird dann anhand konfigurierter Regeln nach bestimmten Angaben gesucht, z. B. einer Kundennummer. An das Profil selbst wird in Form eines einfachen CSV-Textes eine Liste von Schlüssel-Wert-Paaren weitergegeben, also z. B.:
Profilename;PDFTestProfil
Kundenname;Maier
Kundennummer;4711
Auftragsnummer;12345
Die erste Zeile enthält auf jeden Fall immer den Namen des Profils mit dem Schlüssel Profilename. Alles weiteren Inhalte definieren Sie.
Das Profil kann nun z. B. mit diesen Beispiel-Daten in einem einfachen Mapping in der Datenbank vermerken, dass für den Kunden Maier mit Kundennummer 4711 der Auftrag mit der Nummer 12345 eingegangen ist und diesen dann (wie empfangen) per FTP an den betreffenden Kunden weiterleiten. Neben den aus dem PDF extrahierten Werten können auch Fixwerte angegeben werden, die dann direkt nach dem Profilnamen in die CSV-Ausgabe geschrieben werden.
Aufbau der Konfigurationsdatei
Vergleichen Sie hierzu das Beispiel am Ende der Seite.
Das Root-Element
Das Root-Element der Konfiguration muss den Namen PDFPreParser tragen. Darin enthalten ist pro Profil ein Abschnitt mit dem Elementnamen Profile.
Das Profile-Element
Pflicht ist dort ein Element Name, das diesen Abschnitt der Konfigurationsdatei einem bestimmten Profil zuordnet. Will ein Profil den PDFPreParser nutzen und findet keinen Abschnitt mit seinem Namen, schlägt der Profillauf fehl.
Desweiteren muss mit den Elementen LineFrom und LineTo der Zeilen-Bereich angegeben sein, in dem nach Werten gesucht werden soll. Also z. B. in den Zeilen 10 bis 20. Ob hierbei auch Leerzeilen mitgezählt werden sollen, können Sie mit dem Element IgnoreEmptyLines festlegen. Geben Sie diesem den Wert false, dann werden Leerzeilen mitgezählt ansonsten werden sie ignoriert.
Optional können Sie mit dem Element FixValue eine beliebige Anzahl feste Werte vorgeben und mittels Replace Zeichencodes für Ersetzungen einzelner Zeichen durch andere. Hierbei gibt man mit Old und New den Code des Zeichens (als Integer) an.
Welche Daten wie aus dem Text gelesen werden sollen, beschreiben schließlich die Tag-Elemente. Siehe hierzu die Beschreibung im folgenden Abschnitt.
Enthält das PDF Formulardaten, kann das Auslesen mittels WithFormData und dem Wert true aktiviert werden. Sollen ausschließlich Formulardaten ausgelesen werden, ist diese Einschränkung mit der zusätzlichen Einstellung OnlyFormData und dem Wert true zu erreichen.
Das Tag-Element
Zu jedem Datenfeld (wie z. B. der Kundennummer) werden ein oder mehrere Tag-Elemente angelegt. Eine Element Name darin gibt den Namen des Datenelements an, also eben z. B. Kundennummer. Sind mit dem selben Namen mehrere Tag-Elemente angegeben, gilt das als ODER-Angabe, die Kundennummer kann somit auf verschiedene Arten gefunden werden bzw., wenn beide Konfigurationen etwas finden, kann die Kundennummer auch zwei mal im Ergebnis vorkommen. Bei einer Kundennummer mag das sinnlos sein, aber in einem Auftrag können ja beispielsweise mehrere Artikelnummern vorkommen, die dann auch alle gelistet werden sollen. Wie die Daten aus dem Text extrahiert werden sollen, wird mit folgenden Angaben geregelt:
LineNumber |
Werte nur Zeile mit angegebener Nummer aus (ist die originale Zeilennummer aus dem Text). Das greift auch in Kombination mit allen anderen Möglichkeiten. Zeilen, die nicht diese Nummer haben, werden ignoriert, auch wenn was anderes passen würde. Nur die LineNumber gibt einfach die ganze Zeile zurück. |
LinesAfter |
Werte genau die angegebene Anzahl an Zeilen nach der Zeile aus, in der ein anderes Tag gefunden wurde. Alle anderen Zeilen werden ignoriert. Kombinierbar mit allem anderen. Beispiel: <LinesAfter Tag="Kunde">2</LinesAfter> wertet die zweite Zeile nach der aus, in der das Tag Kunde gefunden wurde. |
BeginsAfter |
Nimmt Text nach diesem String. Kombinierbar mit: EndsBefore, Characters, Words. |
EndsBefore |
Nimmt Text vor diesem String. Kombinierbar mit: BeginsAfter, Characters, Words. |
FirstWord |
Nimmt die Worte (getrennt durch Blank) ab hier (Offset: 1). Kombinierbar mit: LastWord oder Words (LastWord schlägt Words). |
LastWord |
Nimmt die Worte (getrennt durch Blank) bis hier (Offset: 1). Kombinierbar mit: FirstWord oder Words (FirstWord schlägt Words). |
Words |
In Kombination mit einem der obigen. Liefert die angegebene Zahl Worte (Blank-getrennt) zurück. Attribut Direction: Die ersten (default) oder letzten (Wert = last) Worte. |
Characters |
Kombinierbar mit LineNumber, BeginsAfter, EndsBefore und Words. Nicht kombinierbar mit: FirstWord und LastWord. Liefert die angegebene Anzahl Zeichen zurück. Schlägt Words, also erst werden die Characters ausgeschnitten, davon dann die Words gezählt. Attribut Direction: Die ersten (Default) oder letzten (Wert = last) Zeichen. |
Trim |
Normalerweise wird der gefundene Wert "getrimmt" (d. h. Leerzeichen vorne und hinten werden weggeschnitten). Dies kann man mit dem Element Trim und dem Wert false verhindern. |
IgnoreCase |
Bei true wird die Groß- und Kleinschreibung nicht berücksichtigt. |
Erstellung der Konfigurationsdatei
Um zu sehen, was der Preparser für einen Text aus dem PDF extrahiert, auf den er dann die Regeln in der Konfigurationsdatei anwendet, können Sie in Ihrem Profil einen Test laufen lassen und sich das Log ansehen, wobei Sie hierfür natürlich schon eine rudimentäre Konfigurationsdatei benötigen. So haben Sie auch eine Möglichkeit die Konfigurationsdatei entsprechend Schritt für Schritt zu erweitern.
Nun bauen Sie Ihre Konfiguration auf, indem Sie erst mal das Grundgerüst erstellen. Benutzen Sie einen ganz normalen Editor und achten Sie bitte darauf, die Datei in dem Encoding zu speichern, das Sie angeben, in diesem Beispiel UTF-8 (bitte immer ohne BOM).
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
PDFPreParser
>
<
Profile
>
<
Name
>Ihr_Profilname</
Name
>
<
LineFrom
>1</
LineFrom
>
<
LineTo
>4</
LineTo
>
</
Profile
>
</
PDFPreParser
>
Hier würden wir die ersten 4 Zeilen (Leerzeilen ausgenommen) beachten. Der Rest wird ignoriert.
Wichtig ist nun noch, dass Sie im Tag <Name> den Namen Ihres Test-Profils eintragen und innerhalb des Profile-Elements ein Tag-Elemente angeben, dann können Sie ausgehend von dieser Konfigurationsdatei schrittweise Ihre komplette Konfigurationsdatei aufbauen.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
PDFPreParser
>
<
Profile
>
<
Name
>Ihr_Profilname</
Name
>
<
LineFrom
>1</
LineFrom
>
<
LineTo
>4</
LineTo
>
<
Tag
>
<
Name
>Testelement</
Name
>
<
LineNumber
>1</
LineNumber
>
</
Tag
>
</
Profile
>
</
PDFPreParser
>
Für PDFs unterschiedlichen Formats, die sich nicht mit ein und derselben Konfiguration parsen lassen, müssen mehrere Profile mit jeweils passenden Konfigurationen erstellt werden.
Beispiel-Datei
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
PDFPreParser
>
<
Profile
>
<
Name
>Ihr_Profilname</
Name
>
<
LineFrom
>1</
LineFrom
>
<
LineTo
>4</
LineTo
>
<
FixValue
Name
=
"Fix1"
>1</
FixValue
>
<
FixValue
Name
=
"Fix2"
>2</
FixValue
>
<
FixValue
Name
=
"Fix3"
>3</
FixValue
>
<!-- Nimm aus Zeile zwei alles bis zum zweiten Wort-->
<
Tag
>
<
Name
>Kundenname</
Name
>
<
LastWord
>2</
LastWord
>
<
LineNumber
>2</
LineNumber
>
</
Tag
>
<!-- Das wuerde alle l zu f und alle r zu e ersetzen
<
Replace
>
<
Old
>108</
Old
>
<
New
>102</
New
>
</
Replace
>
<
Replace
>
<
Old
>114</
Old
>
<
New
>101</
New
>
</
Replace
>
-->
<!--Variante 1: Nimm nach dem Text KdNr das letzte Wort
<
Tag
>
<
Name
>Kundennummer</
Name
>
<
BeginsAfter
>KdNr</
BeginsAfter
>
<
Words
Direction
=
"last"
>1</
Words
>
</
Tag
>
-->
<!--Variante 2: Nimm nach dem Text KdNr die letzten vier Zeichen und trimme
<
Tag
>
<
Name
>Kundennummer</
Name
>
<
BeginsAfter
>KdNr</
BeginsAfter
>
<
Trim
>true</
Trim
>
<
Characters
Direction
=
"last"
>4</
Characters
>
</
Tag
>
-->
<!--Hole das erste Wort aus Zeile 3
<
Tag
>
<
Name
>Strasse</
Name
>
<
LineNumber
>3</
LineNumber
>
<
Words
>1</
Words
>
</
Tag
>
-->
<!--Hole das letzte Wort aus Zeile 3
<
Tag
>
<
Name
>HausNr</
Name
>
<
LineNumber
>3</
LineNumber
>
<
Words
Direction
=
"last"
>1</
Words
>
</
Tag
>
-->
<!--Das letzte Wort, das zwischen Ort: und Tel: steht
<
Tag
>
<
Name
>Ort</
Name
>
<
BeginsAfter
>Ort:</
BeginsAfter
>
<
EndsBefore
>Tel:</
EndsBefore
>
<
Words
Direction
=
"last"
>1</
Words
>
</
Tag
>
-->
<!--Das erste Wort der ersten 10 Zeichen, die zwischen Ort: und Tel: stehen-->
<!--noch mal zur Erinnerung: Characters wird immer VOR Words ausgefuehrt!!
<
Tag
>
<
Name
>PLZ</
Name
>
<
BeginsAfter
>Ort:</
BeginsAfter
>
<
EndsBefore
>Tel:</
EndsBefore
>
<
Characters
>10</
Characters
>
<
Words
>1</
Words
>
</
Tag
>
-->
<!--Die 5. Zeile nach der Kundennummer enthaelt zusaetzliche Infos, aber nur in den ersten 10 Worten
<
Tag
>
<
Name
>AddInfo</
Name
>
<
LinesAfter
Tag
=
"KDNR"
>5</
LinesAfter
>
<
Words
>10</
Words
>
</
Tag
>
-->
</
Profile
>
</
PDFPreParser
>