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

Merge branch 'release/2.9.1'

parents e4ff0924 68595cc3
......@@ -9,7 +9,7 @@
<param key="textgrid.webauth"></param>
<param key="textgrid.authZinstance"></param>
<param key="textgrid.public-triplestore"></param>
<param key="textgrid.nonpublic-triplestore"/>
<param key="textgrid.nonpublic-triplestore"></param>
<!-- if you want to distinguish between develop and productive instance,
set sade.develop "true"
......@@ -30,7 +30,9 @@
<module key="multilanguage">
if present, all requests and links in the response will be redirected
to the choosen or default language. in the standard template, a
switch will be present in the top menu.
<param key="lang.default">de</param>
<param key="lang.alt" description="a semicolon seperated list of alternative languages">en</param>
......@@ -19,19 +19,22 @@ Over the years a few components became obsolete, so the current version is a
completely rewritten one.
## Features
- faceted search
- preconfigured indexes
- TextGrid clients
- [faceted search](
- [preconfigured indexes](
- [TextGrid clients](
- transfer data from the Lab
- fork/download projects
- Lucene string analyzer made for TEI
- validation against RelaxNG schema on publish
- store data in the Lab
- [fork/download projects](
- [Lucene string analyzer](
- made for TEI
- easy (as in easy) configuration of charmaps and synonyms
- easy (as in easy) to configure menu bar (frontend)
- wiki parser
- Confluence
- Dokuwiki
- [wiki parser](
- [Confluence](
- [Dokuwiki](
- professional template
- prepared for optionally prerendering
- [prepared for optionally prerendering](
### Third party addons
- SemToNotes
# Confluence-Wiki-Parser
Dieses Teilmodul kann **öffentliche** Seiten eines Confluence Wikis parsen, um sie als HTML Seiten darszustellen.
Es ist mit dem Modul für **Mehrsprachigkeit kompatibel**!
## Konfiguration des Moduls
Die Konfiguration für dieses Modul befindet sich in der `config.xml`. Dort muss lediglich die (Haupt-)URL der REST Schnittstelle des Wikis angegeben werden.
<param key="confluence.url"></param>
## Allgemeine Benutzung
Nach der Konfiguration kann auf der gewünschten HTML Seite der Inhalt einer Wikiseite folgendermaßen eingebunden werden:
<div data-template="confluence:confluence" data-template-id="44769550"/>
Das Attribute `data-template-id` muss durch die pageID der Wikiseite ersetzt werden.
Standardmäßig ist die Datei wiki.html im template vorhanden. Dieser Seite kann die pageID als Parameter übergeben werden. So können Wikiinhalte mit einem gewünschten Templates umrundet werden.
Beispiel: `doku.html?id=44769550`
## Benutzung mit dem Modul Mehrsprachigkeit
Durch das Konfigurieren des Moduls für Mehrsprachigkeit sind die Sprachen über Sprachenkürzel in der `config.xml` angegeben. Fügen sie bitte für jedes dieser Sprachenkürzel (auch das der Defaultsprache) ein Mapping im `<module key="wiki">` mit dem Confluence eigenen Makronamen der Sprache hinzu. Im folgenden Beispiel sind die Sprachen Deutsch, Englisch und Französisch konfiguriert:
<param key="confluence.lang" description="if the multilanguage plugin is enabled, used languages specified here">
<lang code="de" name="german"/>
<lang code="en" name="english"/>
<lang code="fr" name="french"/>
## Funktionsweise
Für die jeweilige Wikiseite wird beim Aufruf des Nutzers geprüft, ob es eine neue Revision gibt. Ist dies der Fall, wird die neue Revision geparst und in der Datenbank gespeichert. Ist das Modul für Mehrsprachigkeit aktiviert, wird für jede konfigurierte Sprache je eine Datei gespeichert.
# Fork
When working with a SADE instance users usually start manipulating the output,
preparing own transformations or want to use a different configuration for the
lucene index. These changes should be tracked in a Version Control System like
*git* and also they should be deployed to a standalone application that does not
interfere with others. Thats why SADE offers a mechanism to fork any instance at
any state. Developers can use this to continue development and to new users it
offers a playground for testing purposes.
At the SADE GUI within the Lab enter a new project name at the input field in
the first panel (1).
Click on "create" (2) and wait until you get redirected to your own instance.
[Enter a new secure password!]
To continue you have to enter new credentials to the SADE Plugin configuration.
> URL: append -ProjectName to "/sade
> User: ProjectName
> Password:
The username will be the same as the project name and you have to enter the
formerly typed password here as well.
# Download
You can download any application by clicking on the download button at the SADE
Publihser GUI. This gives you a XAR package according to the EXPath package
standard which is in fact a ZIP archive.
When any further development is planned, fork the offical SADE repo from
[]( clone the
repo to your local machine and replace the files with those from the XAR archive.
This is for complete upstream compatibility.
\ No newline at end of file
# Indexes
SADE ships with preconfigured indexes to be found in the files `collection.xconf`.
For larger data sets a good index configuration helps to provide adequate load
**Attention**: To take effect changes must be done in the corresponding resources at `/db/system/config/`. The the post installation script copies the files over there. This is just to preserve the configuration in the EXPath package of this
## Range Index
The range index is used for fast key/value lookups. You will find more information in the eXist-db documentation [website](
Queries are *may* optimized by automatic index lookups when they provide paths.
## Lucene Fulltext Index
For all text nodes in the XML resources, Lucene provides an index to query for
words and phrases. It is used by the [faceted search module](
With a standard installation of SADE, a customized and configurable [String Analyzer]( is available. It is installed as a XAR library.
## Current Configurations
### `/collection.xconf`
Within the root collection, the configuration contains the RESTXQ trigger only,
that enables REST annotations for function calls to provide paths and convert
folders to parameter.
**This currently not used by SADE.** All pathes additional to the collections and
resources stored in the database are provided by the URL rewriter at `/controller.xql`.
### `textgrid/agg/collection.xconf` and `textgrid/rdf/collection.xconf`
Enables the RDF index. This is an optional feature that requires the
`RDF index module` from a [separate package](
### `textgrid/tile/collection.xconf`
This configures the range index for objects generated with the text-image-link editor. Indexes are configured for link targets and shapes.
### `textgrid/meta/collection.xconf`
Within this collection all textgrid metadata is stored. Usually queries regard the
complete URI in the `tgmd:textgridUri` element and the title from `tgmd:title`.
### `textgrid/data/collection.xconf`
This configures the Lucene index and a range index.
#### Lucene
Character mappings and a synonym list are stored in a separate files on the file system. The publish GUI puts text files (text/plain) there.
Define the nodes a text index should be prepared with `<text qname="tei:TEI" analyzer="fontane"/>`. To index words that are divided in different text nodes because of inline elements, these elements should be defined with `<inline qname="tei:g"/>` (optional). Text nodes in elements may not appear in the index can be defined with `<ignore qname="tei:del"/>` (optional).
#### Range
# Mehrsprachigkeit
Dieses Modul ermöglicht mehrsprachige Inhalte. Standardmäßig ist Deutsch als Defaultsprachig eingestellt und Englisch als Alternativsprache.
## Konfiguration des Moduls
Die Konfiguration für dieses Modul befindet sich in der `config.xml`.
Dort muss unter dem Modul `multilanguage` im Parameter `lang.default` eine Defaultsprache (bzw. das entsprechende Sprachenkürzel) angegeben werden. Unter dem Parameter `lang.alt` können beliebig viele weitere Sprachen hinzugefügt werden. Diese müssen mit einem Semikolon getrennt werden. Im folgenden Beispiel sind die Sprachen Deutsch, Englisch und Französisch konfiguriert:
<module key="multilanguage">
<param key="lang.default">de</param>
<param key="lang.alt" description="a semicolon seperated list of alternative languages">en;fr</param>
Bei Abweichungen von der Standardkonfiguration muss der Languageswitcher bearbeitet werden. Standardmäßig ist dieser in der `page_index.html` vorhanden. Dort muss für jede Sprache ein a-Element mit dem dem data-template-to Parameter für die zuvor konfigurierten Sprachenkürzel angelegt werden.
<a data-template="app:switchLanguage" data-template-to="de">Deutsch</a>
<a data-template="app:switchLanguage" data-template-to="en">English</a>
## Benutzung
In der Navigationsleiste `navigation.xml` müssen für jede zusätzlich zu der Defaultsprache konfigurierten Sprache ein Label erstellt werden. Beispiel für Deutsch als Defaultsprache und Englisch als Zweitsprache:
<submenu label="Weiterführende Links" label-en="Further Links">
Um einzelne Wörter, wie Überschriften, auf HTML-Seiten sprachenspezifisch anzeigen zu lassen benutzen sie DIV- oder SPAN-Element mit dem Parameter `data-template="lang:translate"` und einem selbstgewählten `data-template-content` Parameter. Beispiel:
<span data-template="lang:translate" data-template-content="Publications"/>
Dieser `data-template-content` Parameter muss einzigartig sein und zusätzlich in der `lang.xml` erstellt werden.
Folgendes Beispiel zeigt die Übersetzungen für das Wort "Search" in Deutsch, Englisch und Französisch:
<word key="Publications">
<lang key="de">Publikationen</lang>
<lang key="en">Publications</lang>
<lang key="fr">Publications</lang>
## Funktionsweise
Das Modul funktioniert mit dem GET-Parameter "lang". Dieser wird an interne Links automatisch angehängt. Dieses Modul ist kompatibel mit dem Modul Confluence Wiki. Um sprachenspezifische Inhalte aus dem Wiki darzustellen nutzen Sie bitte die Confluence eigenen Makros (z.B. German, English, ...).
# Publizieren aus dem TextGridLab
# Publish via the TextGridLab
## Vorbemerkung
Der Grundsätzliche Umgang mit dem TextGridLab sollte bekannt sein, ansonsten ist das [Benutzerhandbuch]( eine gute Resource für weitergehende Informationen.
Within the TextGridLab the SADE Publish-Plugin is needed. It is available via the [Marketplace](
## Vorbereitung
### Installation des "SADE Publish Tool" im TextGridLab
Um SADE an das TextGridLab anzubinden und komfortables publizieren aus dem Lab zu ermöglichen sollte das "SADE Publish Tool" aus dem Marketplace installiert werden. Dafür im Lab den Menüpunkt "Hilfe->Eclipse-Marketplace" auswählen. Im "Recent" Tab befindet sich der Eintrag "SADE Publish Tool". Nach ein Klick auf "Install" wird dieser ins Lab integriert. Das Lab möchte nun neustarten, das sollte es auch tun.
## Installation
![Marketplace Screenshot](~assets/docs/marketplace.png)
......@@ -14,9 +11,9 @@ Um SADE an das TextGridLab anzubinden und komfortables publizieren aus dem Lab z
Nach dem Neustart aus dem Menu "Fenster->Benutzervorgaben" auswählen. Hier den Eintrag "Sade Publisher" auswählen und eintragen:
> __SADE Url:__ http://localhost:8080/exist/apps/textgrid-connect/publish/tutorial/
> __Authorized User:__ sade
> __Password:__ test
![Preferences Screenshot](~assets/docs/preferences.png)
# TextGrid Clients
\ No newline at end of file
# WikiParser
This module loads, parses and caches documents from wiki systems. It gets the
data via export function (Dokuwiki) or REST interfaces (Confluence), transforms
the somewhat weird formats to plain HTML and stores these resources in `docs`.
To setup one or both modules, a specified configuration is needed. Read on at the
specific documentation:
* **[Conluence Wiki](**
* **[DokuWiki](**
# Inhalte aus einem Wiki laden/parsen
Dieses Modul kann Seiten eines Wikis parsen, um sie als HTML Seiten darszustellen.
Es sind zwei verschiedene Parser verfügbar:
* Confluence Wiki (mit dem Modul für **Mehrsprachigkeit kompatibel**!)
* DokuWiki (**NICHT** mit dem Modul für **Mehrsprachigkeit kompatibel**!)
Beide Parser würden auch parallel funktionieren, unterscheiden sich aber in ihrer Funktionsweise, der Konfiguration und den Vorausetzungen.
## Dokumentation
Bitte lesen sie vor der Benutzung die jeweilige Dokumentation:
* **[Conluence Wiki](**
* **[DokuWiki](**
<package xmlns="" name="" abbrev="SADE" version="2.9.0" spec="1.0">
<package xmlns="" name="" abbrev="SADE" version="2.9.1" spec="1.0">
<title>Scalable Architecture for Digital Editions powered by TextGrid</title>
<dependency package=""/>
<dependency package=""/>
xquery version "3.1";
: generic and simple functions used by templates and other modules.
: also an incubator of new modules.
module namespace app="";
......@@ -6,11 +11,11 @@ import module namespace config="" at "config.x
import module namespace templates="" ;
import module namespace functx="";
declare namespace rdf="";
declare namespace tei="";
declare namespace tgmd="";
declare namespace tgrel="";
declare namespace xqdoc="";
: Get the title of this app by using the config.xml.
......@@ -229,3 +234,95 @@ declare function app:error($node as node(), $model as map(*)) {
declare function app:currentyear($node as node(), $model as map(*)) {
year-from-date( current-date() )
: A templating function to lookup and represent the XQDocs from fundocs app.
: Depends on the optional fundocs app.
: :)
function app:xqdocs($node as node(), $model as map(*)) {
let $xqdata := "/db/apps/fundocs/data/"
if( not(xmldb:collection-available($xqdata)) )
then error( QName("", "XQDOCS01"), "Docs not available.")
let $modules :=
for $xqdoc in collection($xqdata)//xqdoc:location[starts-with(., $config:app-root||"/")]/ancestor::xqdoc:xqdoc
order by $xqdoc/xqdoc:module/xqdoc:name/text()
(: error( QName("", "XQDOCS01"), $modules[1]):)
map {"modules": $modules}
declare function app:xqdocs-name($node as node(), $model as map(*)) {
element { node-name($node) } {
attribute data-doc {($model("module")/base-uri() => tokenize("/"))[last()]},
declare function app:xqdocs-version($node as node(), $model as map(*)) {
element { node-name($node) } {
$node/@*[not(starts-with(local-name(), "data-"))],
declare function app:xqdocs-uri($node as node(), $model as map(*)) {
element { node-name($node) } {$model("module")//xqdoc:module/xqdoc:uri/text()}
declare function app:xqdocs-desc($node as node(), $model as map(*)) {
let $desc := $model("module")//xqdoc:module//xqdoc:description/text()
element { node-name($node) } {
$node/@*[not(starts-with(local-name(), "data-"))],
declare function app:xqdocs-author($node as node(), $model as map(*)) {
let $author := string-join($model("module")//xqdoc:module//xqdoc:author/text(), ", ")
element { node-name($node) } {
$node/@*[not(starts-with(local-name(), "data-"))],
function app:xqdocs-module($node as node(), $model as map(*)) {
map {"functions": $model("module")//xqdoc:functions/xqdoc:function}
declare function app:xqdocs-functionname($node as node(), $model as map(*)) {
element { node-name($node) } {$model("function")/xqdoc:name/text()}
declare function app:xqdocs-signature($node as node(), $model as map(*)) {
declare function app:xqdocs-functiondesc($node as node(), $model as map(*)) {
declare function app:xqdocs-functionparam($node as node(), $model as map(*)) {
for $param in $model("function")/xqdoc:comment/xqdoc:param
let $pattern := "\s(\-|–)\s"
let $name := tokenize($param/text(), $pattern)[1]
let $desc := string-join(tokenize($param/text(), $pattern)[position() gt 1], " ")
element { node-name($node) } {
$node/@*[not(starts-with(local-name(), "data-"))],
<li class="param">
{if($desc = "") then () else
declare function app:xqdocs-functionreturn($node as node(), $model as map(*)) {
element { node-name($node) } {
$node/@*[not(starts-with(local-name(), "data-"))],
......@@ -139,13 +139,13 @@ declare function fsearch:result-kwic($node as node(), $model as map(*)) {
let $hit := $model("hit")
let $expanded := kwic:expand($hit)
let $kwic-width := config:get("faceted-search", "kwic-width")
let $kwic-width := config:get("kwic-width", "faceted-search")
order by ft:score($hit) descending
for $i in 1 to xs:integer(config:get("kwic-hits", "faceted-search"))
if(($expanded//exist:match)[$i]) then ()
(: kwic:get-summary($expanded, ($expanded//exist:match)[$i], <config width="{$kwic-width}"/>):)
if(($expanded//exist:match)[$i]) then
kwic:get-summary($expanded, ($expanded//exist:match)[$i], <config width="{$kwic-width}"/>)
else ()
......@@ -107,7 +107,7 @@ declare function multiviewer:markdown($docpath as xs:string) as item()* {
declare function multiviewer:TEI($TEI as element(tei:TEI)) as node()* {
let $stylesheet := doc($config:app-root || "_assets/TEI-Stylesheets/html5/html5.xsl")
let $stylesheet := doc( substring-before($config:app-root, "/sade") || "/sade_assets/TEI-Stylesheets/html5/html5.xsl")
let $transform := transform:transform($TEI, $stylesheet, ())/xhtml:body/node()
......@@ -132,7 +132,10 @@ declare function tgconnect:publish( $uri as xs:string,
"storing the data failed with " || $err:code || ": " || $err:description
|| "Is your file conform to XML standard? Typical mistakes are empty xml:id attributes.") }
let $render := (: this is where you can start with prerendering. :) ()
let $render := (: this is where you can start with prerendering.
it is recommended to call a function placed
at the bottom or in a separat module. :)
let $validate :=
(: validation fails on autodeploy :)
if( $login = true() ) then () else
......@@ -19,6 +19,12 @@ declare function tgmenu:template($node as node(), $model as map(*)) {
let $metacollection := collection( $config:data-root || "/meta" )
let $uris := $metacollection//tgmd:textgridUri/string()
if($uris = ())
then error(
QName("", "MENU01"),
"There is no data available. Please publish items at first.")
else (: continue :)
let $aggcollection := collection( $config:data-root || "/agg" )
let $aggregates := $aggcollection//ore:aggregates/string(@rdf:resource)
<div data-template="templates:surround" data-template-with="templates/page_index.html" data-template-at="content-container">
<div class="container xqdocs" data-template="app:xqdocs">
<div class="row" data-template="templates:each" data-template-from="modules" data-template-to="module">
<section data-template="app:xqdocs-module">
<h1 class="block-header">
<span data-template="app:xqdocs-name"></span>
<div class="panel panel-default">
<div class="panel-heading"><span data-template="app:xqdocs-uri"/><span class="version" data-template="app:xqdocs-version"/></div>
<div class="panel-body">
<div class="desc" data-template="app:xqdocs-desc"/>
<div class="author" data-template="app:xqdocs-author"/>
<div data-template="templates:each" data-template-from="functions" data-template-to="function">
<div class="panel panel-default">
<div class="panel-heading">
<span data-template="app:xqdocs-functionname"/>
<div class="panel-body">
<pre><code><span data-template="app:xqdocs-signature"/></code></pre>
<div class="desc" data-template="app:xqdocs-functiondesc"/>
<ul class="param" data-template="app:xqdocs-functionparam"/>
<div class="return" data-template="app:xqdocs-functionreturn"/>
......@@ -126,7 +126,7 @@
<a href="">Bibliothek der Neologie</a>
<a href="">Bibliothek der Neologie</a>
<a href="">Architrave</a>
<div data-template="templates:surround" data-template-with="templates/page_index.html" data-template-at="content-container">
<div class="row" data-template="fsearch:results">
<div class="row faceted-search" data-template="fsearch:results">
<ul class="col-md-3 facet-area">
<div data-template="fsearch:facet"/>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment