Kapitel 7. Unicode

Unicode in PDF

Funktionieren die bisher beschriebenen Tests auch mit Inhalten, die nicht ISO-8859-1 sind, beispielsweise mit russischen, griechischen oder chinesischen Texten und Metadaten?

Eine schwierige Frage. Denn auch wenn bei der Entwicklung von PDFUnit viel Wert darauf gelegt wurde, generell mit Unicode zu funktionieren, kann eine pauschale Antwort nur gegeben werden, wenn die eigenen Tests für PDFUnit selber mit allen Möglichkeiten durchgetestet wurde. PDFUnit hat zwar etliche Tests für griechische, russische und chinesische Dokumente, aber es fehlen noch Tests mit hebräischen und japanischen PDF-Dokumenten. Insofern kann die eingangs gestellte Frage nicht abschließend beantwortet werden.

Prinzipiell tun Sie gut daran, sämtliche Werkzeuge auf UTF-8 zu konfigurieren, wenn Sie Unicode-Daten verarbeiten müssen.

Die folgenden Tipps im Umgang mit UTF-8 Dateien lösen nicht nur Probleme im Zusammenhang mit PDFUnit. Sie sind sicher auch in anderen Situationen hilfreich.

Einzelne Unicode-Zeichen

Metadaten und Schlüsselwörter können Unicode-Zeichen enthalten. Wenn Ihre Entwicklungsumgebung die fremden Fonts nicht unterstützt, können Sie ein Unicode-Zeichen mit \uXXXX schreiben, wie hier das Copyright-Zeichen © als \u00A9:

<testcase name="hasProducer_CopyrightAsUnicode">
  <assertThat testDocument="unicode/unicode_producer.pdf">
    <hasProducer>
                              <!-- 'copyright' -->
      <matchingComplete>txt2pdf v7.3 \u00A9 SANFACE Software 2004</matchingComplete>
    </hasProducer>
  </assertThat>
</testcase>

Längere Unicode-Texte

Es wäre nun zu mühsam, für längere Texte den Hex-Code aller Buchstaben herauszufinden. Deshalb stellt PDFUnit das kleine Programm ConvertUnicodeToHex zur Verfügung. Übergeben Sie den ausländischen Text als String an das Werkzeug, entnehmen Sie der daraus erzeugten Datei anschließend den Hex-Code und fügen ihn in Ihr Testprogramm ein. Eine genaue Beschreibung steht in Kapitel 9.12: „Unicode-Texte in Hex-Code umwandeln“. Das Test mit Unicode sieht dann so aus:

<testcase name="hasSubject_Greek">
  <assertThat testDocument="unicode/unicode_subject.pdf">
    <hasSubject>
      <matchingComplete>
        Εργαστήριο Μηχανικής ΙΙ ΤΕΙ ΠΕΙΡΑΙΑ / Μηχανολόγοι       1
      </matchingComplete>
    </hasSubject>
  </assertThat>
</testcase>

1

Wenn Sie an dieser Stelle keinen griechischen Text sehen, liegt das daran, dass das darstellende System (PDF, eBook oder HTML) die Schriftart nicht unterstützt.

PDF mit Unicode gegen XML-Dateien vergleichen

XML- und XPath-basierte Tests funktionieren auch mit Dateien, die Unicode enthalten, wie z.B. die nach XML extrahierten Bookmarks im folgenden Beispiel:

<!-- 
  This test needs the following setting before starting ANT:
  set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8                 1
-->

<testcase name="hasBookmarks_MatchingXML">
  <assertThat testDocument="unicode/unicode_bookmarks.pdf">
    <hasBookmarks>
      <matchingXML file="unicode/unicode_bookmarks.xml" />   2
    </hasBookmarks>
  </assertThat>
</testcase>

1

Die Codepage kann über die Umgebungsvariable file.encoding gesetzt werden.

2

Die Bookmarks wurden mit dem Hilfsprogramm ExtractBookmarks nach XML exportiert.

Unicode in XPath-Ausdrücken

In Kapitel 8: „XPath-Einsatz“ wird beschrieben, wie PDFUnit-Tests zusammen mit XPath funktionieren. Auch die XPath-Ausdrücke können Unicode enthalten:

<testcase name="hasBookmarks_MatchingXPath">
  <assertThat testDocument="unicode/unicode_bookmarks.pdf">
    <hasBookmarks>
      <!-- The line is wrapped for printing: -->
      <matchingXPath expr="//Title[@Action][.='\u00D1\u00EE\u00E4
                                               \u00E5p\u00E6\u00E0
                                               \u00ED\u00E8\u00E5']" />
    </hasBookmarks>
  </assertThat>
</testcase>

