3.17. Lesezeichen (Bookmarks) und Sprungziele

Überblick

Lesezeichen (Bookmarks) dienen der schnellen Navigation innerhalb eines PDF-Dokumentes oder auch nach außen. Der Gebrauchswert eines Buches sinkt erheblich, wenn die einzelnen Kapitel nicht über das Inhaltsverzeichnis erreichbar sind. Mit den folgenden Tests sollen eventuelle Probleme frühzeitig erkannt werden:

<!-- Tags for tests on bookmarks: -->

<hasNumberOfBookmarks />
<hasBookmarks />
  
<hasBookmark withLabel=".."        (One of these attributes ...
             withLinkToName=".."   ...
             withLinkToPage=".."   ...
             withLinkToURI=".."    ...
             withoutDeadLink=".."  ... has to be used)
/>

<hasBookmark withLabel=".."        (Only these two attributes ...
             linkingToPage=".."     ... can be used together.)    
/>

<!-- Nested tags of <hasBookmarks />: -->
<hasBookmarks>
  <matchingXPath />   (optional)
  <matchingXML   />   (optional)
<hasBookmarks />

Betrachtet man Lesezeichen als Absprungmarken, dann sind Named Destinations die Sprungziele. Sprungziele können von Lesezeichen genutzt werden, dienen aber auch als Ziel für HTML-Links. So kann aus einer Webseite direkt an eine bestimmte Stelle innerhalb eines PDF-Dokumentes gesprungen werden.

Für Sprungziele (Named Destinations) gibt es diese Tags:

<!-- Tags to check named destinations: -->

<hasNamedDestination />

<!-- Nested tags: -->
<hasNamedDestination>
  <withName />          (optional)
</hasNamedDestination>

Sprunziele, Named Destinations

Namen von Sprungzielen können einfach getestet werden:

<testcase name="hasNamedDestination_WithName">
  <assertThat testDocument="namedDestination/manyNamedDestinations.pdf">
    <hasNamedDestination>
      <withName>Seventies</withName>
      <withName>Eighties</withName>
      <withName>1999</withName>
      <withName>2000</withName>
    </hasNamedDestination>
  </assertThat>
</testcase>

Da die Namen auch über externe Links funktionieren müssen, dürfen sie keine Leerzeichen enthalten. Wird beispielsweise innerhalb von LibreOffice eine Sprungmarke mit Leerzeichen "Export to PDF" erstellt, erzeugt LibreOffice daraus beim Export nach PDF die Sprungmarke "First2520Bookmark". Der Test muss dann diese Zeichenkette benutzen:

<!-- 
  The convertion of the bookmarks by LibreOffice converts every 
  space in a bookmark label into "2520" in the named destination".
-->
<testcase name="hasNamedDestination_CreatedWithLibreOffice">
  <assertThat testDocument="namedDestination/problem_convert-bookmarks-to-pdf.pdf">
    <hasNamedDestination>
      <withName>First2520Bookmark</withName> 1
    </hasNamedDestination>
  </assertThat>
</testcase>

1

"2520" steht für "%20", das wiederrum einem Leerzeichen entspricht.

Existenz von Lesezeichen (Bookmarks)

Am einfachsten kann die Existenz von Lesezeichen überprüft werden:

<testcase name="hasBookmarks">
  <assertThat testDocument="bookmarks/diverseContentOnMultiplePages.pdf">
    <hasBookmarks /> 
  </assertThat>
</testcase>

Anzahl

Nach dem Test, ob ein PDF-Dokument überhaupt Lesezeichen hat, ist die Anzahl der Lesezeichen prüfenswert:

<testcase name="hasNumberOfBookmarks">
  <assertThat testDocument="bookmarks/manyBookmarks.pdf">
    <hasNumberOfBookmarks>19</hasNumberOfBookmarks>
  </assertThat>
</testcase>

Text eines Lesezeichens (Label)

Eine wichtige Eigenschaft eines Lesezeichens ist das, was der Leser sieht: das Label. Deshalb sollten Sie testen, ob ein bestimmtes Lesezeichen genauso heißt, wie Sie es erwarten:

