Commit b0d82b62 authored by Mathias Goebel's avatar Mathias Goebel 🎠
Browse files

ALL NEW SADE

parent bd2a9fbb
<?xml version="1.0" encoding="UTF-8"?>
<collection xmlns="http://exist-db.org/collection-config/1.0">
<index xmlns:xs="http://www.w3.org/2001/XMLSchema">
<fulltext default="none" attributes="false"/>
</index>
<triggers>
<trigger class="org.exist.extensions.exquery.restxq.impl.RestXqTrigger"/>
</triggers>
</collection>
\ No newline at end of file
xquery version "3.1";
import module namespace console="http://exist-db.org/xquery/console" at "java:org.exist.console.xquery.ConsoleModule";
import module namespace config="http://textgrid.de/ns/SADE/config" at "modules/config/config.xqm";
declare variable $exist:path external;
declare variable $exist:resource external;
declare variable $exist:controller external;
declare variable $exist:prefix external;
declare variable $exist:root external;
let $project := tokenize( $exist:path, "/" )[. != ""][not(ends-with(., "html"))][1]
let $project := config:list-projects()[1]
let $test := console:log("@@@@@@@ NEW REQUEST @@@@@@")
let $test := console:log($exist:path)
let $test := console:log($exist:resource)
let $test := console:log($exist:controller)
return
if ($exist:path eq '') then
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="{request:get-uri()}/"/>
</dispatch>
else if ($project = ()) then
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="{config:list-projects()[1]}/{request:get-uri()}/"/>
</dispatch>
else if ($exist:path eq "/") then
(: forward root path to index.xql :)
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="index.html"/>
</dispatch>
else if (ends-with($exist:resource, ".html")) then
let $doc-path := $config:projects-dir || $project || config:get("template") || $exist:resource
return
(: the html page is run through view.xql to expand templates :)
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<!--view-->
<forward url="{$exist:controller}/modules/view.xql" method="get">
<add-parameter name="doc-path" value="{$doc-path}"/>
</forward>
<!--/view-->
<error-handler>
<forward url="{$exist:controller}/error-page.html" method="get"/>
<forward url="{$exist:controller}/modules/view.xql"/>
</error-handler>
</dispatch>
(: Resource paths starting with $shared are loaded from the shared-resources app :)
else if (contains($exist:path, "/$shared/")) then
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<forward url="/shared-resources/{substring-after($exist:path, '/$shared/')}">
<set-header name="Cache-Control" value="max-age=3600, must-revalidate"/>
</forward>
</dispatch>
else
(: everything else is passed through :)
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<cache-control cache="yes"/>
<forward url="../../../../sade-projects/{$project}/templates/tmpl1/{substring-after($exist:path, $project)}">
<set-header name="Cache-Control" value="max-age=3600, must-revalidate"/>
</forward>
</dispatch>
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://expath.org/ns/pkg" name="http://textgrid.de/ns/SADE" abbrev="SADE" version="1" spec="1.0">
<title>Scalable Architecture for Digital Editions powered by TextGrid</title>
<dependency package="http://exist-db.org/apps/markdown"/>
<dependency package="http://exist-db.org/apps/monex"/>
</package>
icon.png

22.8 KB

