Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1fc0c61
adds XSLT for generating a SEED config for media type transformations
lueck May 19, 2026
5129505
adds chained transformation correctly to libraries
lueck May 22, 2026
ee59912
supports the 4 compile time parameters required for media-type
lueck May 22, 2026
e93763c
fixes typo
lueck May 22, 2026
fae955a
makes test more robust against changes in library
lueck Jun 4, 2026
8e9adc2
adds sample chaining to plain text output as test case
lueck Jun 4, 2026
14dccd1
uses saxon configuration file for testing
lueck Jun 4, 2026
b65e26c
adds tests for the plain SEED configuration
lueck Jun 4, 2026
fae7172
adds test for chaining with dependencies in chained stylesheet
lueck Jun 4, 2026
a15f8f7
makes tests for SEED configuration generation pass again
lueck Jun 4, 2026
c6853c6
adds command line equivalent for debugging
lueck Jun 4, 2026
47e972f
removes debugging messages
lueck Jun 4, 2026
10b6ddb
updates the documentation of SEED config generation
lueck Jun 4, 2026
c584128
merge SEED configurations in JSON format and include it into package
lueck Jun 4, 2026
89f71f6
adds named template and function as entry points for generating config
lueck Jun 9, 2026
950ddf9
XSLT for making chained configs from JSON configs
lueck Jun 9, 2026
298a5e3
refactoring to prepare merging of document and chained XSLT
lueck Jun 9, 2026
415fd73
adds regression test for merging SEED JSON configurations
lueck Jun 9, 2026
5a20212
generate configuration for the chained testing XSLT
lueck Jun 9, 2026
8ffaee3
adds a regression test for the testing chaining with tei2txt.xsl
lueck Jun 9, 2026
d6d28c5
assembles a chained XSLT for testing on SEED
lueck Jun 9, 2026
d4505a1
exclude testing material
lueck Jun 9, 2026
cd628bb
adds a parameter that for testing purpose only
lueck Jun 10, 2026
f834f25
makes chain.xsl work and pass tests
lueck Jun 10, 2026
896cea5
make a package of testing resources for deployment on SEED
lueck Jun 10, 2026
9409812
make YAML config for SEED from merged JSON configurations
lueck Jun 10, 2026
509acac
reflects recent change of names of build artifacts
lueck Jun 10, 2026
c48ab48
report changes in 0.4.11
lueck Jun 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changes

## 0.4.11

