4.3.3.2  Implementierung als XQuery Skript

In diesem Abschnitt werden wir eine HTML Seite mit Inhaltsverzeichnis aus den zuvor geladenen Daten generieren.

Beginnen wir mit einem Skript book.xqy im Verzeichnis C:\xml-scrapper

xquery version "1.0-ml";

xdmp:set-response-content-type("text/html"),
let $pages :=
<html>
    <body>
        {
            for $chapter in collection("/chapter")/descendant::chapter
                return (
                    <h3>{ $chapter/title/text() }</h3>,
                    <p>{ $chapter/content/text() }</p> 
                )
        }
    </body>
</html>
return $pages
Plain Text
Ergebnis: Die Kapitel der Webseite werden hintereinander weggeschrieben. Das ist natürlich noch nicht optimal
figure: 13  Erste Ausgabe unseres kleinen XQuery Skripts für eine Website
Hier fällt auf, dass wir 2x ein Kapitel 2 eingebunden haben. Es handelt sich dabei um einen Tippfehler.
Wir kümmern uns um diesen Fehler später.

Nun wollen wir die einzelnen Seiten auf verschiedene Webseiten aufsplitten und auf einer Cover-Page ein Inhaltsverzeichnis darstellen.

xquery version "1.0-ml";

declare variable $page:= xdmp:get-request-field('page');

xdmp:set-response-content-type("text/html"),
let $page-id := if ($page) then $page else ('cover'),
$pages :=
<html>
    <body>
        {
            <h3>Welcome to The Book</h3>,
            for $chapter at $position in collection("/chapter")/descendant::chapter
                return (
                    if ($page-id = 'cover') then (
                        <p><a href="?page={$position}">{ $chapter/title/text() }</a></p>
                    ) else (
                        (: TODO :)
                    )
                )
        }
    </body>
</html>
return $pages
Plain Text

Im Vergleich zu einer XSLT Lösung stellt man fest, dass man vergeblich versucht die XPath Funktion fn:position() anzuwenden. Stattdessen verwendet man das Schlüsselwort at in der for Loop.

Auf der initialen Cover-Seite wird nun ein verlinktes Inhaltsverzeichnis angezeigt:

Der zweite Schritt unserer Webapplikation ist ein Inhaltsverzeichnis mit verlinkten Kapiteln
figure: 14  Zweite Ausgabe unseres kleinen XQuery Skripts für eine Website

Der im Skript deklarierte Request-Parameter $page wird nun ausgewertet, um die Kapitelseiten zu erzeugen.

xquery version "1.0-ml";

declare variable $page:= xdmp:get-request-field('page');

xdmp:set-response-content-type("text/html"),
let $page-id := xs:decimal(if ($page) then $page else '0'),
$pages := collection("/chapter"),
$website :=
<html>
    <body>
        {
            <h3>Welcome to The Book</h3>,
            for $chapter at $position in $pages/descendant::chapter
                return (
                    if ($page-id lt 1 or  $page-id gt count($pages)) then (
                        <p><a href="?page={$position}">{ $chapter/title/text() }</a></p>
                    ) else  if ($page-id = $position) then (
                        <h2>{ $chapter/title/text() }</h2>,
                        <p>{ $chapter/content/text() }</p>,
                        <p><a href="{ xdmp:get-request-path() }">Back To Cover</a></p>
                    ) else ()
                )
         }
    </body>
</html>
return $website
Plain Text

Hier ist das at Schlüsselwort interessant mit dem man die Position in der Schleife abgreifen kann. fn:position() wie bei XSLT gebräuchlich würde hier nicht funtktionieren. Dass wir bedingte Anweisungen in funktionalen Sprachen als Ausdruck auswerten können, haben wir in hier schon gelernt, vgl. die sx:decimal Cast Anweisung zur Typ-Konvertierung.

Unsere Website wäre eigentlich schon perfekt, wenn da der fehlerhafte Datenimport nicht wäre, und wir das Kapitel 2 nicht doppelt importiert hätten. Um die Daten zu bereinigen ist eine Daten-Migration notwendig.