xquery version "3.1";
module namespace app="http://textgrid.de/ns/SADE/templates";
import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://textgrid.de/ns/SADE/config" at "config/config.xqm";
(:~
: Collects information from <a href="https://www.uni-goettingen.de/de/publikationen/303721.html">
: Fontane-Arbeitstelle website</a>.
:
: @param $node the HTML node with the attribute which triggered this call
: @param $model a map containing arbitrary data - used to pass information between template calls
:)
declare function app:publications($node as node(), $model as map(*)) {
httpclient:get(xs:anyURI('https://www.uni-goettingen.de/de/publikationen/303721.html'), true(), ())//ul[@class="txtlist"][1]/li[position() < 4]
};
(:~
: Collects information from <a href="https://www.uni-goettingen.de/de/publikationen/303721.html">
: Fontane-Arbeitstelle website</a>.
:
: @param $node the HTML node with the attribute which triggered this call
: @param $model a map containing arbitrary data - used to pass information between template calls
:)
declare function app:presentations($node as node(), $model as map(*)) {
for $item in httpclient:get(xs:anyURI('https://www.uni-goettingen.de/de/vortr%C3%A4ge-und-pr%C3%A4sentationen/303717.html'), true(), ())//ul[@class="txtlist"][1]/li[position() < 5]
return
element li { for $i in $item/node() return local:nodeTest($i) }
};
declare function local:nodeTest($node){
typeswitch ($node)
case element(a) return element a {
attribute href {if(starts-with($node/@href, '/de/document')) then 'https://www.uni-goettingen.de'||$node/@href else $node/@href},
attribute target {'_blank'},
if (starts-with($node/text(), 'Power Point' )) then substring-after($node/text(), 'Power Point') else $node/text()
}
default return $node
};
\ No newline at end of file
xquery version "3.1";
module namespace config="http://exist-db.org/xquery/apps/config-params";
(:~
config.template.xql file is copied (manually or during build) to config.xql and optionally adapted
config.xql is part of the app - imported by config.xqm
:)
(: the simple variant, however with projects-collection inside /db/apps
declare variable $config:projects-dir := "/db/apps/sade-projects/";
declare variable $config:projects-baseuri:= "/sade-projects/";
:)
(: this variant allows the projects-folder outside /db/apps
(mark the trick with parent folder for the baseuri - this is necessary to fool the controller ):
:)
declare variable $config:projects-dir := "/db/sade-projects/";
declare variable $config:projects-baseuri:= "/SADE/../../sade-projects/";
xquery version "3.1";
(:~
: A set of helper functions to access the application context from
: within a module.
:)
module namespace config="http://textgrid.de/ns/SADE/config";
import module namespace console="http://exist-db.org/xquery/console" at "java:org.exist.console.xquery.ConsoleModule";
import module namespace config-params="http://exist-db.org/xquery/apps/config-params" at "config.xql";
declare namespace templates="http://exist-db.org/xquery/templates";
declare namespace repo="http://exist-db.org/xquery/repo";
declare namespace expkg="http://expath.org/ns/pkg";
(:
Determine the application root collection from the current module load path.
:)
declare variable $config:app-root :=
let $rawPath := system:get-module-load-path()
let $modulePath :=
(: strip the xmldb: part :)
if (starts-with($rawPath, "xmldb:exist://")) then
if (starts-with($rawPath, "xmldb:exist://embedded-eXist-server")) then
substring($rawPath, 36)
else
substring($rawPath, 15)
else
$rawPath
return
substring-before($modulePath, "/modules")
;
declare variable $config:data-root := $config:app-root || "/data";
declare variable $config:repo-descriptor := doc(concat($config:app-root, "/repo.xml"))/repo:meta;
declare variable $config:expath-descriptor := doc(concat($config:app-root, "/expath-pkg.xml"))/expkg:package;
declare variable $config:projects-dir := $config-params:projects-dir;
(:~
: Resolve the given path using the current application context.
: If the app resides in the file system,
:)
declare function config:resolve($relPath as xs:string) {
if (starts-with($config:app-root, "/db")) then
doc(concat($config:app-root, "/", $relPath))
else
doc(concat("file://", $config:app-root, "/", $relPath))
};
(:~
: Returns the repo.xml descriptor for the current application.
:)
declare function config:repo-descriptor() as element(repo:meta) {
$config:repo-descriptor
};
(:~
: Returns the expath-pkg.xml descriptor for the current application.
:)
declare function config:expath-descriptor() as element(expkg:package) {
$config:expath-descriptor
};
declare %templates:wrap function config:app-title($node as node(), $model as map(*)) as text() {
$config:expath-descriptor/expkg:title/text()
};
declare function config:app-meta($node as node(), $model as map(*)) as element()* {
<meta xmlns="http://www.w3.org/1999/xhtml" name="description" content="{$config:repo-descriptor/repo:description/text()}"/>,
for $author in $config:repo-descriptor/repo:author
return
<meta xmlns="http://www.w3.org/1999/xhtml" name="creator" content="{$author/text()}"/>
};
declare variable $config:project :=
let $value:= try { request:get-url() => substring-after("SADE/") => substring-before("/") } catch * { "textgrid" }
return if($value="") then "textgrid" else $value;
declare variable $config:configDoc := doc( $config-params:projects-dir || $config:project || "/config.xml" );
declare variable $config:configMap := map:new(
for $param in $config:configDoc/config/*[@key]
return map:entry(string($param/@key), string($param))
);
declare function config:get($key as xs:string) as xs:string {
let $return :=
switch ($key)
case "data-dir" return $config-params:projects-dir || $config:project || "/" || $config:configMap($key)
case "project-dir" return $config-params:projects-dir || $config:project
default return $config:configMap($key)
return
if(string($return) != "")
then $return
else
let $doc := doc( $config-params:projects-dir || $config:project || "/config.xml" )
let $map := map:new(for $param in $doc/config/*[@key] return map:entry(string($param/@key), string($param)))
return
switch ($key)
case "data-dir" return $config-params:projects-dir || $config:project || "/" || $map($key)
case "project-dir" return $config-params:projects-dir || $config:project
default return $map($key)
};
declare function config:keys() {
map:keys($config:configMap)
};
declare function config:module-get($module-name as xs:string, $key as xs:string) as item()? {
let $module := $config:configDoc//module[string(@key)=$module-name]
return
$module/param[ string(@key)=$key ]/node()
};
declare function config:module-get($module-name as xs:string, $key as xs:string, $default as item()?) as item()? {
let $value := config:module-get($module-name , $key)
return if (empty($value)) then
$default
else
$value
};
(:~ checks if there is a config-file for given project
@author SADE-Team
@param $project project identifier
:)
declare function config:project-exists($projectname as xs:string) as xs:boolean {
let $project-config-path := $config-params:projects-dir || $project || "/config.xml"
return doc-available($project-config-path)
};
(:~ lists all existing modules (i.e. present in the modules-collection) :)
declare function config:list-modules() {
let $modules-dir := //expkg:package[@abbrev="SADE"]/base-uri() => replace("expath\-pkg\.xml", "modules/")
return
xmldb:get-child-collections($modules-dir)
};
(:~ lists all existing modules (i.e. present in the modules-collection) :)
declare function config:list-projects() as xs:string+ {
xmldb:get-child-collections($config-params:projects-dir)
};
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<config type="module">
<module key="faceted-search">
<param key="kwic-hits">3</param>
<param key="thumbnail">true</param>
<param key="hits-per-page">10</param>
<param key="query-root">
<!-- TODO: find out why config from /sade-projects/.../config.xml is not available anymore
system uses project config. again.
-->
<!--xpath>//tei:TEI</xpath-->
<xpath>//tei:sourceDoc/tei:surface</xpath>
</param>
<param key="result-title">
<xpath>//tei:fileDesc//tei:titleStmt/tei:title/text()</xpath>
</param>
<param key="facets">
<!-- <facet key="plc" title="Ort">
<xpath>tei:rs/@ref[starts-with(., 'plc')]</xpath>
</facet>
<facet key="psn" title="Person">
<xpath>tei:rs/@ref[starts-with(., 'psn')]</xpath>
</facet>
<facet key="org" title="Organisation">
<xpath>tei:rs/@ref[starts-with(., 'org')]</xpath>
</facet>
<facet key="wrk" title="Werk">
<xpath>tei:rs/@ref[starts-with(., 'wrk')]</xpath>
</facet>
-->
</param>
</module><!-- added by faceted search -->
<container key="html-head">
<script type="text/javascript" src="modules/faceted-search/js/bootstrap-paginator.min.js"/>
</container>
</config>
\ No newline at end of file
xquery version "3.1";
module namespace fsearch = "http://sade/faceted-search" ;
import module namespace kwic="http://exist-db.org/xquery/kwic";
import module namespace config="http://textgrid.de/ns/SADE/config" at "../config/config.xqm";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace bol="http://blumenbach-online.de/blumenbachiana";
declare namespace templates="http://exist-db.org/xquery/templates";
declare function fsearch:results($node as node(), $model as map(*)) as map()* {
let $page := xs:integer(request:get-parameter("page", "1"))
let $target := config:get("data-dir")
let $hits := local:get-hits($model, $target)
let $obreq := request:get-parameter("order-by", "relevance")
let $order-by := string-join($model("config")//module[@key="faceted-search"]//order[@key = $obreq]//xpath , ",")
let $hitsordered :=
if(request:get-parameter("order", "descending") = "descending") then
for $hit in $hits
order by util:eval($order-by) descending
return $hit
else
for $hit in $hits
order by util:eval($order-by) ascending
return $hit
let $num := try{ xs:integer(config:module-get("faceted-search", "hits-per-page")) } catch * {0}
let $pages := try { ceiling(count($hits) div $num) } catch * { 0 }
let $start := $page * $num - $num + 1
return
map {
"facets" := fsearch:facets($model, $hits),
"hits" := subsequence($hitsordered,$start,$num),
"totalhits" := count($hits),
"start" := $start,
"page" := $page,
"pages" := $pages
}
};
declare
function fsearch:searchquery($node as node(), $model as map(*)) {
let $query := request:get-parameter("q", ())
return <input type="text" value="{$query}" name="q" class="form-control" />
};
declare
%templates:wrap
function fsearch:hitcount($node as node(), $model as map(*)) {
$model("totalhits")
};
declare
%templates:wrap
function fsearch:hitstart($node as node(), $model as map(*)) {
$model("start")
};
declare
%templates:wrap
function fsearch:hitend($node as node(), $model as map(*)) {
let $num := try { xs:integer(config:module-get("faceted-search", "hits-per-page")) } catch * {0}
let $res := $model("start") + $num - 1
return if($res > $model("totalhits"))
then $model("totalhits")
else $res
};
declare
%templates:wrap
function fsearch:page($node as node(), $model as map(*)) {
$model("page")
};
declare
%templates:wrap
function fsearch:pages($node as node(), $model as map(*)) {
$model("pages")
};
declare function fsearch:result-title($node as node(), $model as map(*)) {
let $viewdoc := config:module-get('faceted-search','viewer-html')
return
<a href="{$viewdoc}{util:document-name($model("hit"))}">
{
for $titleQuery in $model("config")//module[@key="faceted-search"]/param[@key="result-title"]//xpath
return util:eval("($model('hit')" || $titleQuery || ")[1]")
}
</a>
};
declare function fsearch:result-xslt($node as node(), $model as map(*)) {
let $docname := util:document-name($model("hit"))
let $id := substring-before($docname, ".")
let $link := config:module-get('faceted-search','viewer-html') || $docname
let $xslt := config:module-get('faceted-search','result-xslt')
let $docpath := config:get("data-dir") || "/xml/data/" || $docname
let $title := doc($docpath)//tei:fileDesc/tei:titleStmt/tei:title
return
transform:transform($model("hit"), doc($xslt),
<parameters>
<param name="id" value="{$id}"/>
<param name="link" value="{$link}"/>
<param name="title" value="{$title}"/>
</parameters>
)
};
declare function fsearch:result-score($node as node(), $model as map(*)) {
ft:score($model('hit'))
};
declare function fsearch:result-img($node as node(), $model as map(*)) {
(: TODO: could better be done in template, than by param :)
if(xs:boolean(config:module-get("faceted-search", "thumbnail"))) then
(: TODO image-xpath should be configured by conf.xml:)
let $src := $model("hit")//bol:kerndaten/bol:mediafiles//bol:mediafile[1]/@file_uri || ($model("hit")//tei:pb)[1]/@facs
return
if(string-length($src) > 0) then
<img src="{config:get("digilib.url")}{$src}{config:get("digilib.thumbnailparam")}"/>
else
()
else
()
};
declare function fsearch:result-kwic($node as node(), $model as map(*)) {
let $hit := $model("hit")
let $expanded := kwic:expand($hit)
let $kwic-width := config:module-get("faceted-search", "kwic-width", 40)
order by ft:score($hit) descending
return
for $i in 1 to xs:integer(config:module-get("faceted-search", "kwic-hits"))
return
if(($expanded//exist:match)[$i]) then
kwic:get-summary($expanded, ($expanded//exist:match)[$i], <config width="{$kwic-width}"/>)
else ()
};
declare function fsearch:result-source($node as node(), $model as map(*)) {
let $docloc := config:get("data-dir") || "/xml/data/" || util:document-name($model("hit"))
return
<a href="/exist/rest{$docloc}">{$node/@class, $node/* }</a>
};
declare
(: %templates:wrap:)
function fsearch:result-id($node as node(), $model as map(*)) {
element { node-name($node) } { attribute name { util:document-name($model("hit")) }, $node/@*, $node/* }
};
declare function fsearch:facets($model as map(*), $hits) as map() {
map:new(
for $facet in $model("config")//module[@key="faceted-search"]//facet
return
map:entry(xs:string($facet/@key), local:facet($model, $hits, $facet/@key, $facet//xpath/text()))
)
};
declare function fsearch:list-facets($node as node(), $model as map(*)) as map(*){
map { "facetgroups" := $model("facet") }
};
declare
function fsearch:facet-title($node as node(), $model as map(*)) {
<li>{map:keys($model("facet"))}</li>
};
declare function fsearch:facet($node as node(), $model as map(*)) as item()* {
let $facets := $model("config")//module[@key="faceted-search"]//facet
for $facet in $facets
(: hide facet-categories with less than one entry :)
where (count($model("facets")(xs:string($facet/@key))) > 0)
return
<li><strong>{xs:string($facet/@title)}</strong>
<ul class="hideMore">{local:deselected-for-key($model, xs:string($facet/@key))}{$model("facets")(xs:string($facet/@key))}</ul>
</li>
};
declare function local:facet($model as map(*), $hits as node()*, $key as xs:string, $types as xs:string*) as node()* {
let $query := request:get-parameter("q", ())
let $order := request:get-parameter("order", ())
let $order-by := request:get-parameter("order-by", ())
let $facetReq := local:facet-query-from-request()
(: the link to the html page displaying this module :)
let $search-html := config:get('exist-resource')
(:construct xpath, e.g. $hits//tei:persName | $hits//bol:a0 :)
let $fqueries := for $type in $types
return concat("$hits", "//", $type)
let $fquery := string-join($fqueries, " |")
(: normalize strings :)
let $unnormal := for $x in util:eval($fquery)
return
(:let $norms := normalize-space($x):)
let $norms := xs:string($x)
return if (string-length($norms) >= 1) then
<un>{$norms}</un>
else
()
let $deselected := local:deselected-for-key($model, $key)
for $facet in distinct-values($unnormal)
let $freq := count($unnormal[. eq $facet])
order by $freq descending
return
if(local:facetSelected($key, $facet))
then
let $facetRemoveQuery := replace($facetReq, $key || ":" || xmldb:encode($facet) || "," , "")
return
<li class="facetSelected">
<a class="facet-minus" href="{$search-html}?q={$query}&amp;facet={$facetRemoveQuery}&amp;order={$order}&amp;order-by={$order-by}">-</a>
{$facet} ({$freq})
</li>
else
<li>
<a class="facet-minus" href="{$search-html}?q={$query}&amp;facet={$key}:!{xmldb:encode($facet)},{$facetReq}&amp;order={$order}&amp;order-by={$order-by}">-</a>
<a href="{$search-html}?q={$query}&amp;facet={$key}:{xmldb:encode($facet)},{$facetReq}&amp;order={$order}&amp;order-by={$order-by}">{$facet}</a> ({$freq})
</li>
};
declare function local:deselected-for-key($model, $key as xs:string) {
let $query := request:get-parameter("q", ())
let $order := request:get-parameter("order", ())
let $order-by := request:get-parameter("order-by", ())
(: the link to the html page displaying this module :)
let $search-html := config:get('exist-resource')
let $facetReq := local:facet-query-from-request()
for $fparts in tokenize($facetReq, ",")
let $parts := tokenize($fparts, ":")
return if($parts[1] eq $key) then
if(starts-with($parts[2], "!"))
then
let $facetRemoveQuery := replace($facetReq, $key || ":" || $parts[2] || "," , "")
return
<li class="facet-deselected">
<a class="facet-plus" href="{$search-html}?q={$query}&amp;facet={$facetRemoveQuery}&amp;order={$order}&amp;order-by={$order-by}">+</a>
{xmldb:decode(substring-after($parts[2], "!"))}
</li>
else
()
else ()
};
declare function local:get-hits($model as map(*), $target as xs:string) as node()*{
let $query := request:get-parameter("q", ())
let $fxquery := local:construct-facet-query($model)
let $options :=
<options>
<leading-wildcard>yes</leading-wildcard>
</options>
let $xqueries := for $query-root in $model("config")//module[@key="faceted-search"]/param[@key="query-root"]//xpath
return
if($query) then
"collection($target)" || $query-root || $fxquery || "[ft:query(., $query, $options)]"
else
"collection($target)" || $query-root || $fxquery
let $xquery := string-join($xqueries, " | ")
return util:eval($xquery)
};
declare function local:construct-facet-query($model as map(*)) as xs:string {
let $facet := local:facet-query-from-request()
let $fxquery :=
if ($facet) then
for $fquery in tokenize($facet, ",")
let $parts := tokenize($fquery, ":")
let $select :=
for $xpath in $model("config")//module[@key="faceted-search"]//facet[@key = $parts[1]]//xpath
let $val := xmldb:decode($parts[2])
let $op := if(starts-with($val, "!"))
then " ne "
else " eq "
let $val := replace($val, "!", "")
return if(starts-with($xpath, ".") or starts-with($xpath, "/"))
(: to escpae quotes, you have to double them :)
then $xpath || $op || """" || $val || """"
else ".//" || $xpath || $op || """" || $val || """"