From 2cd06bfe2036080b5b4790bf501083d603676e85 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Wed, 29 Nov 2023 13:36:13 +0100 Subject: [PATCH 01/36] handle tei:foreign --- edoc/resources/xsl/tei-common.xsl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/edoc/resources/xsl/tei-common.xsl b/edoc/resources/xsl/tei-common.xsl index a1f1634c..6213d56e 100644 --- a/edoc/resources/xsl/tei-common.xsl +++ b/edoc/resources/xsl/tei-common.xsl @@ -677,7 +677,20 @@ + + + + + + + + + + + - + From 15f05641a78156099876a0627991f4699c451493 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Wed, 29 Nov 2023 16:34:51 +0100 Subject: [PATCH 02/36] function.xqm needs to import pquery --- edoc/modules/function.xqm | 1 + 1 file changed, 1 insertion(+) diff --git a/edoc/modules/function.xqm b/edoc/modules/function.xqm index 0a6ec1f4..552ff47c 100644 --- a/edoc/modules/function.xqm +++ b/edoc/modules/function.xqm @@ -10,6 +10,7 @@ import module namespace wdba = "https://github.com/dariok/wdbplus/auth" import module namespace wdbAddinMain = "https://github.com/dariok/wdbplus/addins-main" at "/db/apps/edoc/modules/addin.xqm"; import module namespace wdbe = "https://github.com/dariok/wdbplus/entity" at "/db/apps/edoc/modules/entity.xqm"; import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "/db/apps/edoc/modules/error.xqm"; +import module namespace wdbpq = "https://github.com/dariok/wdbplus/pquery" at "/db/apps/edoc/modules/pquery.xqm"; import module namespace wdbs = "https://github.com/dariok/wdbplus/stats" at "stats.xqm"; import module namespace wdbSearch = "https://github.com/dariok/wdbplus/wdbs" at "/db/apps/edoc/modules/search.xqm"; import module namespace wdbst = "https://github.com/dariok/wdbplus/start" at "/db/apps/edoc/modules/start.xqm"; From 4a341530811b93a1b32bd10805c71320cb90c06d Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Fri, 1 Dec 2023 11:15:39 +0100 Subject: [PATCH 03/36] handle foreign/@style --- edoc/resources/xsl/tei-common.xsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edoc/resources/xsl/tei-common.xsl b/edoc/resources/xsl/tei-common.xsl index 6213d56e..7f1f38ae 100644 --- a/edoc/resources/xsl/tei-common.xsl +++ b/edoc/resources/xsl/tei-common.xsl @@ -682,7 +682,7 @@ - + From c41b0a0513710752aefb459bd1dc5fb6bb6f82e8 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Mon, 11 Dec 2023 15:49:51 +0100 Subject: [PATCH 04/36] Templating function: add attribute to element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get the value by evaluating an XQuery expression: data-template-attribute for the attrib’s name data-template-expression for the code to evaluate --- edoc/modules/function.xqm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/edoc/modules/function.xqm b/edoc/modules/function.xqm index 552ff47c..a9755fb4 100644 --- a/edoc/modules/function.xqm +++ b/edoc/modules/function.xqm @@ -181,6 +181,13 @@ declare function wdbfp:getVal ($node as node(), $model as map(*), $key as xs:str } }; +declare function wdbfp:evalForAttribute ( $node as node(), $model as map(*), $attribute as xs:string, $expression as xs:string ) { + element { local-name($node) } { + attribute { $attribute } { util:eval($expression) }, + $node/node() + } +}; + declare function wdbfp:getHead ( $node as node(), $model as map(*), $templateFile as xs:string* ) as element(head) { From d706b9710dd9239721b5e8994d0746a25cac9d89 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Tue, 12 Dec 2023 16:56:13 +0100 Subject: [PATCH 05/36] use standard $ed for project ID finalize and apply nomenclature for function parameters adjust to style book Cf. #499 #441 --- edoc/rest/rest-coll.xql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/edoc/rest/rest-coll.xql b/edoc/rest/rest-coll.xql index d0e1f2cf..aa7ef05c 100644 --- a/edoc/rest/rest-coll.xql +++ b/edoc/rest/rest-coll.xql @@ -407,13 +407,13 @@ function wdbRc:getStructureJson ( $id ) { (: navigation :) declare %rest:GET - %rest:path("/edoc/collection/{$id}/nav.xml") -function wdbRc:getCollectionNavXML ($id as xs:string) { - let $md := collection($wdb:data)/id($id)[self::meta:projectMD] - let $uri := base-uri($md) - let $struct := $md/meta:struct + %rest:path("/edoc/collection/{$ed}/nav.xml") +function wdbRc:getCollectionNavXML ( $ed as xs:string ) { + let $md := collection($wdb:data)/id($ed)[self::meta:projectMD] + , $uri := base-uri($md) + , $struct := $md/meta:struct - let $content := {( + let $content := {( $struct/@*, $struct/* )} From 66f1ac5189b218dc814ab88e12eb7daa43e1f635 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Tue, 12 Dec 2023 18:04:55 +0100 Subject: [PATCH 06/36] file upload: show info on parser error --- edoc/resources/scripts/admin.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/edoc/resources/scripts/admin.js b/edoc/resources/scripts/admin.js index a3db1a92..763ef34e 100644 --- a/edoc/resources/scripts/admin.js +++ b/edoc/resources/scripts/admin.js @@ -1,6 +1,3 @@ -/* globals wdb */ -/* jshint browser: true */ -/* globals wdb */ "use strict"; const wdbAdmin = { @@ -111,9 +108,14 @@ const wdbAdmin = { /* jshint loopfunc: true*/ reader.onload = async function ( readFile ) { tableData.innerText = "."; - let fileContent = readFile.target.result, - parser = new DOMParser(), - parsed; + let fileContent = readFile.target?.result; + if ( fileContent === undefined || fileContent === "" || fileContent === null ) { + wdb.report("error", "empty", "no file content", tableData); + return false; + } + + let parser = new DOMParser() + , parsed; // try to parse as XML (for now, we only handle XML files here) try { @@ -124,11 +126,16 @@ const wdbAdmin = { } // try to find an ID for the XML file - let xml = $(parsed), - fileID = xml.find("TEI").attr("xml:id"); + let xml = $(parsed) + , fileID = xml.find("tei\\:TEI, TEI").attr("xml:id") + , parserError = xml.find("parsererror"); - if (fileID === undefined || fileID == "") { - wdb.report("error", "no @xml:id found in " + file.name, {}, tableData); + if ( xml.find("parsererror").length > 0 ) { + wdb.report("error", "parser error", parserError.text(), tableData); + return false; + } + if ( fileID === undefined || fileID === "" ) { + wdb.report("error", "ID missing", "no @xml:id found in " + file.name, {}, tableData); return false; } From a3e0e7378e68f8c6003d89ec3f052cf8e4ecbead Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Wed, 13 Dec 2023 16:02:10 +0100 Subject: [PATCH 07/36] display sub-structures of current project --- edoc/resources/nav.xsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edoc/resources/nav.xsl b/edoc/resources/nav.xsl index 7550f1ca..5310527f 100644 --- a/edoc/resources/nav.xsl +++ b/edoc/resources/nav.xsl @@ -51,7 +51,7 @@
    - + display: none; From 9072252064137933e629317592bf8eb4a5e0e066 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Wed, 3 Jan 2024 16:29:41 +0100 Subject: [PATCH 08/36] update README and description for v3.0 --- README.md | 50 +++++++++++++++++---------------------------- edoc/expath-pkg.xml | 4 ++-- 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index f9f8f5b5..7395b1c2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,14 @@ An extensible framework for digital Editions for the [eXist XML database](https: This framework still lacks a good name. If you have an idea, please let me know! +## Incompatible changes + +Release 24Q1 dropped support for METS-based projects. As METS files can have a number of very different ways of encoding +information, especially when it comes to behaviours, native support is hard to achieve. At the same time, most +installations use wdb+’s native wdbmeta system as this is what the admin functions work with. +If you require METS support, please open an issue and provide an example of your METS files. We will then try to create +import and export functions. + ## Installation You need a working instance of eXist (4.0 or later). It is recommended that you use the default software selection during installation. The default memory settings usually work very well but you can, of course, always give eXist a @@ -12,38 +20,10 @@ little more RAM. 1. Clone this repo including its submodules (xstring, wdbmeta) 1. `cd edoc` 1. run `ant` -1. install the `.xar` file created in `edoc/build/` using eXist's dashboard +1. install the `.xar` file created in `edoc/build/` using eXist's dashboard or (https://github.com/eXist-db/xst)[XST] The app will be installed into `/db/apps/edoc`. -### eXgit -Additionally, it is possible to use [eXgit](https://github.com/dariok/exgit) to clone the current version directly into a running eXist instance. - -1. Install eXgit as stated in the repo. -1. create a user `wdb` and a group `wdbusers` for the framework and log in under that name –– CAVEAT: this user, at least for the duration of the installation, **needs to be** in the **dba** group! -1. create the target collection (default would be `/db/apps/edoc`) as this user -1. open eXide from eXist's Dashboard -1. paste: - ``` - xquery version "3.1"; - - import module namespace exgit="http://exist-db.org/xquery/exgit" at "java:org.exist.xquery.modules.exgit.Exgit"; - - let $whereToClone := "/home/user/git/wdbplus" - let $targetCollection := "/db/apps/edoc" - - let $cl := exgit:clone("https://github.com/dariok/wdbplus", $whereToClone) - let $ie := exgit:import($whereToClone || "/edoc", $targetCollection) - let $ic := exgit:import($whereToClone || "/edoc/config", "/db/system/config/db/apps") - ``` -1. replace the value of `$whereToClone` with the full target directory on your file system where the app shall be cloned into -1. if you do not want to install into `/db/apps/edoc`, change the value of `$targetCollection` to the full DB path -1. run the script -1. open `post-install.xql` in your target collection -1. if you did not install into `/db/apps/edoc`, change `$targetCollection` accordingly -1. run `post-install.xql` to set rights and index configuration - - ### manual installation 1. clone this repo including its submodules 1. put folder `edoc` anywhere you want in your eXist; the default would be `/db/apps/edoc`; you can also rename it to your needs (in this case, you have to adjust the paths in the next steps!). @@ -55,7 +35,14 @@ Set the name for the instance and other settings in `edoc/config.xml` or using t ## Creating and uploading projects While many different ways of putting data into the application are possible, the standard way is to have one collection -under data for each project. It is possible to create an initial setup using `admin/admin.html`. The following describes a manual installation and assumes that you work with a standard setup, i.e. have installed the app +under data for each project. + +### Using admin functions +It is possible to create an initial setup using `admin/admin.html`. After creating a project, you can immediately start +uploading files using the upload form. wdb+ will take care of creating meta data entries. + +### Manual approach +The following describes a manual installation and assumes that you work with a standard setup, i.e. have installed the app into `/db/apps/edoc` and want to put your projects into `/db/apps/edoc/data/yourproject`. 1. create `wdbmeta.xml` in `/db/apps/edoc/data/yourproject`, either by copying, pasting and editing the example below or by using @@ -102,6 +89,7 @@ See the Wiki for details! * Repertotium frühneuzeitlicher Rechtsquellen * Protokolle der Sitzungen der Gesamtakadmie * Akademie der Wissenschaften, Heidelberg - * Theologenbriefwechsel + * Theologenbriefwechsel +* ULB Darmstadt If you use wdbplus for your editions, please drop me a message so I can add you to this list. diff --git a/edoc/expath-pkg.xml b/edoc/expath-pkg.xml index 7b21c517..fe43428b 100644 --- a/edoc/expath-pkg.xml +++ b/edoc/expath-pkg.xml @@ -1,4 +1,4 @@ - + W. Digitale Bibliothek - + From cf8ca549b4ff18227c5730375af8f9fa15757369 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Wed, 3 Jan 2024 17:09:58 +0100 Subject: [PATCH 09/36] enable XInclude processing by default --- README.md | 5 +++++ edoc/modules/app.xqm | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7395b1c2..a09379b8 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ installations use wdb+’s native wdbmeta system as this is what the admin funct If you require METS support, please open an issue and provide an example of your METS files. We will then try to create import and export functions. +Release 24Q1 introduced changes to the transformation: previously, XIncludes were not expanded before the XSLT was +applied to a file. This has now been dropped meaning that XIncludes will always be expanded. This is most likely the +expected behaviour. If you want to ignore XInclude, you can add this as a global setting in eXist: in +`${eXist-dir}/etc/conf.xml` set `serializer/@enable-xinclude` to `no`. + ## Installation You need a working instance of eXist (4.0 or later). It is recommended that you use the default software selection during installation. The default memory settings usually work very well but you can, of course, always give eXist a diff --git a/edoc/modules/app.xqm b/edoc/modules/app.xqm index 444b2573..8f1702b6 100644 --- a/edoc/modules/app.xqm +++ b/edoc/modules/app.xqm @@ -53,7 +53,7 @@ declare variable $wdb:data := where contains($path, '.xml') order by string-length($path) return $path - + return replace(xstring:substring-before-last($paths[1], '/'), '//', '/') ; @@ -206,7 +206,9 @@ declare function wdb:getEE($node as node(), $model as map(*), $id as xs:string, $view as xs:string, $p as xs:string) as item()* { let $newModel := wdb:populateModel($id, $view, $model, $p) - let $pathParts := tokenize(replace($newModel?fileLoc, '//', '/'), '/') + let $pathParts := if ( $newModel instance of map(*) ) + then tokenize(replace($newModel?fileLoc, '//', '/'), '/') + else wdbErr:error(map{"code": "wdbErr:0815", "newModel": $newModel}) , $collection := string-join($pathParts[not(position() = last())], '/') , $dateTime := xmldb:last-modified($collection, $pathParts[last()]) , $adjusted := adjust-dateTime-to-timezone($dateTime,"-PT0H0M") @@ -497,7 +499,7 @@ declare function wdb:getContent($node as node(), $model as map(*)) { return try {
    - { transform:transform(doc($file), doc($xslt), $params, $attr, "expand-xincludes=no") } + { transform:transform(doc($file), doc($xslt), $params, $attr, "") } { wdb:getLeftFooter($node, $model) }
    } catch * { (util:log("error", From fa08c79b06ff9f17f48029598d35588453296912 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Thu, 18 Jan 2024 00:03:35 +0100 Subject: [PATCH 10/36] Drop METS support Cf. #418 --- doc/Global-variables.md | 4 +- doc/Main-HTML-files.md | 1 - doc/wdbmeta.xml.md | 4 +- edoc/admin/admin.xqm | 18 +- edoc/admin/projects.xqm | 20 +- edoc/config/edoc/data/collection.xconf | 7 +- edoc/modules/app.xqm | 80 +--- edoc/modules/stats.xqm | 51 +-- edoc/modules/wdb-files.xqm | 21 +- edoc/resources/mets.xsl | 494 ------------------------ edoc/resources/xsl/tei-introduction.xsl | 21 +- edoc/resources/xsl/tei-transcript.xsl | 2 +- edoc/rest/rest-coll.xql | 25 +- edoc/rest/rest-files.xql | 16 +- 14 files changed, 84 insertions(+), 680 deletions(-) delete mode 100644 edoc/resources/mets.xsl diff --git a/doc/Global-variables.md b/doc/Global-variables.md index 364552f1..b1809303 100644 --- a/doc/Global-variables.md +++ b/doc/Global-variables.md @@ -8,10 +8,10 @@ This is part of eXist's templating system and has been used in several locations | parameter | contents | |--|--| -| `ed` | the ID of the Collection (= `@xml:id` of `meta:projectMD` or `mets:mets`) | +| `ed` | the ID of the Collection (= `@xml:id` of `meta:projectMD`) | | `fileLoc` | full path to the current Resource | | `id` | a file's ID (e.g. file to be displayed) | -| `infoFileLoc` | full path to `wdbmeta.xml` or `mets.xml` | +| `infoFileLoc` | full path to `wdbmeta.xml` | | `pathToEd` | the full DB-Path to the Collection (= `substring-before($infoFileLoc, '/wdbmeta.xml')`) | | `projectFile` | path to Project’s `project.xqm`| | `projectResources` | path to Project’s resource folder (= `substring-before($projectFile, 'project.xqm') || 'resources'`)| diff --git a/doc/Main-HTML-files.md b/doc/Main-HTML-files.md index 208b83a8..06c7c7a5 100644 --- a/doc/Main-HTML-files.md +++ b/doc/Main-HTML-files.md @@ -10,7 +10,6 @@ _Template:_ `page2.html` ### index.html Serves as the main point of entry by displaying an inventory of all projects currently present in the instance. It is assumed, that every project uses a `wdbmeta.xml` and that every `wdbmeta.xml` describes a project. Thus, subprojects are recognized. -Projects that solely rely on a `mets.xml` will be recognized and displayed, too. Subporjects for a METS-project are not supported, though. _Template:_ `page2.html` diff --git a/doc/wdbmeta.xml.md b/doc/wdbmeta.xml.md index 862cd989..c6cd70e8 100644 --- a/doc/wdbmeta.xml.md +++ b/doc/wdbmeta.xml.md @@ -5,8 +5,8 @@ This documentation will cover the most important parts and how the file is evalu Evey project should have a `wdbmeta.xml` file. This is also true about the main data collection. `wdbmeta.xml` is intended to replace `mets.xml` with a less verbose format while maintaining its functionality as a table of contents for a project. -While it is possible to solely rely on a `mets.xml`, the app is designed with `wdbmeta.xml` in mind. -Especially when it comes to rules for processing files, `wdbmeta.xml` is a lot easier to work with than a `mets.xml`. +Since v 3.0, `wdbmeta.xml` is the only format available as METS support has been dropped. If METS are required, the way +to achieve this is via an XSLT-based import and export of the METS data into `wdbmeta.xml`. The files main element in `projectMD` in the namespace `https://github.com/dariok/wdbplus/wdbmeta`. diff --git a/edoc/admin/admin.xqm b/edoc/admin/admin.xqm index ed968eac..7f9aaa44 100644 --- a/edoc/admin/admin.xqm +++ b/edoc/admin/admin.xqm @@ -8,8 +8,6 @@ import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" a import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "/db/apps/edoc/modules/error.xqm"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace mets = "http://www.loc.gov/METS/"; -declare namespace mods = "http://www.loc.gov/mods/v3"; declare namespace sm = "http://exist-db.org/xquery/securitymanager"; (:~ @@ -22,19 +20,13 @@ declare %templates:default("ed", "") function wdbAdmin:start ( $node as node(), $model as map(*), $ed as xs:string ) { try { - let $pathToEd := if ( $ed = "" ) then - $wdb:data - else - wdb:getEdPath($ed, true()) + let $pathToEd := if ( $ed = "" ) + then $wdb:data + else wdb:getEdPath($ed, true()) - (: The meta data are taken from wdbmeta.xml or a mets.xml as fallback :) + (: The meta data are taken from wdbmeta.xml :) let $infoFileLoc := wdb:getMetaFile($pathToEd) - - let $title := - ( - normalize-space((doc($infoFileLoc)//meta:title)[1]), - normalize-space((doc($infoFileLoc)//mods:title)[1]) - )[1] + , $title := normalize-space((doc($infoFileLoc)//meta:title)[1]) return map { "ed": if ( $pathToEd = $wdb:data ) then "data" else $ed, diff --git a/edoc/admin/projects.xqm b/edoc/admin/projects.xqm index 4c7e8f87..0400a10f 100644 --- a/edoc/admin/projects.xqm +++ b/edoc/admin/projects.xqm @@ -9,7 +9,6 @@ import module namespace xstring = "https://github.com/dariok/XStringUtils" at declare namespace config = "https://github.com/dariok/wdbplus/config"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace mets = "http://www.loc.gov/METS/"; declare namespace tei = "http://www.tei-c.org/ns/1.0"; declare function wdbPL:pageTitle ($node as node(), $model as map(*)) { @@ -98,10 +97,7 @@ declare function wdbPL:body ( $node as node(), $model as map(*) ) { declare function local:getFiles($model) { let $infoFile := doc($model?infoFileLoc) - let $filesInEd := ( - $infoFile//meta:file, - $infoFile//mets:file - ) + , $filesInEd := $infoFile//meta:file return
    @@ -116,7 +112,7 @@ declare function local:getFiles($model) { { for $doc in $filesInEd - let $info := if ($doc[self::meta:file]) + let $info := if ( $doc[self::meta:file] ) then let $id := $doc/@xml:id let $view := $infoFile//meta:view[@file = $id] @@ -128,17 +124,7 @@ declare function local:getFiles($model) { $model?pathToEd || "/" || $doc/@path, $view/@label ) - else - let $id := $doc/@ID - let $struct := $infoFile//mets:fptr[@FILEID = $id]/parent::tei:div - return ( - $id, - if ($struct/@ORDERLABEL castable as xs:int) - then number($struct/@ORDERLABEL) - else string($struct/@ORDERLABEL), - $model?pathToEd || "/" || $doc/mets:FLocat/@*:href, - $struct/@LABEL - ) + else () order by $info[3] return diff --git a/edoc/config/edoc/data/collection.xconf b/edoc/config/edoc/data/collection.xconf index add9e0d2..ec6f18ed 100644 --- a/edoc/config/edoc/data/collection.xconf +++ b/edoc/config/edoc/data/collection.xconf @@ -1,5 +1,5 @@ - + @@ -59,10 +59,7 @@ - - - - + diff --git a/edoc/modules/app.xqm b/edoc/modules/app.xqm index 8f1702b6..e39cf14e 100644 --- a/edoc/modules/app.xqm +++ b/edoc/modules/app.xqm @@ -21,10 +21,8 @@ import module namespace xstring = "https://github.com/dariok/XStringUtils" declare namespace config = "https://github.com/dariok/wdbplus/config"; declare namespace main = "https://github.com/dariok/wdbplus"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace mets = "http://www.loc.gov/METS/"; declare namespace rest = "http://exquery.org/ns/restxq"; declare namespace tei = "http://www.tei-c.org/ns/1.0"; -declare namespace xlink = "http://www.w3.org/1999/xlink"; (: ALL-PURPOSE VARIABLES :) (:~ @@ -283,20 +281,16 @@ declare function wdb:populateModel ( $id as xs:string, $view as xs:string, $mode let $pathToEd := wdb:getEdPath($id, true()) let $pathToEdRel := substring-after($pathToEd, $wdb:edocBaseDB||'/') - (: The meta data are taken from wdbmeta.xml or a mets.xml as fallback :) + (: The meta data are taken from wdbmeta.xml :) let $infoFileLoc := wdb:getMetaFile($pathToEd) - let $ed := if (ends-with($infoFileLoc, 'wdbmeta.xml')) - then string(doc($infoFileLoc)/meta:projectMD/@xml:id) - else string(doc($infoFileLoc)/mets:mets/@OBJID) + let $ed := string(doc($infoFileLoc)/meta:projectMD/@xml:id) - let $xsl := if ( contains($pTF, 'wdbmeta.xml') ) then + let $xsl := if ( contains($pTF, 'wdbmeta.xml') ) + then (: TODO get path to XSL via function (use what’s in rest-files.xql) :) xs:anyURI($wdb:data || '/resources/nav.xsl') - else if ( ends-with($infoFileLoc, 'wdbmeta.xml') ) then - wdb:getXslFromWdbMeta($infoFileLoc, $id, 'html') - else - wdb:getXslFromMets($infoFileLoc, $id, $pathToEdRel) + else wdb:getXslFromWdbMeta($infoFileLoc, $id, 'html') let $xslt := if (doc-available($xsl)) then $xsl @@ -599,8 +593,7 @@ declare function wdb:getFilePath ( $id as xs:string ) as xs:string { : @returns the path (relative) to the app root :) declare function wdb:getEdPath($id as xs:string, $absolute as xs:boolean) as xs:string { - let $file := (collection($wdb:data)/id($id)[local-name() = ('file', 'projectMD', 'struct', 'mets')], - collection($wdb:data)//mets:file[@ID = $id])[1] + let $file := collection($wdb:data)/id($id)[local-name() = ('file', 'projectMD', 'struct')] let $edPath := if ( count($file) = 1 ) then xstring:substring-before-last(base-uri($file), '/') @@ -642,11 +635,8 @@ declare function wdb:getAbsolutePath ( $ed as xs:string, $path as xs:string ) { : @return the ID of the project :) declare function wdb:getEdFromFileId ($id as xs:string) as xs:string { - let $file := (collection($wdb:data)/id($id)[self::meta:file], - collection($wdb:data)//mets:file[@ID = $id])[1] - return if ($file[self::meta:file]) - then $file/ancestor::meta:projectMD/@xml:id - else $file/ancestor::mets:mets/@OBJID + let $file := collection($wdb:data)/id($id)[self::meta:file] + return $file/ancestor::meta:projectMD/@xml:id }; (: ~ @@ -669,12 +659,10 @@ declare function wdb:getEdFromPath($path as xs:string, $absolute as xs:boolean) wdbErr:error(map{"code": "wdbErr:wdb2001", "additional": {$path}}) else for $p in $pa order by string-length($p) descending - let $p1 := $p || '/wdbmeta.xml' - let $p2 := $p || '/mets.xml' - return if (doc-available($p1) or doc-available($p2)) then $p else () + return if ( doc-available($p || '/wdbmeta.xml') ) then $p else () - return if ($absolute) + return if ( $absolute ) then $path[1] else substring-after($path[1], $wdb:edocBaseDB||'/') }; @@ -791,14 +779,12 @@ declare function wdb:eval($function as xs:string, $cache-flag as xs:boolean, $ex (:~ : Return the full path to the project collection by trying to find the meta file by the project ID : - : @param $ed The ID of a project, to be found in meta:projectMD/@xml:id or mets:mets/@OBJID + : @param $ed The ID of a project, to be found in meta:projectMD/@xml:id : @return The path to the project :) declare function wdb:getProjectPathFromId ( $ed as xs:string ) as xs:string { - let $md := ( - collection($wdb:data)/id($ed)[self::meta:projectMD], - collection($wdb:data)/mets:mets[@OBJID = $ed] - ) + let $md := collection($wdb:data)/id($ed)[self::meta:projectMD] + return xstring:substring-before-last(base-uri(($md)[1]), '/') }; @@ -806,10 +792,8 @@ declare function wdb:getProjectPathFromId ( $ed as xs:string ) as xs:string { : Get the meta data file from the ed path :) declare function wdb:getMetaFile($pathToEd) { - if (doc-available($pathToEd||'/wdbmeta.xml')) + if ( doc-available($pathToEd||'/wdbmeta.xml') ) then $pathToEd || '/wdbmeta.xml' - else if (doc-available($pathToEd || '/mets.xml')) - then $pathToEd || '/mets.xml' else fn:error(fn:QName('https://github.com/dariok/wdbErr', 'wdbErr:wdb0003')) }; @@ -819,7 +803,7 @@ declare function wdb:getMetaFile($pathToEd) { : @param $ed The project ID to be evaluated :) declare function wdb:getMetaElementFromEd ( $ed as xs:string ) as element() { - collection($wdb:data)/id($ed)[self::meta:projectMD or self::mets:mets] + collection($wdb:data)/id($ed)[self::meta:projectMD] }; (: END GENERAL HELPER FUNCTIONS :) @@ -858,40 +842,6 @@ declare function wdb:getXslFromWdbMeta ( $infoFileLoc as xs:string, $id as xs:st (: As we check from most specific to default, the first command in the sequence is the right one :) return ($sel)[1]/text() }; -declare function wdb:getXslFromMets ($metsLoc, $id, $ed) { - let $mets := doc($metsLoc) - let $structs := $mets//mets:div[mets:fptr[@FILEID=$id]]/ancestor-or-self::mets:div/@ID - - let $be := for $s in $structs - return $mets//mets:behavior[matches(@STRUCTID, concat('(^| )', $s, '( |$)'))] - let $behavior := for $b in $be - order by local:val($b, $structs, 'HTML') - return $b - let $trans := $behavior[last()]/mets:mechanism/@xlink:href - - return concat($wdb:edocBaseDB, '/', $ed, '/', $trans) -}; -(: Try to find the most specific mets:behavior - : $test: mets:behavior to be tested - : $seqStruct: sequence of mets:div/@ID (ordered by specificity, ascending) - : $type: return type - : returns: a weighted value for the behavior's “rank” :) -declare function local:val($test, $seqStruct, $type) { - let $vIDt := for $s at $i in $seqStruct - return if (matches($test/@STRUCTID, concat('(^| )', $s, '( |$)'))) - then math:exp10($i) - else 0 - let $vID := fn:max($vIDt) - let $vS := if ($test[@BTYPE = $type]) - then 5 - else if ($test[@LABEL = $type]) - then 3 - else if ($test[@ID = $type]) - then 1 - else 0 - - return $vS + $vID -}; (: we need a lookup function for the templating system to work :) declare variable $wdb:lookup := function($functionName as xs:string, $arity as xs:int) { diff --git a/edoc/modules/stats.xqm b/edoc/modules/stats.xqm index b1485434..ab5984a8 100644 --- a/edoc/modules/stats.xqm +++ b/edoc/modules/stats.xqm @@ -5,8 +5,6 @@ module namespace wdbs = "https://github.com/dariok/wdbplus/stats"; import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "app.xqm"; import module namespace templates = "http://exist-db.org/xquery/html-templating"; -declare namespace mets = "http://www.loc.gov/METS/"; -declare namespace mods = "http://www.loc.gov/mods/v3"; declare namespace tei = "http://www.tei-c.org/ns/1.0"; declare namespace wdbc = "https://github.com/dariok/wdbplus/config"; declare namespace wdbmeta = "https://github.com/dariok/wdbplus/wdbmeta"; @@ -24,7 +22,6 @@ declare function wdbs:projectList($admin as xs:boolean, $ed) { wdb:getEdPath($ed, true()) } catch * {()} - let $editionsM := collection($pathToEd)//mets:mets let $editionsW := collection($pathToEd)//wdbmeta:projectMD return @@ -32,51 +29,35 @@ declare function wdbs:projectList($admin as xs:boolean, $ed) { Eintrag Titel - {if ($admin = true()) then - ( - Metadaten-Datei, - verwalten + { + if ( $admin ) then ( + Metadaten-Datei, + verwalten ) else () } - {( - for $mets in $editionsM - let $name := $mets/mets:dmdSec[1]/mets:mdWrap[1]/mets:xmlData[1]/mods:mods[1]/mods:titleInfo[1]/mods:title[1] - let $metsFile := document-uri(root($mets)) - let $id := wdb:getEdPath($metsFile) - order by $id - return - - (M) {$id} - {normalize-space($name)} - {if ($admin = true()) then - ( - {$metsFile}, - verwalten - ) - else () - } - , + { for $w in $editionsW let $name := $w/wdbmeta:titleData/wdbmeta:title[1] - let $metaFile := document-uri(root($w)) - let $id := $w/@xml:id - let $pa := substring-before(substring-after($metaFile, $wdb:data), "/wdbmeta.xml") - let $padding := count(tokenize($pa, '/')) + 0.2 + , $metaFile := document-uri(root($w)) + , $id := $w/@xml:id + , $pa := substring-before(substring-after($metaFile, $wdb:data), "/wdbmeta.xml") + , $padding := count(tokenize($pa, '/')) + 0.2 order by $pa return {$id} {normalize-space($name)} - {if ($admin = true()) then ( - {xs:string($metaFile)}, - verwalten - ) - else () + { + if ( $admin ) then ( + {xs:string($metaFile)}, + verwalten + ) + else () } - )} + } }; diff --git a/edoc/modules/wdb-files.xqm b/edoc/modules/wdb-files.xqm index 9312f216..8d0da35d 100644 --- a/edoc/modules/wdb-files.xqm +++ b/edoc/modules/wdb-files.xqm @@ -12,36 +12,35 @@ xquery version "3.1"; module namespace wdbFiles = "https://github.com/dariok/wdbplus/files"; -import module namespace functx = "http://www.functx.com" at "/db/system/repo/functx-1.0.1/functx/functx.xq"; +import module namespace functx = "http://www.functx.com" at "/db/system/repo/functx-1.0.1/functx/functx.xq"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace mets = "http://www.loc.gov/METS/"; declare namespace wdbErr = "https://github.com/dariok/wdbplus/errors"; -declare namespace xlink = "http://www.w3.org/1999/xlink"; (:~ : Return the path to all Resources with a given ID : - : This function looks within metadata files, i.e. wdbmeta.xml and mets.xml, and returns all paths found. If a file has - : an xml:id but is not “registered” with its project’s metadata, it wont’t be returned. Also, this function will - : return all files; it is up to the caller to act upon this accordingly. + : This function looks within a project’s metadata file, i.e. wdbmeta.xml, and returns all paths found. If a file has no + : xml:id or has an xml:id but is not “registered” with its project’s metadata, it wont’t be returned. Also, this + : function will return all files with a given ID; it is up to the caller to act upon this accordingly. : : @param $collection as xs:string: ID of the collection in which to search : @param $id as xs:string: the ID value to be used : @return attribute()* the path attributes to the files as stored in the meta data files :) declare function wdbFiles:getFilePaths ( $collection, $id ) as attribute()* { - ( - collection($collection)//id($id)[self::meta:file]/@path, - collection($collection)//id($id)[self::meta:struct]/@xml:id, - collection($collection)//mets:file[@ID = $id]/mets:FLocat/@xlink:href + let $candidates := collection($collection)//id($id) + + return ( + $candidates[self::meta:file]/@path, + $candidates[self::meta:struct]/@xml:id ) }; (:~ : Return the absolute Path to the file identified by the path attribute : - : @param $path as attribute() an attribute node from wdbmeta or METS + : @param $path as attribute() an attribute node from wdbmeta : @return xs:anyURI :) declare function wdbFiles:getAbsolutePath ( $path as attribute() ) { diff --git a/edoc/resources/mets.xsl b/edoc/resources/mets.xsl deleted file mode 100644 index 8472698f..00000000 --- a/edoc/resources/mets.xsl +++ /dev/null @@ -1,494 +0,0 @@ - - - - - - - - - - - - - - - - - Contents - - - Inhalt - - - Parallel Views - - - Parallele Anzeige - - -
    - - -
    -
    - - - - - - - - - - - [ - - - - - - _blank - ↗opac - - ] - - - - No title found - please contact - the library - - -
    -
    - - - - - - - - -
    -
    -
    - -
    -
    - -
    -
    - - - -
    -

    - - - - - - - - -

    -
    -
      - - - -
    -
    -
    - -
    -

    - - - - - - - - -

    -
    -
      - -
    -
    -
    -
    -
    -
    - - - - - - - - -
    - - - - , - - - - - - - - - - - . - - - - : - - - - . - - - - : - - - - [ - - - - - - _blank - ↗opac - - ] - - - - - - - - - - - - - - - - - - - - ; - - - - - - - - , - - - - - - - - - - : - - - - - - ; - - - - - - - - , - - - - - - - - - - : - - - - - - - - - . - - - - - - - : - - - - - - - - - - . - - - ( - - ) - - - - - - - - - , - - - - - - - [ - - - - - - - - - - - - - - - - _blank - - - - ] - - -
    - -
    -
    - - - - - - -

    [zum Eintrag in der - Handschriftendatenbank]

    -
    - - - - ( - - ) -
    -
    -
    -
    - - - - . - - - - - - - - - - × - - - - - - - - - - - - - - - . - - - - - - - , - - - - . - - - - -
    - - - - -
    -
    -
    -
    - - - - - - - - - - -
  • - -
      - -
    -
  • -
    - -
  • - - - - - - - - -
      - - bd - - - display:none; - - - - -
    -
  • -
    - -
  • - - - - - - - _blank - - - _top - - - display2 - - - - -
  • -
    - -
  • - - - - ?id= - - - - -
  • -
    - -
    -
    - -
    \ No newline at end of file diff --git a/edoc/resources/xsl/tei-introduction.xsl b/edoc/resources/xsl/tei-introduction.xsl index c89ed43d..2b2bdb80 100644 --- a/edoc/resources/xsl/tei-introduction.xsl +++ b/edoc/resources/xsl/tei-introduction.xsl @@ -1,18 +1,21 @@ - - - - - + + + + + + - - - - diff --git a/edoc/resources/xsl/tei-transcript.xsl b/edoc/resources/xsl/tei-transcript.xsl index 5a0255d7..f43d5fe5 100644 --- a/edoc/resources/xsl/tei-transcript.xsl +++ b/edoc/resources/xsl/tei-transcript.xsl @@ -1,5 +1,5 @@ diff --git a/edoc/rest/rest-coll.xql b/edoc/rest/rest-coll.xql index aa7ef05c..4aab26f8 100644 --- a/edoc/rest/rest-coll.xql +++ b/edoc/rest/rest-coll.xql @@ -11,7 +11,6 @@ import module namespace xstring = "https://github.com/dariok/XStringUtils" declare namespace http = "http://expath.org/ns/http-client"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace mets = "http://www.loc.gov/METS/"; declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; declare namespace rest = "http://exquery.org/ns/restxq"; declare namespace tei = "http://www.tei-c.org/ns/1.0"; @@ -467,20 +466,16 @@ function wdbRc:getCollectionNavHTML ( $ed as xs:string, $externalModel as map(*) let $html := try { - if( ends-with($model?infoFileLoc, 'wdbmeta.xml') ) - then - let $struct := wdbRc:getCollectionNavXML($ed) - , $xsl := if ( wdb:findProjectFunction($model, "wdbPF:getNavXSLT", 0) ) - then (wdb:getProjectFunction($model, "wdbPF:getNavXSLT", 0))($model) - else if ( doc-available($model?pathToEd || '/resources/nav.xsl') ) - then xs:anyURI($model?pathToEd || '/resources/nav.xsl') - else if ( doc-available($wdb:data || '/resources/nav.xsl') ) - then xs:anyURI($wdb:data || '/resources/nav.xsl') - else xs:anyURI($wdb:edocBaseDB || '/resources/nav.xsl') - - return transform:transform($struct, doc($xsl), $params, $attributes, ()) - else - transform:transform(doc($model?infoFileLoc), doc($model?pathToEd || '/mets.xsl'), $params) + let $struct := wdbRc:getCollectionNavXML($ed) + , $xsl := if ( wdb:findProjectFunction($model, "wdbPF:getNavXSLT", 0) ) + then (wdb:getProjectFunction($model, "wdbPF:getNavXSLT", 0))($model) + else if ( doc-available($model?pathToEd || '/resources/nav.xsl') ) + then xs:anyURI($model?pathToEd || '/resources/nav.xsl') + else if ( doc-available($wdb:data || '/resources/nav.xsl') ) + then xs:anyURI($wdb:data || '/resources/nav.xsl') + else xs:anyURI($wdb:edocBaseDB || '/resources/nav.xsl') + + return transform:transform($struct, doc($xsl), $params, $attributes, ()) } catch * {

    Error transforming meta data file {$model?infoFileLoc} to navigation HTML:
    {$err:description}

    } diff --git a/edoc/rest/rest-files.xql b/edoc/rest/rest-files.xql index 0884bb41..3d7fbb2d 100644 --- a/edoc/rest/rest-files.xql +++ b/edoc/rest/rest-files.xql @@ -379,23 +379,19 @@ declare %rest:query-param("view", "{$view}", "") function wdbRf:getResourceView ($id as xs:string, $type as xs:string, $view as xs:string*) { let $model := wdb:populateModel($id, $view, map {}) - - (: This mechanism can only be used with wdbmeta. A METS-only project will return an error :) - let $wdbmeta := if (ends-with($model?infoFileLoc, "wdbmeta.xml")) - then doc($model?infoFileLoc) - else () + , $wdbmeta := doc($model?infoFileLoc) (: by definition in wdbmeta.rng and in analogy to the behaviour of view.html: $type maps to process/@target, $view is used as a parameter. If there is only one process for $type, $view will be handed over as a parameter; if there are multiple processes for $type, $view will be used to select via process/@view. If the are multiple processes but none with the given $view, this is an error :) let $processes := $wdbmeta//meta:process[@target = $type] - let $process := if (count($processes) = 1) - then ($processes[1]) - else ($processes[@view = $view]) + let $process := if ( count($processes) = 1 ) + then $processes[1] + else $processes[@view = $view] - let $status := if ($wdbmeta = ()) - then (500, "no wdbmeta found for " || $id || " (project with mets.xml?)") + let $status := if ( $wdbmeta = () ) + then (500, "no wdbmeta found for " || $id || "!") else if (not($processes)) then (404, "no process found for target type " || $type) else if (not($process)) From bc71eb6177055e2d4e469571e877f2a066138392 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Thu, 18 Jan 2024 00:11:23 +0100 Subject: [PATCH 11/36] Entities: only look for list* in text for now, we ignore standOff as this may return many result per collection for the future, device a way to have magic file names (see #99 #183) --- edoc/modules/function.xqm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/edoc/modules/function.xqm b/edoc/modules/function.xqm index a9755fb4..51f9bfdb 100644 --- a/edoc/modules/function.xqm +++ b/edoc/modules/function.xqm @@ -58,15 +58,20 @@ declare function wdbfp:populateModel ( $id as xs:string?, $ed as xs:string, $p a else if ( request:exists() and request:get-uri() => ends-with('/entity.html') ) then let $regFile := switch ( $q ) case "per" - return collection(wdb:getEdPath($ed, true()))//*:listPerson + return collection(wdb:getEdPath($ed, true()))//*:listPerson[ancestor::*:text] case "org" - return collection(wdb:getEdPath($ed, true()))//*:listOrg + return collection(wdb:getEdPath($ed, true()))//*:listOrg[ancestor::*:text] + case "pla" + return collection(wdb:getEdPath($ed, true()))//*:listPlace[ancestor::*:text] default return "" let $entryEd := $regFile/id($id) + , $pathToEd := if ( $ed = "" ) + then $wdb:data + else wdb:getEdPath($ed, true()) (: TODO: this only uses a project specific list* file; we want ot use (or at least support) globals files :) - return map { "entry": $entryEd, "id": $id, "ed": $ed } + return map { "entry": $entryEd, "id": $id, "ed": $ed, "pathToEd": $pathToEd } else if ( $id = "" ) then (: no ID: related to a project :) let $pathToEd := if ( $ed = "" ) @@ -145,7 +150,6 @@ declare %templates:default("p", "") %templates:default("id", "") %templates:default("ed", "") - %templates:wrap function wdbfp:start ( $node as node(), $model as map(*), $id as xs:string, $ed as xs:string, $p as xs:string, $q as xs:string ) as item()* { let $newModel := wdbfp:populateModel($id, $ed, $p, $q) From f59399432200a088524ba48f820f79a4f5a61e7e Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Thu, 18 Jan 2024 00:34:28 +0100 Subject: [PATCH 12/36] use an XSLT to display entity data To do: extend XSLT to return useful results Based on ebda1d1 which somehow got lost Closes #183 #110 #99 --- edoc/entity.html | 14 +- edoc/modules/entity.xqm | 241 ++----------------------------- edoc/resources/xsl/tei-index.xsl | 12 ++ 3 files changed, 31 insertions(+), 236 deletions(-) create mode 100644 edoc/resources/xsl/tei-index.xsl diff --git a/edoc/entity.html b/edoc/entity.html index 3eee12b9..c7e68916 100644 --- a/edoc/entity.html +++ b/edoc/entity.html @@ -1,11 +1,5 @@ - -
    - -
    -

    Kilroy was here

    -
    +
    +
    +

    Kilroy was here

    - \ No newline at end of file +
    diff --git a/edoc/modules/entity.xqm b/edoc/modules/entity.xqm index 241837d1..50ebb93b 100644 --- a/edoc/modules/entity.xqm +++ b/edoc/modules/entity.xqm @@ -1,239 +1,28 @@ -xquery version "3.0"; -(: erstellt 2016-07-26 Bearbeiter:DK Dario Kampkaspar :) +xquery version "3.1"; module namespace wdbe = "https://github.com/dariok/wdbplus/entity"; import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "app.xqm"; import module namespace console = "http://exist-db.org/xquery/console"; -declare namespace tei = "http://www.tei-c.org/ns/1.0"; +declare namespace tei = "http://www.tei-c.org/ns/1.0"; (: $id ID-String of the entity to be displayed – must be globally unique - $ed ID of the project from which specific information shall be drawn - $reg a file containing a project specific tei:list*, if such information is requested :) -declare function wdbe:getEntity($node as node(), $model as map(*), $id as xs:string, $ed as xs:string?, $reg as xs:string?, $xsl as xs:string?) as map(*) { - (: TODO check calls; entry ID and project ID should be the only necessary parameters :) - (: TODO support project specific views :) + $ed ID of the project from which specific information shall be drawn :) +declare function wdbe:getEntity ( $node as node(), $model as map(*), $ent as xs:string, $ed as xs:string ) as map(*) { + let $edPath := wdb:getEdPath($ed, true()) + , $entry := collection($edPath || "/index")/id($ent) - let $edPath := wdb:getEdPath($ed) - let $regFile := $edPath || '/' || $reg - let $testPath := $wdb:data || '/' || $ed || '/' || $reg - let $entryEd := doc($wdb:data || '/' || $ed || '/' || $reg)/id($id) - (: TODO: this only uses a project specific list* file; we want ot use (or at least support) globals files :) - - (: let $t := console:dump("default", ("edPath", "regFile", "testPath", "entryEd")) :) - return map { "entry": $entryEd, "id": $id, "ed": $ed } -}; - -(: create the heading for the HTML snippet; 2016-08-17 DK :) -declare function wdbe:getEntityName($node as node(), $model as map(*)) { - let $entryEd := $model("entry") - return

    { - typeswitch ($entryEd) - case element(tei:person) - return if ($entryEd/tei:persName[@type='index']) - then wdbe:passthrough($entryEd/tei:persName[@type='index'], $model) - else wdbe:shortName($entryEd/tei:persName[1]) - case element(tei:bibl) - return wdbe:shortTitle($entryEd, $model) - case element(tei:place) - return normalize-space($entryEd/tei:placeName) - default - return name($entryEd[1]) - }

    + return map { "entry": $entry, "ent": $ent, "ed": $ed, "pathToEd": $edPath } }; -declare function wdbe:getEntityBody($node as node(), $model as map(*)) { - let $ent := $model("entry") +declare function wdbe:getEntityBody( $node as node(), $model as map(*) ) as element() { + let $xsl := if ( doc-available($model?pathToEd || "/resources/tei-index.xsl") ) + then doc($model?pathToEd || "/resources/tei-index.xsl") + else doc("/db/apps/edoc/resources/tei-index.xsl") + , $result := transform:transform($model?entry, $xsl, ()) - return wdbe:transform($ent, $model) -}; - -(: TODO replace by proper XSLT and the usual means of project specifics; 2019-08-23 DK :) -declare function wdbe:transform($node, $model as map(*)) as item()* { - typeswitch ($node) - case text() return $node - case element(tei:person) return - - - - - - {wdbe:passthrough($node, $model)} -
    - - - - - Person
    - case element(tei:org) return - - - - - - {wdbe:passthrough($node, $model)} -
    - - - - - Organisation / Körperschaft
    - case element(tei:persName) return wdbe:persName($node, $model) - case element(tei:birth) return wdbe:bd($node, $model) - case element(tei:death) return wdbe:bd($node, $model) - case element(tei:floruit) return wdbe:bd($node, $model) - case element(tei:listBibl) return wdbe:listBibl($node, $model) - case element(tei:note) return wdbe:note($node, $model) - case element(tei:bibl) return - if ($node/ancestor::tei:person or count($node/ancestor::tei:place)>0) (: Literatur zu anderen Entitäten: Kurzausgabe :) - then wdbe:listBiblBibl($node, $model) - else wdbe:bibl($node) - case element(tei:name) return - if ($node/parent::tei:abbr) - then {$node} - else wdbe:passthrough($node, $model) - case element(tei:title) return - if ($node/parent::tei:abbr) - then {string($node)} - else wdbe:passthrough($node, $model) - case element(tei:placeName) return - if ($node/ancestor::tei:person) - then wdbe:shortPlace($node) - else wdbe:placeName($node) - case element(tei:place) return {wdbe:passthrough($node, $model)}
    - case element(tei:idno) return wdbe:idno($node) - case element(tei:occupation) return - - { if ( $node/@type ) then "Titel" else "Beruf" } - { normalize-space($node) } - - case element(tei:orgName) return wdbe:persName($node, $model) - -(: default return wdbe:passthrough($node):) - (:default return concat("def: ", name($node)):) - default return $node -}; - -declare function wdbe:passthrough($nodes as node()*, $model) as item()* { - if (count($nodes) > 1 or $nodes instance of text()) - then for $node in $nodes return wdbe:transform($node, $model) - else for $node in $nodes/node() return wdbe:transform($node, $model) -}; - -(: die folgenden neu 2016-08-16 DK :) -declare function wdbe:persName($node, $model) { - - Name - { normalize-space($node) } - -}; - -declare function wdbe:names($node) { - - { - typeswitch($node) - case element(tei:forename) return "Vorname" - case element(tei:surname) return "Nachname" - case element(tei:nameLink) return "Prädikat" - case element(tei:roleName) return "Amt/Titel" - case element(tei:genName) return "" - case element(tei:addName) return wdbe:addName($node) - default return local-name($node) - } - {$node/text()} - -}; - -declare function wdbe:addName($node) as xs:string { -let $resp := - if ($node/@type = "toponymic") then 'toponymischer Beiname' - else if ($node/@type = 'cognomen') then 'Cognomen' - else "Beiname" - - return $resp -}; - -declare function wdbe:bd($node, $model) { - - { - typeswitch($node) - case element(tei:birth) return "geb." - case element(tei:death) return "gest." - default return "lebte" - } - {wdbe:passthrough($node, $model)} - -}; - -declare function wdbe:listBibl($node, $model) { - - Literatur -
      { - for $bibs in $node return wdbe:passthrough($bibs, $model) - }
    - -}; - -(: Kurztitelausgaben in einer listBibl; 2016-08-17 DK :) -declare function wdbe:listBiblBibl($node, $model) { - if ($node/@ref) then - let $id := substring-after($node/@ref, '#') - let $entry := collection(concat('/db/', $model('ed')))/id($id) -(: let $ln := $wdb:edocBaseURL || '/entity.html?id=' || $id || '&ed=' || $model('ed'):) - let $ln := "javascript:show_annotation('" || $model('ed') || "', '/db/" || $model('ed') || "/register/bibliography.xml', '" - || $wdb:edocBaseDB || "/resource/bibl.xsl', '" || $id || "', 0, 0);" - return
  • {wdbe:passthrough($entry/tei:abbr, $model)}{string($node)}
  • - else - let $link := $node/tei:ref/@target - let $text := $node/tei:ref/text() - return
  • {$text}
  • -}; - -(: Ausgabe einer bibliographischen Langangabe; 2016-08-17 DK :) -declare function wdbe:bibl($node) { - (: TODO erweitern für strukturierte Angaben! :) -

    {$node/node()[not(self::tei:abbr)]}

    -}; - -(: zur Ausgabe von Kurztiteln eines Buches; 2016-08-17 DK :) -(: $node ein Element tei:bibl - Ausgabe formatierter Kurztitel :) -declare function wdbe:shortTitle($node, $model) { - (: Kurztitel: Verarbeitung von tei:abbr. Evtl. enthaltenes tei:name in Kapitälchen, tei:title kursiv :) - if ($node/tei:abbr) then wdbe:passthrough($node/tei:abbr, $model) - else substring($node, 1, 50) -}; - -declare function wdbe:shortName($node) { - { - if ($node/tei:name) then $node/tei:name - else - let $tr := string-join(($node/tei:surname, $node/tei:forename), ", ") - let $add := if ($node/tei:addName) then concat(' (', $node/tei:addName, ')') else "" - return concat($tr, ' ', $node/tei:nameLink, $add) - } -}; - -declare function wdbe:note($node, $model) { - Anmerkung{wdbe:passthrough($node, $model)} -}; - -declare function wdbe:shortPlace($node) { - (: TODO tei:head oder tei:label als Standardwert nutzen, falls vorhanden :) - (: TODO ggfs. sind hier andere Arten zu berücksichtigen (tei:geogName) :) - {replace($node/tei:placeName[1]/tei:settlement, '!', ', ')} -}; - -declare function wdbe:placeName($node) { - (: TODO anpassen an ausführlichere Angaben :) - if ($node/tei:country) - then (Name{replace($node/tei:settlement, '!', ', ')}, - Land{string($node/tei:country)}) - else Name{replace($node/tei:settlement, '!', ', ')} -}; - -(: neu 2017-05-22 DK :) -declare function wdbe:idno($node) { - Normdaten-ID{$node} + return if ( count($result) = 1 ) + then $result + else

    Keine Informationen gefunden.

    }; diff --git a/edoc/resources/xsl/tei-index.xsl b/edoc/resources/xsl/tei-index.xsl new file mode 100644 index 00000000..14fd3061 --- /dev/null +++ b/edoc/resources/xsl/tei-index.xsl @@ -0,0 +1,12 @@ + + + + + + + + From a19cd57a38e83a1377d1a240435433afa2c328a9 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Thu, 18 Jan 2024 00:35:15 +0100 Subject: [PATCH 13/36] Addins: main module must return one or more elements --- edoc/modules/addin.xqm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/edoc/modules/addin.xqm b/edoc/modules/addin.xqm index 866b1916..606dc0fe 100644 --- a/edoc/modules/addin.xqm +++ b/edoc/modules/addin.xqm @@ -11,10 +11,10 @@ import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at " declare namespace wdbadd = "https://github.com/dariok/wdbplus/addins"; (: load the main XQuery module for the requested addin. It is mandatory these implement wdbadd:main($map as map(*)) :) -declare function wdbAddinMain:body($node as node(), $model as map(*)) { +declare function wdbAddinMain:body ( $node as node(), $model as map(*) ) as element()+ { let $addinName := substring-before(substring-after(request:get-uri(), 'addins/'), '/') - let $path := $wdb:edocBaseDB || "/addins/" || $addinName || "/addin.xqm" - let $map := map { "location-hints": $path } + , $path := $wdb:edocBaseDB || "/addins/" || $addinName || "/addin.xqm" + , $map := map { "location-hints": $path } let $module := try { load-xquery-module("https://github.com/dariok/wdbplus/addins", $map) From 9c781f4ac4b48c49469e7f5d592e26730b7aa5b0 Mon Sep 17 00:00:00 2001 From: Dario Kampkaspar Date: Thu, 18 Jan 2024 00:38:51 +0100 Subject: [PATCH 14/36] remove copy of github Wiki a more in-depth documentation is planned Cf. # 158 --- doc/Basic-collection-structure.md | 80 ------------------- doc/CSS-files-and-classes.md | 48 ----------- doc/Global-Configuration.md | 35 -------- doc/Global-variables.md | 35 -------- doc/Home.md | 15 ---- ...de-an-image-viewer-via-projectSpecifics.md | 68 ---------------- doc/JS-functions.md | 36 --------- doc/List-of-namespaces.md | 18 ----- doc/Main-HTML-files.md | 46 ----------- doc/Main-files.md | 18 ----- ...ing,-and-identifying-projects-and-files.md | 22 ----- doc/Project-specifics.md | 48 ----------- doc/Project.xqm.md | 24 ------ doc/REST-endpoints.md | 46 ----------- doc/Request-parameters.md | 15 ---- doc/Writing-scripts-to-display-XML-files.md | 7 -- doc/XQ-functions.md | 16 ---- doc/_Sidebar.md | 23 ------ doc/start.html.md | 38 --------- doc/view.html.md | 7 -- doc/wdbmeta.xml.md | 39 --------- 21 files changed, 684 deletions(-) delete mode 100644 doc/Basic-collection-structure.md delete mode 100644 doc/CSS-files-and-classes.md delete mode 100644 doc/Global-Configuration.md delete mode 100644 doc/Global-variables.md delete mode 100644 doc/Home.md delete mode 100644 doc/Include-an-image-viewer-via-projectSpecifics.md delete mode 100644 doc/JS-functions.md delete mode 100644 doc/List-of-namespaces.md delete mode 100644 doc/Main-HTML-files.md delete mode 100644 doc/Main-files.md delete mode 100644 doc/Naming,-finding,-and-identifying-projects-and-files.md delete mode 100644 doc/Project-specifics.md delete mode 100644 doc/Project.xqm.md delete mode 100644 doc/REST-endpoints.md delete mode 100644 doc/Request-parameters.md delete mode 100644 doc/Writing-scripts-to-display-XML-files.md delete mode 100644 doc/XQ-functions.md delete mode 100644 doc/_Sidebar.md delete mode 100644 doc/start.html.md delete mode 100644 doc/view.html.md delete mode 100644 doc/wdbmeta.xml.md diff --git a/doc/Basic-collection-structure.md b/doc/Basic-collection-structure.md deleted file mode 100644 index 63fa11b0..00000000 --- a/doc/Basic-collection-structure.md +++ /dev/null @@ -1,80 +0,0 @@ -## Intro - -While the app was built with the possibility in mind to adapt it to different local needs and data structures, there is a default structure. While the app tries hard to figure out the correct structure by itself, this may fail. If you use a structure different from the default, you may need to adapt several scripts and keep that in mind when updating and upgrading. - -## Default Structure - -The default setup install the app into the collection `/db/apps/edoc` of eXist. It contains the [[main HTML files|main-html-files]] and the everything else the app needs to run. It is also home to several subcollections: - - edoc - ├─admin - ├─data - ├─global - ├─include - ├─modules - ├─resources - ├─rest - ├─schema - ├─templates - ├─(annotations) - ├─(doc) - -* `admin`, as the name suggests, contains a few scripts to help admins keep an overview of the projects within this installation (more are to be added in later versions). -* `data` is where the different projects go as subcollections. While it can be empty, it may contain [[start.xml|main-files#start]] and should contain [[wdbmeta.xml]] to give a global start page or set global metadata. -* `global` is where globally available or root level content is stored, e.g. `index.html`. **This is the only place in the app root where users should (and need to) make changes** -* `include` contains recent versions of related projects, namely the schema for [[wdbmeta.xml|main-files#wdbmeta]] and a collection of XSL/XQuery functions to deal with strings (extending the normal XPath string functions). -* `modules` is where the main global scripts go. -* `resources` contains global resources such as default XSLTs, global CSS and JavaScript. -* `rest` contains scripts for the RESTful interface. While it is possible for users to change these scripts, it is recommended to instead add scripts instead of changing existing ones. -* `schema` contains schema files for global files other than `wdbmeta.xml` (currently, this is only `config.xml`). -* `templates` contains the rump HTML files used for the templating system. While it is possible to change these files, most changes can better be done by using [[project specific layout and functions|project-specifics]]. The standard files here may be overwritten by an update. -* `annotation` and `doc` are not in use yet but are to be considered 'reserved' as they will be used for internal functions in upcoming releases. - -Except for `global`, there are no user servicable parts in these collections. All changes may be overwritten by an update or upgrade. Instead, use the [[configuration options|global-configuration]] and [[project specific layout and functions|project-specifics]] to adapt functions and layout to your needs. -Should you really require a change in one of these subcollections, consider opening an issue instead so this can be changed to an option that can be set on a project or instance level. - -## Non-default structures - -### projects as subcollections of `edoc` -It is possible to deviate from the general structure. For instance, one might want to forego the `data` subcollection and store all projects as a subcollection within `edoc` itself. This is possible and should be recognized correctly by all scripts; however, as the main call to view a page is via `view.html` and an ID, this is not strictly necessary. Should you need it e.g. to maintain a stable URL for the source XML/XSLT/etc. files, consider using a reverse proxy instead, especially if you run into problems reading and displaying files. - -### different name than `edoc` -It is also possible to name the collection other than `edoc`. In fact, this feature will be put to use in a later release as part of the possibility to have both _publication_ and _workbench_ [[roles|server-roles]] run on the same eXist server. All scripts should be able to figure out the correct name. - -### as a subcollection of `db` instead of `/db/apps` -This is possible, too, and should not require additional changes. If you run into problems with the URLs generated by the scripts, automatic resolution of the basic URL might have failed. Consider setting the appropriate option in [[config.xml|global-configuration]] - -### port 80 and/or no mention of 'exist' in URL -If you want to have a URL without port 8080 and the 'exist' part, so 'http://example.com/edoc/view.html' rather than 'http://example.com:8080/exist/apps/edoc', you need to adjust eXist's configuration. Depending on the way you deployed eXist, the port configuration can be found e.g. in the Jetty config files (e.g. `tools/jetty/etc/jetty-http.xml`). In eXist's main `controller-config.xml` change - - - -to - - - - -and in `exist-webapp-context.xml`, change - - /exist - -to - - / - -If you cannot access the collection or any of the builtin apps, e.g. Dashboard or monex, the “portal” might be blocking Jetty’s `/`-context. Try editing `tools/jetty/webapps/portal/WEB-INF/jetty-web.xml` and change the context to something different than `/` or `/exist`, e.g. `/portal`. -Most likely, Dashboard etc. will not be immediately accessible after the splash screen (which, on a production server, should not be a problem) but need to be accessed manually under `$server/apps/dashboard/index.html`. -(see https://sourceforge.net/p/exist/mailman/message/35823429/) - -Another way of doing this – and maybe a better one if this is available to you – is to use a reverse proxy to point to `exist/apps/edoc`. Depending on your setup, you may lose access to eXide or monex. To solve this, add the following to your `controller.xql` before any redirect that checks for `html`: - - - - - - - -and alike for monex. - -### data collection other than `data` -No problems are expected here as the scripts should be able to figure out the correct paths. As with all the other cases, please report any issues you may find. \ No newline at end of file diff --git a/doc/CSS-files-and-classes.md b/doc/CSS-files-and-classes.md deleted file mode 100644 index 0fb27ec1..00000000 --- a/doc/CSS-files-and-classes.md +++ /dev/null @@ -1,48 +0,0 @@ -## global CSS files - -All these files define global CSS rules. While it is possible to change them -directly, the preferred way to go is via -[[project specific files|project-specifics]] as these global files may be -replaced during an update or upgrade. - -|file|rules| -|--|--| -|resources/css/wdb.css|basic layout of any page – this one is loaded first by all pages in the templating system| -|resources/css/function.css| basic layout for function pages (small aside left, wide main right)| -|[[resources/css/view.css\|css-files-and-classes#viewcss]]| main layout file for _header_, _nav_, _main_ and _aside_ in of view.html| -|resources/css/search.css|additional layout for search page and results| -|[[resources/css/start.css\|css-files-and-classes#startcss]]| additional layout for `start.html`| -|[[resources/css/footnotes.css\|css-files-and-classes#footnotescss]]| additional layout for footnotes| - -## overview of classes -### view.css -|class / rule / id|intended for| -|--|--| -|header|the horizontal header at the top| -|main|main text area to the left| -|nav|(global) navigation| -|#wdbRight|the right hand side| -|#fac|container for facsimile (on the right)| -|#facsimile|iframe to load facsimiles| -|#wdbShowHide|central vertical bar to adjust size| -|#wdbContent|container for text in _main_| -|footer|the footer below a text (container)| -|span.dispOpts|options in the header (usually to the right)| -|#marginalia_container|container for marginalia| - -### footnotes.css -|class / rule / id|intended for| -|--|--| -|div.footnotes|container for all footnotes| -|#kritApp, #FußnotenApparat, #critApp, #apparatus|one group of notes| -|hr.fnRule|footnote rule (above)| -|a.fn_number|footnotes's identifier in the main text| -|.fn_number_app|footnotes's identifier within the footnote| -|span.footnoteText|footnote's text (usually after the identifier)| - - -### start.css -|class / rule / id|intended for| -|--|--| -|#toc_title|title for the table of contents| -|div.startImage|an image to be displayed on the right| \ No newline at end of file diff --git a/doc/Global-Configuration.md b/doc/Global-Configuration.md deleted file mode 100644 index d76b4aae..00000000 --- a/doc/Global-Configuration.md +++ /dev/null @@ -1,35 +0,0 @@ -# Global Configuration - -All global configuration options, i.e. those that affect how the app works, are set in `$approot/config.xml`. -If you use the [[default setup|basic-collection-structure#default-structure]], `$approot := /db/apps/edoc`. - -## Settings in `config.xml` -### meta -- `name` – a long title for this instance of the app -- `short` – a short title, e.g. to be used in `html:title` - -### role -- `type` – the [[role|server-roles]] of this instance -- `peer` – for a _workbench_, this points to the House of Lords, i.e. the _publication_ instance - -See the documentation of the [[server roles|server-roles]] for more detail. - -### params -- `param` – a key-value pair for global parameters that are available in all scripts and will be passed on to the model. - -Not really implemented yet but planned for version 2.0. - -### server -A full URL, reachable from the outside, to be used if the automatic resolution in `app.xql` does not work or needs to be overwritten. This needs to point to the collection containg `config.xml` (thus, the standard setting would be `http://yourexist.tld/exist/apps/edoc/`)– a setting here overwrites the automatic processing and will be globally available as `$wdb:edocBaseURL`, the server's name (or IP) as `$wdb:server`. -While all standard scripts should be able to figure this out correctly, certain setups may cause problems. - -Scripts invoked via RESTXQ will not be able to use automatic resolution – if you need the base URL from within a RESTXQ endpoint (e.g. for the IIIF image descriptor), you MUST set this option. - -### rest -A full URL which is the base for REST calls. This will be used by JavaScript functions, e.g. to load navigation or to insert/retrieve annotations. This must be set if the rest endpoint is not available under the usual location (i.e. `http://yourexist.tld/exist/restxq/edoc/` for the standard setup). This might be the case if you hid parts of the standard path by eXist's configuration or reverse proxying. - -NB: this needs to include the “edoc/” part - -## Projects -In order to create a project, you have to create a collection for it and make the most important settings in `wdbmeta.xml`. The initial settings can be done using `admin/admin.html` (New Project). -After that, you have to add at least one view and an entry for every file you want to access. \ No newline at end of file diff --git a/doc/Global-variables.md b/doc/Global-variables.md deleted file mode 100644 index b1809303..00000000 --- a/doc/Global-variables.md +++ /dev/null @@ -1,35 +0,0 @@ -# Global variables -## $model - -In several instances, most prominently in `app.xqm`, a parameter called `$model` is passed to functions. -This is part of eXist's templating system and has been used in several locations to allow for uniform distribution of common parameters. - -`$model` always is a `map(*)`. The most important parameters MUST be the same in all instances. This means: - -| parameter | contents | -|--|--| -| `ed` | the ID of the Collection (= `@xml:id` of `meta:projectMD`) | -| `fileLoc` | full path to the current Resource | -| `id` | a file's ID (e.g. file to be displayed) | -| `infoFileLoc` | full path to `wdbmeta.xml` | -| `pathToEd` | the full DB-Path to the Collection (= `substring-before($infoFileLoc, '/wdbmeta.xml')`) | -| `projectFile` | path to Project’s `project.xqm`| -| `projectResources` | path to Project’s resource folder (= `substring-before($projectFile, 'project.xqm') || 'resources'`)| -| `title` | the title of the file or project | -| `view` (app.xqm only) | the `view` query parameter as pass in the call to `view.html` | -| `xslt` (app.xqm only) | full path to the XSLT to be used for transformation | -| `p` (function.xml only) | all values from `p` query parameter parsed into a `map(*)` | - - -## parameters in `wdb` namespace -The [[wdb namespace|list-of-namespaces]] contains several global parameters that can be accessed from every script that imports `app.xql`: - -|name|contents| -|--|--| -|`$wdb:edocBaseDB`| same as `$config:root` – the path to where the application is installed within `/db/`.| -|`$wdb:configFile`| the (parsed) config file (`{$wdb:edocBaseDB}/config.xml`).| -|`wdb:data`| the path to the data collection. It is assumed that this is the top collection with a `wdbmeta.xml` file.| -|`wdb:server`| the server's address including protocol and port – if automatic resolution does not work, set it manually in [[config.xml\|global-configuration]].| -|`$wdb:edocBaseURL`| the full URL to the app's root or the current subcollection.| -|`$wdb:role`| the [[role\|server-roles]] of this instance.| -|`$wdb:peer`| this instance's peer, if it is a workbench.| diff --git a/doc/Home.md b/doc/Home.md deleted file mode 100644 index c668592f..00000000 --- a/doc/Home.md +++ /dev/null @@ -1,15 +0,0 @@ -Welcome to the wdbplus wiki! - -To get started, please refer to the information in `project.md`. - -Some basic concepts etc. are to be documented here. Until there is a more definite documentation included within the app itself, this is the place for doc to go. It may also serve as a stable target for documentation of older releases. - -Your point of entry should be [[global-configuration]] which introduces you to the most important settings and caveats. - -If you want to know more about the structure of collections within the app and what you can change, please have a look at [[Basic Collection Structure|basic-collection-structure]]. This page also contains information about settings to change when you want to use a different setup, e.g. place the app outside of `/db/apps`. - -An overview of how projects can be customized and the app's configuration options, see [[project-specifics]] as well as [[wdbmeta.xml]] for project metadata. - -Functions you can use are listed in [[the list of JavaScript functions|js-functions]] and [[the list of XQuery functions|xq-functions]]. - -To learn about what the most important files in this app do, consult [[the list of main HTML files|main-html-files]] and [[the list of other main files|main-files]]. \ No newline at end of file diff --git a/doc/Include-an-image-viewer-via-projectSpecifics.md b/doc/Include-an-image-viewer-via-projectSpecifics.md deleted file mode 100644 index 39da0500..00000000 --- a/doc/Include-an-image-viewer-via-projectSpecifics.md +++ /dev/null @@ -1,68 +0,0 @@ -As an example how to use projectSpecifics and as a how-to for embedding a viewer, we will have a look at how to include the OpenSeaDragon viewer in your project or instance. - -1. Images are usually displayed to the right. So we need to include the viewer in the right part of `view.html`, which is the element `aside` (on the basic page layout cf. [[main-html-files]]). To include the necessary files, we will create a footer here. A globally defined footer will live in `edoc/resource/rightFooter.html` while a project specific footer will be located in `edoc/data/yourProject/resource/projectRightFooter.html` or defined by a function `wdbPF:getProjectRightFooter`. -1. Create a JS file `osdviewer.js` for all functions necessary for the viewer in `edoc/resource` or ``edoc/data/yourProject/resource`: - - $.holdReady(true); - var viewer = OpenSeadragon({ - preserveViewport: true, - visibilityRatio: 1, - minZoomLevel: 1, - defaultZoomLevel: 1, - id: "fac", - sequenceMode: true, - tileSources: [] - }); - - id = $("meta[name='id']").attr("content"); - rest = $("meta[name='rest']").attr("content"); - $.get(rest + "resource/iiif/" + id + "/images", function(data){viewer.open(data);}); - - viewer.addHandler('page', function(source, page, data){ - $('#pag' + (source.page + 1))[0].scrollIntoView(); - }); - viewer.addHandler('open', function() { $.holdReady(false); }); - -1. In this example, we create the HTML file with only one line: - - - - Adjust the path in `@src` to point to where you stored the JS in the step before. -1. In a project’s `project.xqm` (or the global `project.xqm` for those projects without their own), load the main OpenSeadragon JS. Change `wdbPF:getProjectFiles` so it looks similar to this (of course you should keep `link` or `script` elements you already added): - - declare function wdbPF:getProjectFiles ( $model as map(*) ) as node()* { - ( - , -