- adds utilities for generating SEED config for chained transformations (fixes issue #20)
- adds a testing package for SEED with chained transformation

## 0.4.10

- adds saxon config for SEED with assertions enabled (fixes issue #18)
Expand Down
38 changes: 38 additions & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
<antcall target="test-test-post-proc-call.xsl"/>
<antcall target="test-xsl-uri-templates-query-parameters.xsl"/>
<antcall target="test-xsl-uri-templates-path-parameters.xsl"/>
<!-- testing utils -->
<antcall target="test-distribution-seed-seed-config.xsl"/>
<antcall target="test-distribution-seed-seed-config-chain.xsl"/>
<antcall target="test-distribution-seed-merge.xsl"/>
<antcall target="test-distribution-seed-chain.xsl"/>
</target>

<target name="test-xsl-dts.xsl">
Expand Down Expand Up @@ -77,4 +82,37 @@
</antcall>
</target>

<target name="test-test-media-type-tei2txt.xsl">
<antcall target="xspec.xspec" inheritall="false">
<param name="xspec.xml" location="${basedir}/test/media-type/tei2txt.xspec"/>
</antcall>
</target>

<!-- tests for utils -->

<target name="test-distribution-seed-seed-config.xsl">
<antcall target="xspec.xspec" inheritall="false">
<param name="xspec.xml" location="${basedir}/distribution/seed/seed-config.xspec"/>
</antcall>
</target>

<target name="test-distribution-seed-merge.xsl">
<antcall target="xspec.xspec" inheritall="false">
<param name="xspec.xml" location="${basedir}/distribution/seed/merge.xspec"/>
</antcall>
</target>

<target name="test-distribution-seed-chain.xsl">
<antcall target="xspec.xspec" inheritall="false">
<param name="xspec.xml" location="${basedir}/distribution/seed/chain.xspec"/>
</antcall>
</target>

<target name="test-distribution-seed-seed-config-chain.xsl">
<antcall target="xspec.xspec" inheritall="false">
<param name="xspec.xml" location="${basedir}/distribution/seed/seed-config-chain.xspec"
/>
</antcall>
</target>

</project>
32 changes: 24 additions & 8 deletions distribution/seed/assembly.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
<exclude>wiki/**</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/generated-resources/xml/xslt</directory>
<outputDirectory>/${project.artifactId}</outputDirectory>
<includes>
<include>**/*.seed.json</include>
</includes>
<excludes>
<exclude>test/**</exclude>
</excludes>
</fileSet>
<fileSet>
<!-- include all dependencies unpacked in target/dependencies -->
<directory>target/dependencies</directory>
Expand All @@ -59,6 +69,9 @@
<includes>
<include>saxon.*.xml</include>
</includes>
<excludes>
<exclude>test/**</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>distribution/seed</directory>
Expand All @@ -75,14 +88,17 @@
<include>${project.artifactId}.yaml</include>
</includes>
</fileSet>
<fileSet>
<!-- the user-provided yaml config file overwrites the generated one -->
<directory>${project.basedir}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}.yaml</include>
</includes>
</fileSet>
</fileSets>

<files>
<file>
<source>${project.build.directory}/generated-resources/xml/xslt/pom.json</source>
<destName>${project.artifactId}.json</destName>
</file>
<file>
<source>${project.build.directory}/generated-resources/yml/pom.yml</source>
<destName>${project.artifactId}.yaml</destName>
</file>
</files>

</assembly>
132 changes: 132 additions & 0 deletions distribution/seed/chain.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Makes a SEED configuration from the document config and a config of a transformation to be chained to it

USAGE:
target/bin/xslt.sh \
-xsl:distribution/seed/chain.xsl \
-it \
document-config-uri=PATH_TO_DOCUMENT.json \
chained-config-uri=PATH_TO_CHAINED.json \
media-type-package=CHAINED_PACKAGE_NAME

-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
xmlns:seed="http://scdh.wwu.de/transform/seed#" exclude-result-prefixes="#all" version="3.0">

<xsl:output method="json" indent="true"/>

<!-- PATH to JSON config file for XSLT for document endpoint -->
<xsl:param name="document-config-uri" as="xs:string" required="true"/>

<xsl:param name="document-config" as="map(*)"
select="$document-config-uri => unparsed-text() => parse-json()"/>

<!-- PATH to JSON config file fof XSLT to be chained to document endpoint XSLT -->
<xsl:param name="chained-config-uri" as="xs:string" required="true"/>

<xsl:param name="chained-config" as="map(*)"
select="$chained-config-uri => unparsed-text() => parse-json()"/>

<!-- name (ID) of the resulting transformation -->
<xsl:param name="name" as="xs:string">
<xsl:value-of
select="seed:transformation-id($document-config) || '+' || seed:transformation-id($chained-config)"
/>
</xsl:param>

<!-- set this to the empty string or () if you do not want pass on to a mediaType processor -->
<xsl:param name="media-type-package" as="xs:string" required="true"/>

<!-- version of the mediaType processor package -->
<xsl:param name="media-type-package-version" as="xs:string" select="'1.0.0'"/>

<!-- should be 'template', 'mode', or 'function' -->
<xsl:param name="media-type-component" as="xs:string" select="'template'"/>

<!-- name of the template, mode or function used as an entry point for mediaType processing -->
<xsl:param name="media-type-processor" as="xs:string" select="'post-proc'"/>

<xsl:variable name="media-type-parameters" as="map(xs:string, item()*)*">
<xsl:map>
<xsl:map-entry key="'name'">media-type-package</xsl:map-entry>
<xsl:map-entry key="'value'" select="$media-type-package"/>
<xsl:map-entry key="'type'">xs:string?</xsl:map-entry>
</xsl:map>
<xsl:map>
<xsl:map-entry key="'name'">media-type-package-version</xsl:map-entry>
<xsl:map-entry key="'value'" select="$media-type-package-version"/>
<xsl:map-entry key="'type'">xs:string</xsl:map-entry>
</xsl:map>
<xsl:map>
<xsl:map-entry key="'name'">media-type-component</xsl:map-entry>
<xsl:map-entry key="'value'" select="$media-type-component"/>
<xsl:map-entry key="'type'">xs:string</xsl:map-entry>
</xsl:map>
<xsl:map>
<xsl:map-entry key="'name'">media-type-processor</xsl:map-entry>
<xsl:map-entry key="'value'" select="$media-type-processor"/>
<xsl:map-entry key="'type'">xs:string</xsl:map-entry>
</xsl:map>
</xsl:variable>

<xsl:template match="document-node()">
<xsl:sequence select="seed:chain()"/>
</xsl:template>

<xsl:template name="xsl:initial-template">
<xsl:sequence select="seed:chain()"/>
</xsl:template>

<xsl:variable name="document-bare-config" as="map(xs:string, item()*)"
select="seed:bare-config($document-config)"/>

<xsl:variable name="chained-bare-config" as="map(xs:string, item()*)"
select="seed:bare-config($chained-config)"/>


<xsl:function name="seed:chain" as="map(xs:string, item()*)" visibility="final">
<xsl:map>
<xsl:map-entry key="$name">
<xsl:sequence select="
map:merge((map:remove($chained-bare-config, ('location', 'requiresSource')), $document-bare-config), map {'duplicates': 'use-first'}) =>
map:put('libraries', array:join((map:get($document-bare-config, 'libraries'), seed:as-library($chained-config) => map:get('libraries')))) =>
map:put('parameterDescriptors', map:merge((map:get($document-bare-config, 'parameterDescriptors'), seed:as-library($chained-config) => map:get('parameterDescriptors')))) =>
map:put('compileTimeParameters', array {$media-type-parameters}) =>
map:put('description', concat(seed:transformation-id($chained-config), ' chained to ', seed:transformation-id($document-config), ': ', map:get($chained-bare-config, 'description')))"
/>
</xsl:map-entry>
</xsl:map>
</xsl:function>

<xsl:function name="seed:transformation-id" as="xs:string">
<xsl:param name="named-config" as="map(xs:string, map(xs:string, item()*))"/>
<xsl:value-of select="map:keys($named-config)[1]"/>
</xsl:function>

<xsl:function name="seed:bare-config" as="map(xs:string, item()*)">
<xsl:param name="named-config" as="map(xs:string, map(xs:string, item()*))"/>
<xsl:sequence select="map:get($named-config, seed:transformation-id($named-config))"/>
</xsl:function>

<xsl:function name="seed:as-library" as="map(xs:string, item()*)" visibility="final">
<xsl:param name="config" as="map(xs:string, item()*)"/>
<xsl:variable name="transformation" as="map(*)" select="seed:bare-config($config)"/>
<xsl:variable name="stylesheet" as="map(*)" select="
(
map:entry('location', map:get($transformation, 'location')),
map:entry('asName', $media-type-package),
map:entry('asVersion', $media-type-package-version)
) => map:merge()"/>
<xsl:variable name="libraries" as="array(*)"
select="array:join((array {$stylesheet}, map:get($transformation, 'libraries')))"/>
<xsl:map>
<xsl:map-entry key="'libraries'" select="$libraries"/>
<xsl:map-entry key="'parameterDescriptors'"
select="map:get($transformation, 'parameterDescriptors')"/>
</xsl:map>
</xsl:function>

</xsl:stylesheet>
127 changes: 127 additions & 0 deletions distribution/seed/chain.xspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<x:description xmlns:x="http://www.jenitennison.com/xslt/xspec"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
xmlns:seed="http://scdh.wwu.de/transform/seed#" stylesheet="chain.xsl" run-as="external">

<x:helper stylesheet="seed-config.xsl"/>

<x:param name="saxon-config-uri" select="'../../saxon.xml'"/>
<x:param name="transformations" select="'xsl/document.xsl'"/>
<x:variable name="document.json" select="seed:mk-config()"/>

<x:variable name="config-base-uri"
select="resolve-uri('../../../target/generated-resources/xml/xslt/', static-base-uri())"/>

<x:variable name="document-cfg-uri" as="xs:string"
select="resolve-uri('xsl/document.seed.json', $config-base-uri)"/>
<x:variable name="tei2txt-config-uri" as="xs:string"
select="resolve-uri('test/media-type/tei2txt.chain.json', $config-base-uri)"/>

<x:variable name="document-cfg" as="map(*)"
select="$document-cfg-uri => unparsed-text() => parse-json()"/>
<x:variable name="tei2txt-config" as="map(*)"
select="$tei2txt-config-uri => unparsed-text() => parse-json()"/>

<x:variable name="document-id" as="xs:string" select="map:keys($document-cfg)"/>
<x:variable name="tei2txt-id" as="xs:string" select="map:keys($tei2txt-config)"/>

<x:variable name="document-tei2txt-id" as="xs:string"
select="($document-id, $tei2txt-id) => string-join('+')"/>

<x:variable name="media-type-parameters" as="xs:string*"
select="'media-type-package','media-type-package-version','media-type-component','media-type-processor'"/>

<x:scenario label="seed:as-library">
<x:param name="document-config-uri" as="xs:string" select="''"/>
<x:param name="chained-config-uri" as="xs:string" select="''"/>
<x:param name="media-type-package" as="xs:string" select="'http://th.is'"/>
<x:call function="seed:as-library">
<x:param as="map(*)" select="$document.json"/>
</x:call>
<x:expect label="keeps transformation id" test="map:contains(., 'libraries')"/>
<x:expect label="document.xsl entry package in libraries"
test="map:get(., 'libraries') => array:filter(function ($x) {map:get($x, 'location') => ends-with('document.xsl')}) => array:size()"
select="1"/>
<x:expect label="one more libraries than before"
test="map:get(., 'libraries') => array:size()"
select="map:get($document.json, 'xsl-document') => map:get('libraries') => array:size() + 1"/>
<x:expect label="document.xsl is first library"
test="map:get(., 'libraries') => array:get(1) => map:get('location')"
select="'xsl/document.xsl'"/>
<x:expect label="library as name"
test="map:get(., 'libraries') => array:get(1) => map:get('asName')"
select="'http://th.is'"/>
<x:expect label="library as version"
test="map:get(., 'libraries') => array:get(1) => map:get('asVersion')" select="'1.0.0'"/>
<x:expect label="has parameter descriptors property"
test="map:contains(., 'parameterDescriptors')"/>
<x:expect label="same number of parameter descriptors"
test="map:get(., 'parameterDescriptors') => map:size()"
select="map:get($document.json, 'xsl-document') => map:get('parameterDescriptors') => map:size()"
/>
</x:scenario>

<x:scenario label="chain tei2txt.xsl to document.xsl">
<x:param name="document-config-uri" as="xs:string" select="''"/>
<x:param name="chained-config-uri" as="xs:string" select="''"/>
<x:param name="document-config" as="map(*)" select="$document-cfg"/>
<x:param name="chained-config" as="map(*)" select="$tei2txt-config"/>
<x:param name="media-type-package" as="xs:string" select="'http://example.com/xsl/tei2txt'"/>
<x:call function="seed:chain"/>
<x:expect label="results in 1 transformation config" test="map:size(.)" select="1"/>
<x:expect label="result transformation ID" test="map:keys(.)" select="$document-tei2txt-id"/>

<x:expect label="has hint about chaining in description"
test="map:get(., $document-tei2txt-id) => map:get('description') => matches('tei2txt.+chained\s+to.+document')"/>
<x:expect label="uses description from chained"
test="map:get(., $document-tei2txt-id) => map:get('description') => ends-with(map:get($tei2txt-config, $tei2txt-id) => map:get('description'))"/>

<x:expect label="content type determined by chained transformation"
test="map:get(., $document-tei2txt-id) => map:get('mediaType')"
select="map:get($tei2txt-config, $tei2txt-id) => map:get('mediaType')"/>

<x:expect label="location of document.xsl"
test="map:get(., $document-tei2txt-id) => map:get('location')"
select="map:get($document-cfg, $document-id) => map:get('location')"/>

<x:expect label="transformation to have the document libraries and tei2txt"
test="map:get(., $document-tei2txt-id) => map:get('libraries') => array:size()"
select="map:get($document-cfg, $document-id) => map:get('libraries') => array:size() + 1"/>
<x:expect label="chained stylesheet (tei2txt.xsl) is a library"
test=". => map:get($document-tei2txt-id) => map:get('libraries') => array:filter(function ($x) as xs:boolean { map:get($x, 'location') => matches('tei2txt\.xsl') }) => array:size()"
select="1"/>
<x:expect label="chained stylesheet (tei2txt.xsl) has location"
test=". => map:get($document-tei2txt-id) => map:get('libraries') => array:filter(function ($x) as xs:boolean { map:get($x, 'location') => matches('tei2txt\.xsl') }) => array:get(1) => map:get('location')"
select="map:get($tei2txt-config, $tei2txt-id) => map:get('location')"/>
<x:expect label="chained stylesheet (tei2txt.xsl) has asName"
test=". => map:get($document-tei2txt-id) => map:get('libraries') => array:filter(function ($x) as xs:boolean { map:get($x, 'location') => matches('tei2txt\.xsl') }) => array:get(1) => map:get('asName')"
select="'http://example.com/xsl/tei2txt'"/>
<x:expect label="chained stylesheet (tei2txt.xsl) has asVersion"
test=". => map:get($document-tei2txt-id) => map:get('libraries') => array:filter(function ($x) as xs:boolean { map:get($x, 'location') => matches('tei2txt\.xsl') }) => array:get(1) => map:get('asVersion')"
select="'1.0.0'"/>

<x:expect label="transformation to have parameters of document and of tei2txt"
test="map:get(., $document-tei2txt-id) => map:get('parameterDescriptors') => map:size()"
select="map:get($document-cfg, $document-id) => map:get('parameterDescriptors') => map:size() + map:get($tei2txt-config, $tei2txt-id) => map:get('parameterDescriptors') => map:size()"/>

<x:expect label="has the media-type related compile time parameters"
test=". => map:get($document-tei2txt-id) => map:get('compileTimeParameters') => array:for-each(function ($x) as xs:string { map:get($x, 'name') })"
select="array {$media-type-parameters}"/>
</x:scenario>


<x:scenario label="chain tei2txt.xsl to document.xsl when called with a source document">
<x:param name="document-config-uri" as="xs:string" select="''"/>
<x:param name="chained-config-uri" as="xs:string" select="''"/>
<x:param name="document-config" as="map(*)" select="$document-cfg"/>
<x:param name="chained-config" as="map(*)" select="$tei2txt-config"/>
<x:param name="media-type-package" as="xs:string" select="'http://example.com/xsl/tei2txt'"/>
<x:context href="test-assembly.xml"/>
<x:expect label="results in 1 transformation config" test="map:size(.)" select="1"/>
<x:expect label="result transformation ID" test="map:keys(.)" select="$document-tei2txt-id"
/>
</x:scenario>

</x:description>
Loading
Loading