Skip to content

Commit

Permalink
MCR-2966 move saxon compatible stylesheets to folder xslt (#1964)
Browse files Browse the repository at this point in the history
* move saxon xsls to xslt folder, add configuration variable for default xsl folder
* add URI resolver for XEditor XSLs

---------

Co-authored-by: Michael Becker <[email protected]>
  • Loading branch information
michael-becker and Michael Becker authored Nov 3, 2023
1 parent bafd51c commit d797e1a
Show file tree
Hide file tree
Showing 85 changed files with 362 additions and 92 deletions.
3 changes: 2 additions & 1 deletion mycore-base/src/main/java/org/mycore/common/MCRMailer.java
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ public static Element sendMail(Document input, String stylesheet) throws Excepti
private static Document transform(Document input, String stylesheet, Map<String, String> parameters)
throws Exception {
MCRJDOMContent source = new MCRJDOMContent(input);
MCRXSL2XMLTransformer transformer = MCRXSL2XMLTransformer.getInstance("xsl/" + stylesheet + ".xsl");
final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
MCRXSL2XMLTransformer transformer = MCRXSL2XMLTransformer.getInstance(xslFolder + "/" + stylesheet + ".xsl");
MCRParameterCollector parameterCollector = MCRParameterCollector.getInstanceFromUserSession();
parameterCollector.setParameters(parameters);
MCRContent result = transformer.transform(source, parameterCollector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ private String getResourceName(String id) {
* Builds the filename of the stylesheet to use, e. g. "playlist-simple.xsl"
*/
private String buildStylesheetName(String id) {
return String.format(Locale.ROOT, "xsl/%s.xsl", id.replaceAll("-default$", ""));
final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
return String.format(Locale.ROOT, "%s/%s.xsl", xslFolder, id.replaceAll("-default$", ""));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPathExpressionException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.cache.HttpCacheContext;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
Expand Down Expand Up @@ -233,6 +234,7 @@ private HashMap<String, URIResolver> getResolverMapping() {
supportedSchemes.put("catchEx", new MCRExceptionAsXMLResolver());
supportedSchemes.put("notnull", new MCRNotNullResolver());
supportedSchemes.put("xslStyle", new MCRXslStyleResolver());
supportedSchemes.put("xslStyleXEditor", new MCRXslStyleXEditorResolver());
supportedSchemes.put("xslTransform", new MCRLayoutTransformerResolver());
supportedSchemes.put("xslInclude", new MCRXslIncludeResolver());
supportedSchemes.put("xslImport", new MCRXslImportResolver());
Expand Down Expand Up @@ -266,7 +268,8 @@ private HashMap<String, URIResolver> getResolverMapping() {
static String getParentDirectoryResourceURI(String base) {
if (base == null) {
// the file was not included from another file, so we need to use the default resource directory
return "resource:xsl/";
final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
return "resource:" + xslFolder + "/";
} else {
String resolvingBase = null;

Expand Down Expand Up @@ -381,7 +384,9 @@ private Source tryResolveXSL(String href, String base) throws TransformerExcepti
}

// new relative include did not work, now fall back to old behaviour and print a warning if it works
Source oldResolveMethodResult = SUPPORTED_SCHEMES.get("resource").resolve("resource:xsl/" + href, base);
final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
Source oldResolveMethodResult = SUPPORTED_SCHEMES.get("resource")
.resolve("resource:" + xslFolder + "/" + href, base);
if (oldResolveMethodResult != null) {
LOGGER.warn("The Stylesheet {} has include {} which only works with an old absolute include " +
"mechanism. Please change the include to relative!", base, href);
Expand Down Expand Up @@ -1228,7 +1233,19 @@ public Source resolve(String href, String base) throws TransformerException {
}
}

private MCRXSLTransformer getTransformer(String... stylesheet) {
protected MCRXSLTransformer getTransformer(String... stylesheet) {
final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
String[] stylesheets = new String[stylesheet.length];
for (int i = 0; i < stylesheets.length; i++) {
stylesheets[i] = xslFolder + "/" + stylesheet[i] + ".xsl";
}
return MCRXSLTransformer.getInstance(stylesheets);
}
}

private static class MCRXslStyleXEditorResolver extends MCRXslStyleResolver {
@Override
protected MCRXSLTransformer getTransformer(String... stylesheet) {
String[] stylesheets = new String[stylesheet.length];
for (int i = 0; i < stylesheets.length; i++) {
stylesheets[i] = "xsl/" + stylesheet[i] + ".xsl";
Expand Down Expand Up @@ -1340,10 +1357,12 @@ public Source resolve(String href, String base) {
.orElseGet(Collections::emptyList);
}

final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
for (String include : propValue) {
// create a new include element
Element includeElement = new Element("include", xslNamespace);
includeElement.setAttribute("href", include.contains(":") ? include : "resource:xsl/" + include);
includeElement.setAttribute("href",
include.contains(":") ? include : "resource:" + xslFolder + "/" + include);
root.addContent(includeElement);
LOGGER.debug("Resolved XSL include: {}", include);
}
Expand All @@ -1368,6 +1387,17 @@ private static class MCRXslImportResolver implements URIResolver {

@Override
public Source resolve(String href, String base) throws TransformerException {
final String baseURI = getParentDirectoryResourceURI(base);
// set xslt folder
final String xslFolder;
if (StringUtils.startsWith(baseURI, "resource:xsl/")) {
xslFolder = "xsl";
} else if (StringUtils.startsWith(baseURI, "resource:xslt/")) {
xslFolder = "xslt";
} else {
xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
}

String importXSL = MCRXMLFunctions.nextImportStep(href.substring(href.indexOf(':') + 1));
if (importXSL.isEmpty()) {
LOGGER.debug("End of import queue: {}", href);
Expand All @@ -1377,7 +1407,8 @@ public Source resolve(String href, String base) throws TransformerException {
return new JDOMSource(root);
}
LOGGER.debug("xslImport importing {}", importXSL);
return fallback.resolve("resource:xsl/" + importXSL, base);

return fallback.resolve("resource:" + xslFolder + "/" + importXSL, base);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.jdom2.filter.Filters;
import org.jdom2.util.IteratorIterable;
import org.mycore.common.MCRConstants;
import org.mycore.common.config.MCRConfiguration2;
import org.mycore.common.config.MCRConfigurationDir;
import org.mycore.common.content.MCRJDOMContent;
import org.mycore.common.xml.MCRURIResolver;
Expand All @@ -57,8 +58,8 @@

/**
* Lists all *.xsl stylesheets in the web application located in any
* WEB-INF/lib/*.jar or WEB-INF/classes/xsl/ or in {@link MCRConfigurationDir}, outputs the
* dependencies (import/include) and contained templates.
* WEB-INF/lib/*.jar or WEB-INF/classes/[MCR.Layout.Transformer.Factory.XSLFolder]/ or in {@link MCRConfigurationDir},
* outputs the dependencies (import/include) and contained templates.
*
* @author Frank Lützenkirchen
*/
Expand All @@ -69,6 +70,8 @@ public final class MCRXSLInfoServlet extends MCRServlet {
private final Map<String, Stylesheet> stylesheets = new HashMap<>();

private final Set<String> unknown = new HashSet<>();
private final String xslFolder =
MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder") + "/";

protected void doGetPost(MCRServletJob job) throws Exception {
if ("true".equals(job.getRequest().getParameter("reload"))) {
Expand Down Expand Up @@ -202,7 +205,7 @@ private void findInJarInputStream(String pathOfJarFile, InputStream in) throws I

for (ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
String name = ze.getName();
if (name.startsWith("xsl/") && name.endsWith(".xsl")) {
if (name.startsWith(xslFolder) && name.endsWith(".xsl")) {
foundStylesheet(name, pathOfJarFile);
}
zis.closeEntry();
Expand All @@ -211,7 +214,7 @@ private void findInJarInputStream(String pathOfJarFile, InputStream in) throws I
}

private void findXSLinClassesDir() {
String base = "/WEB-INF/classes/xsl/";
String base = "/WEB-INF/classes/" + xslFolder;
for (String path : diveInto(base)) {
if (path.endsWith(".xsl")) {
foundStylesheet(path, base);
Expand All @@ -220,7 +223,7 @@ private void findXSLinClassesDir() {
}

private void foundStylesheet(String path, String source) {
String file = path.substring(path.lastIndexOf("xsl/") + 4);
String file = path.substring(path.lastIndexOf(xslFolder) + 4);
LOGGER.info("Found {} in {}", file, source);
Stylesheet stylesheet = getStylesheet(file);
if (source.startsWith("/WEB-INF/")) {
Expand Down Expand Up @@ -260,7 +263,7 @@ void inspect() {
}

private void resolveXSL() {
String uri = "resource:xsl/" + name;
String uri = "resource:" + xslFolder + name;
resolveXSL(uri);
if (xsl == null) {
resolveXSL(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.jdom2.Element;
import org.jdom2.transform.JDOMSource;
import org.mycore.common.MCRUsageException;
import org.mycore.common.config.MCRConfiguration2;
import org.mycore.common.xml.MCRURIResolver;
import org.mycore.datamodel.common.MCRXMLMetadataManager;
import org.mycore.datamodel.metadata.MCRMetadataManager;
Expand Down Expand Up @@ -167,7 +168,7 @@ public static Stream<String> getIdsFromIdToId(final String startId, final String
* the name of the style to be used when resolving the stylesheet.
* @param defaultStyle
* the name of the default style, ending with <em>.xsl</em> to be used when resolving the stylesheet.
* A corresponding file xsl/<em>defaultStyle</em> must exist.
* A corresponding file [MCR.Layout.Transformer.Factory.XSLFolder]/<em>defaultStyle</em> must exist.
* @param cache
* The transformer cache to be used.
* @return the transformer
Expand All @@ -185,7 +186,8 @@ public static Transformer getTransformer(String style, String defaultStyle, Map<
Element element = MCRURIResolver.instance().resolve("resource:" + xslFilePath);
if (element == null) {
LOGGER.warn("Couldn't find resource {} for style {}, using default.", xslFilePath, style);
xslFilePath = "xsl/" + defaultStyle;
final String xslFolder = MCRConfiguration2.getStringOrThrow("MCR.Layout.Transformer.Factory.XSLFolder");
xslFilePath = xslFolder + "/" + defaultStyle;
element = MCRURIResolver.instance().resolve("resource:" + xslFilePath);
}

Expand Down
4 changes: 3 additions & 1 deletion mycore-base/src/main/resources/config/mycore.properties
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ MCR.BatchEditor.BaseLevel.object=/mycoreobject
# Define the LayoutFactory class
MCR.Layout.Transformer.Factory=org.mycore.common.xml.MCRLayoutTransformerFactory

# Default folder for XSL files, switch to xsl for XSL1 applications
MCR.Layout.Transformer.Factory.XSLFolder=xslt

# The format of the session ID
# MCR.Session.Param=;jsessionid=

Expand Down Expand Up @@ -479,7 +482,6 @@ MCR.Startup.Class=org.mycore.backend.jpa.MCRJPABootstrapper,org.mycore.datamodel
MCR.Website.ReadAccessVerification=true

MCR.URIResolver.xslIncludes.MyCoReWebPage=classificationBrowser.xsl
MCR.URIResolver.xslIncludes.MyCoReWebPage-3=classificationBrowser-3.xsl
MCR.URIResolver.xslIncludes.functions=functions/acl.xsl,functions/classification.xsl,functions/derivate.xsl,functions/i18n.xsl,functions/mcrversion.xsl,functions/property.xsl,functions/stringutils.xsl,functions/url.xsl,functions/layoututils.xsl

##############################################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
>
&html-output;

<xsl:include href="MyCoReLayout-3.xsl" />
<xsl:include href="xslInclude:MyCoReWebPage-3" />
<xsl:include href="MyCoReLayout.xsl" />
<xsl:include href="xslInclude:MyCoReWebPage" />
<!-- <xsl:include href="xslInclude:MyCoReWebPage" /> -->

<xsl:variable name="PageID" select="/MyCoReWebPage/@id" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
import java.util.LinkedHashMap;
import java.util.Map;

import javax.xml.transform.Source;

import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Test;
import org.mycore.common.MCRTestCase;
import org.mycore.common.config.MCRConfiguration2;
import org.mycore.common.config.MCRConfigurationDir;

public class MCRURIResolverTest extends MCRTestCase {
Expand Down Expand Up @@ -52,4 +56,19 @@ protected Map<String, String> getTestProperties() {

return properties;
}

@Test
public void testImportFromSameDirectory() throws Exception {
MCRConfiguration2.set("MCR.URIResolver.xslImports.xsl-import", "functions/xsl-1.xsl,functions/xsl-2.xsl");

Source resolved = MCRURIResolver.instance()
.resolve("xslImport:xsl-import:functions/xsl-2.xsl", "some.jar!/xsl/xsl/functions/xsl-2.xsl");
Assert.assertNotNull(resolved);
Assert.assertTrue(StringUtils.endsWith(resolved.getSystemId(), "/xsl/functions/xsl-1.xsl"));

resolved = MCRURIResolver.instance()
.resolve("xslImport:xsl-import:functions/xsl-2.xsl", "some.jar!/xslt/functions/xsl-2.xsl");
Assert.assertNotNull(resolved);
Assert.assertTrue(StringUtils.endsWith(resolved.getSystemId(), "/xslt/functions/xsl-1.xsl"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import org.junit.Test;
import org.mycore.common.MCRTestCase;
import org.mycore.common.config.MCRConfiguration2;

public class MCRXMLFunctionsTest extends MCRTestCase {

Expand Down Expand Up @@ -173,4 +174,20 @@ public void toNCNameSecondPart() {
}
}

@Test
public void testNextImportStep() {
MCRConfiguration2.set("MCR.URIResolver.xslImports.xsl-import", "functions/xsl-1.xsl,functions/xsl-2.xsl");

// test with first stylesheet in chain
String next = MCRXMLFunctions.nextImportStep("xsl-import");
assertEquals("functions/xsl-2.xsl", next);

// test with include part
next = MCRXMLFunctions.nextImportStep("xsl-import:functions/xsl-2.xsl");
assertEquals("functions/xsl-1.xsl", next);

// test with last stylesheet in chain
next = MCRXMLFunctions.nextImportStep("xsl-import:functions/xsl-1.xsl");
assertEquals("", next);
}
}
5 changes: 5 additions & 0 deletions mycore-base/src/test/resources/xsl/functions/xsl-1.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- test XSL file for MCRURIResolverTest#testImportFromSameDirectory -->
<xsl:import href="xslImport:xsl-import:xsl-1.xsl"/>
</xsl:stylesheet>
5 changes: 5 additions & 0 deletions mycore-base/src/test/resources/xsl/functions/xsl-2.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- test XSL file for MCRURIResolverTest#testImportFromSameDirectory -->
<xsl:import href="xslImport:xsl-import:xsl-2.xsl"/>
</xsl:stylesheet>
5 changes: 5 additions & 0 deletions mycore-base/src/test/resources/xslt/functions/xsl-1.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- test XSL file for MCRURIResolverTest#testImportFromSameDirectory -->
<xsl:import href="xslImport:xsl-import:xsl-1.xsl"/>
</xsl:stylesheet>
5 changes: 5 additions & 0 deletions mycore-base/src/test/resources/xslt/functions/xsl-2.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- test XSL file for MCRURIResolverTest#testImportFromSameDirectory -->
<xsl:import href="xslImport:xsl-import:xsl-2.xsl"/>
</xsl:stylesheet>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
version="3">


<xsl:include href="classificationEditorBase-3.xsl" />
<xsl:include href="classificationEditorBase.xsl" />
<xsl:output method="html" media-type="text/html" encoding="UTF-8" indent="yes" />

<xsl:template match="classificationEditor">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public Source resolve(String href, String base) throws TransformerException {
boolean completelyTiled = MCRIView2Tools.isCompletelyTiled(params[2]);
return new JDOMSource(new Element(String.valueOf(completelyTiled)));
}
case "isFileSupported" -> {
final boolean supported = MCRIView2Tools.isFileSupported(params[2]);
return new JDOMSource(new Element(String.valueOf(supported)));
}
default -> throw new TransformerException("Invalid href: " + href);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ MCR.Module-iview2.MaxResetCount=3
MCR.CLI.Classes.Internal=%MCR.CLI.Classes.Internal%,org.mycore.iview2.frontend.MCRIView2Commands
MCR.URIResolver.ModuleResolver.iview2=org.mycore.iview2.services.MCRIview2URIResolver
MCR.URIResolver.xslIncludes.components=%MCR.URIResolver.xslIncludes.components%,mcr-module-startIview2.xsl
MCR.URIResolver.xslIncludes.components-3=%MCR.URIResolver.xslIncludes.components-3%,mcr-module-startIview2-3.xsl
MCR.URIResolver.xslIncludes.solrResponse=%MCR.URIResolver.xslIncludes.solrResponse%,iview2-solrresponse.xsl
MCR.URIResolver.xslIncludes.solrResponse-3=%MCR.URIResolver.xslIncludes.solrResponse-3%,iview2-solrresponse-3.xsl
MCR.URIResolver.xslIncludes.functions=%MCR.URIResolver.xslIncludes.functions%,functions/iview2.xsl

MCR.Hibernate.Mappings=%MCR.Hibernate.Mappings%,org.mycore.iview2.services.MCRTileJob
Expand Down
18 changes: 18 additions & 0 deletions mycore-iview2/src/main/resources/xslt/iview2-solr.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="xslImport:solr-document:iview2-solr.xsl"/>

<xsl:template match="mycorederivate">
<xsl:apply-imports/>
<xsl:apply-templates select="derivate/internals/internal" mode="iview2"/>
</xsl:template>

<xsl:template match="mycorederivate/derivate/internals/internal" mode="iview2">
<xsl:if test="@maindoc and count(document(concat('iview2:isFileSupported:', @maindoc))/true)&gt;0">
<field name="iviewFile">
<xsl:value-of select="@maindoc"/>
</field>
</xsl:if>
</xsl:template>

</xsl:stylesheet>
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ MCR.URIResolver.xslIncludes.objectTypes=%MCR.URIResolver.xslIncludes.objectTypes
MCR.URIResolver.xslIncludes.functions=%MCR.URIResolver.xslIncludes.functions%,functions/mods.xsl
MCR.URIResolver.xslIncludes.datacite=mycoreobject-datacite.xsl
MCR.URIResolver.xslIncludes.schemaorg=
MCR.URIResolver.xslImports.solr-document=%MCR.URIResolver.xslImports.solr-document%,mods-solr.xsl
MCR.URIResolver.xslImports.solr-document-3=%MCR.URIResolver.xslImports.solr-document-3%,solr/indexing/mods-solr-3.xsl,solr/indexing/mods-dynamicfields-3.xsl
MCR.URIResolver.xslImports.solr-document=%MCR.URIResolver.xslImports.solr-document%,solr/indexing/mods-solr.xsl,solr/indexing/mods-dynamicfields.xsl
MCR.URIResolver.redirect.editor-mods-external=webapp:editor/editor-mods-external.xml

# URIResolver to sort MODS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:mcrmods="http://www.mycore.de/xslt/mods">

<xsl:import href="xslImport:solr-document-3:solr/indexing/mods-dynamicfields-3.xsl" />
<xsl:import href="xslImport:solr-document:solr/indexing/mods-dynamicfields.xsl" />

<xsl:import href="resource:xsl/functions/mods.xsl" />
<xsl:import href="resource:xslt/functions/mods.xsl" />

<xsl:param name="MCR.Solr.DynamicFields" select="'false'" />
<xsl:param name="MCR.Solr.DynamicFields.excludes" select="''" />
Expand Down
Loading

0 comments on commit d797e1a

Please sign in to comment.