<testcase name="hasBookmark_withLabel">
  <assertThat testDocument="bookmarks/diverseContentOnMultiplePages.pdf">
    <hasBookmark withLabel="Content on page 3." /> 
  </assertThat>
</testcase>

Sprungziele von Lesezeichen

Lesezeichen können sehr unterschiedliche Sprungziele haben. Für jedes Sprungziel gibt es deshalb ein geeignetes Attribut innerhalb des Tags <hasBookmark />.

Zielt ein bestimmtes Lesezeichen auf die gewünschte Seitenzahl:

<testcase name="hasBookmark_WithLabelLinkingToPage">
  <assertThat testDocument="bookmarks/diverseContentOnMultiplePages.pdf">
    <hasBookmark withLabel="Content on first page." linkingToPage="1"/>
  </assertThat>
</testcase>

Das Attribut linkingToPage=".." kann nur zusammen mit dem Attribut withLabel=".." genutzt werden. In einem solchen Test muss dieses Label zu der erwarteten Seitenzahl verweisen.

Gibt es irgendein Lesezeichen zu einer gewünschten Seitenzahl:

<testcase name="hasBookmark_WithLinkToPage">
  <assertThat testDocument="bookmarks/diverseContentOnMultiplePages.pdf">
    <hasBookmark withLinkToPage="1" />
  </assertThat>
</testcase>

Gibt es ein Lesezeichen, das zu einer bestimmten Sprungmarke zeigt:

  
<testcase name="hasBookmark_WithLinkToName">
    <assertThat testDocument="bookmarks/twoBookmarkToSameDestination.pdf">
      <hasBookmark withLinkToName="Destination on Page 1" />
    </assertThat>
  </testcase>

Gibt es ein Lesezeichen, dessen Sprungziel eine bestimmte URI ist:

<testcase name="hasBookmark_WithLinkToURI">
  <assertThat testDocument="bookmarks/bookmarkWithURLAction.pdf">
    <hasBookmark withLinkToURI="http://www.wikipedia.org/" />
  </assertThat>
</testcase>

Und als Letztes soll überprüft werden, dass es kein Lesezeichen mit einem toten Link gibt:

<!--
  Looking for dead internal links (GOTO) of any bookmark.
  A 'dead link' means that a bookmark is not pointing to a page.
-->
<testcase name="hasBookmark_WithoutDeadLink">
  <assertThat testDocument="bookmarks/diverseContentOnMultiplePages.pdf">
    <hasBookmark withoutDeadLink="YES" />
  </assertThat>
</testcase>

PDFUnit greift während der Tests nicht auf Webseiten zu. Insofern ist ein toter Link ein Lesezeichen, das auf keine Seite oder kein Sprungziel verweist.

Lesezeichen mit XML/XPath testen

Die nachfolgenden Tests basieren auf einer XML-Struktur, die mit dem Hilfsprogramm ExtractBookmarks erzeugt werden kann.

Das aktuelle Test-PDF-Dokument kann vollständig mit der exportierten XML-Datei verglichen werden:

<!-- 
  When comparing PDF parts against any XML, 
  whitespaces and comments are ignored. 
-->
<testcase name="hasBookmarks_MatchingXML_AsFileName">
  <assertThat testDocument="bookmarks/bookmarksWithPdfOutline.pdf">
    <hasBookmarks>
      <matchingXML file="bookmarks/bookmarksWithPdfOutline.xml"/> 1
    </hasBookmarks>
  </assertThat>
</testcase>

1

Beim Vergleich von PDF-Informationen mit XML spielen Leerzeichen/Whitespaces und XML-Kommentare keine Rolle.

Bookmark-Informationen des aktuellen Test-PDF-Dokumentes können mit individuellen XPath-Ausdrücken evaluiert werden:

<testcase name="hasBookmarks_MatchingXPath_MultipleInvocation_version1">
  <assertThat testDocument="bookmarks/bookmarksWithPdfOutline.pdf">
    <hasBookmarks>
      <matchingXPath expr="count(//Title) = 5" />
      <matchingXPath expr="count(//Title[count(ancestor::*) > 2] ) = 0" />
    </hasBookmarks>
  </assertThat>
</testcase>