- put all files in a collection
/db/apps/pre-render
- open
/db/apps/pre-render/pre-render.xq
in eXide - evaluate
- check
/db/apps/pre-render
for rendered news articles
Last active
June 19, 2023 14:53
-
-
Save line-o/d2682a42a3028d5b4125759a10603c5f to your computer and use it in GitHub Desktop.
Prerender HTML with eXist-db's templating library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<main class="news-list__latest"> | |
<ul> | |
<li data-template="templates:each" data-template-from="articles" data-template-to="article"> | |
<a data-template="pr:article-link"/> | |
</li> | |
</ul> | |
</main> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<main class="news-detail"> | |
<article data-template="pr:include-article" /> | |
<a href="latest-news-rendered.html">back to list</a> | |
</main> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<news> | |
<article id="a5" date="2022-12-13"> | |
<header>Latest news</header> | |
<p>Are so important...</p> | |
</article> | |
<article id="a4" date="2022-03-04"> | |
<header>Lorem of the Rings</header> | |
<p>Lorem ipsum dolor sit amet...</p> | |
</article> | |
<article id="a3" date="2022-02-22"> | |
<header>Latest news</header> | |
<p>Yada yada yada...</p> | |
</article> | |
<article id="a1" date="1970-01-01"> | |
<header>Oldest news</header> | |
<p>In a galaxy far far away ...</p> | |
</article> | |
</news> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title data-template="pr:title" /> | |
</head> | |
<body> | |
<main data-template="pr:include-page-type" /> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xquery version "3.1"; | |
declare namespace pr="http://line-o.de/ns/pre-render"; | |
import module namespace templates="http://exist-db.org/xquery/html-templating"; | |
import module namespace lib="http://exist-db.org/xquery/html-templating/lib"; | |
(: | |
: We have to provide a lookup function to templates:apply to help it | |
: find functions in the imported application modules. The templates | |
: module cannot see the application modules, but the inline function | |
: below does see them. | |
:) | |
declare variable $pr:lookup := function($functionName as xs:string, $arity as xs:int) { | |
function-lookup(xs:QName($functionName), $arity) | |
}; | |
declare variable $pr:templates := map { | |
"news": "news.html", | |
"latest-news": "latest-news.html" | |
}; | |
(: custom include function including the template set in the model :) | |
declare function pr:include-page-type ($node as node(), $model as map(*)) as node() { | |
let $template := $pr:templates($model?page-type) | |
return | |
if (empty($template)) | |
then error((), "No template found for " || $model?page-type, $model) | |
else lib:include($node, $model, $template) | |
}; | |
(: templating configuration :) | |
declare variable $pr:config := map { | |
$templates:CONFIG_APP_ROOT : "/db/apps/pre-render", | |
$templates:CONFIG_STOP_ON_ERROR : true(), | |
$templates:CONFIG_FILTER_ATTRIBUTES : false() | |
}; | |
(: base template for all pages :) | |
declare variable $pr:page-template := doc("page.html"); | |
(: our render function is only dependent on the model :) | |
declare function pr:render ($model as map(*)) { | |
templates:apply( | |
$pr:page-template, $pr:lookup, | |
$model, | |
$pr:config | |
) | |
}; | |
declare | |
%templates:wrap | |
function pr:title ($node as node(), $model as map(*)) as xs:string { | |
$model?title | |
}; | |
(:------ news specific --------:) | |
declare | |
%templates:replace | |
function pr:include-article ($node as node(), $model as map(*)) as node() { | |
$model?data | |
}; | |
declare | |
%templates:wrap | |
function pr:article-link ($node as node(), $model as map(*)) as node()* { | |
attribute href { | |
"news-" || $model?article/@id/string() || ".html" | |
}, | |
$model?article/header/text() | |
}; | |
declare function pr:render-article ($article as node()) as xs:string? { | |
let $news-model := map { | |
'page-type': 'news', | |
'data' : $article, | |
'title' : "NEWS - " || $article/header/string() | |
} | |
let $rendered := pr:render($news-model) | |
let $filename := 'news-' || $article/@id/string() || '.html' | |
return | |
xmldb:store('/db/apps/pre-render', $filename, $rendered) | |
}; | |
(:~ | |
: render all given article elements and store the rendered HTML | |
:) | |
declare function pr:render-article-detail($articles as element(article)*) as xs:string* { | |
for-each($articles, pr:render-article#1) | |
}; | |
declare function pr:sort-by-date ($article as element(article)) as xs:integer { | |
-xs:integer(replace($article/@date/string(), '-', '')) | |
}; | |
(:~ | |
: render all given article elements and store the rendered HTML | |
:) | |
declare function pr:render-latest-news($articles as element(article)*, $how-many as xs:integer) as xs:string* { | |
let $sorted := sort($articles, "?numeric=yes", pr:sort-by-date#1) | |
let $rendered := pr:render(map { | |
'page-type': 'latest-news', | |
'articles': $sorted[position() <= $how-many], | |
'title' : "BREAKING NEWS" | |
}) | |
return | |
xmldb:store('/db/apps/pre-render', 'latest-news-rendered.html', $rendered) | |
}; | |
(: load article data :) | |
let $articles := doc('news.xml')//article | |
(: render HTML and store it :) | |
return ( | |
pr:render-article-detail($articles), | |
pr:render-latest-news($articles, 3) | |
(: Exercise left to the user :) | |
(: pr:render-news-per-year($articles) :) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nice!