UTF-8 File-Encoding für Shell-Skripte

Jedes Java-Programm, das Dateien verarbeitet, also auch PDFUnit, ist von der Umgebungsvariablen file.encoding abhängig. Es gibt mehrere Möglichkeiten, diese Umgebungsvariable für den jeweiligen Java-Prozess zu setzen:

set _JAVA_OPTIONS=-Dfile.encoding=UTF8
set _JAVA_OPTIONS=-Dfile.encoding=UTF-8

java -Dfile.encoding=UTF8
java -Dfile.encoding=UTF-8

UTF-8 File-Encoding für ANT

Während der Entwicklung von PDFUnit gab es zwei Tests, die unter Eclipse fehlerfrei liefen, unter ANT aber mit einem Encoding-Fehler abbrachen. Die Ursache lag in der Java-System-Property file.encoding, die in der DOS-Box nicht auf UTF-8 stand.

Der folgende Befehl löste das Encoding-Problem unter ANT nicht:

// does not work for ANT:

ant -Dfile.encoding=UTF-8

Statt dessen wurde die Property so gesetzt, wie im vorhergehenden Abschnitt für Shell-Skripte beschrieben:

// Used when developing PDFUnit:

set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8

Eclipse auf UTF-8 einstellen

Wenn Sie XML-Dateien in Eclipse erstellen, ist es nicht unbedingt nötig, Eclipse auf UTF-8 einzurichten, denn XML-Dateien sind auf UTF-8 voreingestellt. Für andere Dateitypen ist aber die Codepage des Betriebssystems voreingestellt. Sie sollten daher, wenn Sie mit Unicode-Daten arbeiten, das Default-Encoding für den gesamten Workspace auf UTF-8 einstellen:

Abweichend von dieser Standardeinstellung können einzelne Dateien in einem anderen Encoding gepeichert werden.

Fehlermeldungen und Unicode

Wenn Tests fehlschlagen, die auf Unicode-Inhalte testen, kann es sein, dass Eclipse oder ein Browser die Fehlermeldung nicht ordentlich dargestellen. Ausschlaggebend dafür ist das File-Encoding der Ausgabe, das von PDFUnit selber nicht beeinflusst werden kann. Wenn Sie in ANT dafür gesorgt haben, dass UTF-8 als Codepage verwendet wird, sind die meisten Probleme beseitigt. Danach können noch Zeichen aus der Codepage UTF-16 die Darstellung der Fehlermeldung korrumpieren.

Das PDF-Dokument im nächsten Beispiel enthält einen Layer-Namen, der UTF-16BE-Zeichen enthält. Um die Wirkung der Unicode-Zeichen in der Fehlermeldung zu zeigen, wurde der erwartet Layername bewusst falsch gewählt:

<!--
  The name of the layers consists of UTF-16BE and contains the 
  byte order mark (BOM). The error message is not complete. 
  It was corrupted by the internal Null-bytes.

  Adobe Reader® shows: "Ebene 1(4)"
  The used String is_: "Ebene _XXX"
-->

<testcase name="hasLayer_NameContainingUnicode_UTF16_ErrorIntended"
          errorExpected="YES"
>
  <assertThat testDocument="unicode/unicode_layerName.pdf">
    <hasLayer>
      <withName>
        <matchingComplete>
          \u00fe\u00ff\u0000E\u0000b\u0000e\u0000n\u0000e\u0000 \u0000_XXX
        </matchingComplete>
      </withName>
    </hasLayer>
  </assertThat>
</testcase>

Wenn die Tests mit ANT ausgeführt wurden, zeigt ein Browser die von PDFUnit erzeugte Fehlermeldung fehlerfrei an, einschließlich der Zeichenkette þÿEbene _XXX am Ende:

Unicode für unsichtbare Zeichen - &nbsp;

Im praktischen Betrieb trat einmal ein Problem auf, bei dem ein non-breaking space in den Testdaten enthalten war, das zunächst als normales Leerzeichen wahrgenommen wurde. Der String-Vergleich lieferte aber einen Fehler, der erst durch die Verwendung von Unicode beseitigt werden konnte:

<!--
  The content of the node value terminates with the 
  Unicode value 'non-breaking space'.
-->

<testcase name="nodeValueWithUnicodeValue">
  <assertThat testDocument="xfa/xfaBasicToggle.pdf">
    <hasXFAData>
      <!-- The line is wrapped for printing: -->
      <withNode tag="default:p[7]" 
                value="The code for creating the toggle behavior involves  
                       switching the border between raised and lowered, 
                       and maintaining the button's\u00A0"
                defaultNamespace="http://www.w3.org/1999/xhtml"
      />
    </hasXFAData>
  </assertThat>
</testcase>