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 $pagesPlain Text

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 $pagesPlain 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 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 $websitePlain 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.