From 8acb3bfd71fd94e8167d7ca5f43f8813a9cc36b2 Mon Sep 17 00:00:00 2001 From: Alan Paxton Date: Tue, 25 Apr 2023 16:27:17 +0100 Subject: [PATCH 1/2] [fix] fn:transform global parameters missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem manifests when loading the stylesheet from eXist-db. Stylesheet document fetching into sources is not recognising as documents the documents it received from the DB (as opposed to ones which are constructed in memory). All our testing has been done with temporary in memory documents and we missed the case of transform source in eXist-db. To fix it, we just have to recognise org.exist.dom.persistent.DocumentImpl as well as org.exist.dom.memtree.DocumentImpl as a valid document source; similarly, the case where a document can be a NodeProxy wasn’t recognised, we just need to fetch the node from the proxy when we recognise it as such, and proceed with using a source wrapping the resulting node as the stylesheet source. This appears to make the --- .../functions/fn/transform/Options.java | 8 +- .../functions/fn/transform/Transform.java | 10 +- .../resources/org/exist/xquery/tei-toc.xsl | 65 ++++++++++ .../transform/fnTransformIssue4609.xqm | 111 ++++++++++++++++++ 4 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl create mode 100644 exist-core/src/test/xquery/xquery3/transform/fnTransformIssue4609.xqm diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java index c439c08cd2b..cefcd2cf4ca 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java @@ -32,6 +32,7 @@ import net.sf.saxon.s9api.XdmValue; import org.apache.commons.lang3.StringUtils; import org.exist.dom.memtree.NamespaceNode; +import org.exist.dom.persistent.NodeProxy; import org.exist.security.PermissionDeniedException; import org.exist.xquery.ErrorCodes; import org.exist.xquery.XPathException; @@ -527,7 +528,12 @@ private Source resolvePossibleStylesheetLocation(final String location) throws X "Can not access '" + location + "'" + e.getMessage()); } if (document != null && document.hasOne() && Type.subTypeOf(document.getItemType(), Type.NODE)) { - return new DOMSource((Node) document.itemAt(0)); + if (document instanceof NodeProxy proxy) { + return new DOMSource(proxy.getNode()); + } + else if (document.itemAt(0) instanceof Node node) { + return new DOMSource(node); + } } throw new XPathException(fnTransform, ErrorCodes.FODC0002, "Location '"+ location + "' returns an item which is not a document node"); diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java index 1e6ca3a0de4..324b7f7ae11 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java @@ -34,7 +34,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.dom.QName; -import org.exist.dom.memtree.DocumentImpl; import org.exist.util.Holder; import org.exist.xquery.ErrorCodes; import org.exist.xquery.XPathException; @@ -177,7 +176,7 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro final Document document; Source source = sourceNode.get(); final Node node = ((DOMSource)sourceNode.get()).getNode(); - if (!(node instanceof DocumentImpl)) { + if (!(node instanceof org.exist.dom.memtree.DocumentImpl) && !(node instanceof org.exist.dom.persistent.DocumentImpl)) { //The source may not be a document //If it isn't, it should be part of a document, so we build a DOMSource to use document = node.getOwnerDocument(); @@ -193,7 +192,6 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro final Transform.TemplateInvocation invocation = new Transform.TemplateInvocation( options, sourceNode, delivery, xslt30Transformer, resultDocuments); return invocation.invoke(); - } catch (final SaxonApiException | UncheckedXPathException e) { throw originalXPathException("Could not transform input: ", e, ErrorCodes.FOXT0003); } @@ -205,6 +203,7 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro private XsltExecutable compileExecutable(final Options options) throws XPathException { + final XsltCompiler xsltCompiler = org.exist.xquery.functions.fn.transform.Transform.SAXON_PROCESSOR.newXsltCompiler(); final SingleRequestErrorListener errorListener = new SingleRequestErrorListener(Transform.ERROR_LISTENER); xsltCompiler.setErrorListener(errorListener); @@ -223,7 +222,7 @@ private XsltExecutable compileExecutable(final Options options) throws XPathExce xsltCompiler.setURIResolver((href, base) -> { try { final URI hrefURI = URI.create(href); - if (!options.resolvedStylesheetBaseURI.isPresent() && !hrefURI.isAbsolute() && StringUtils.isEmpty(base)) { + if (options.resolvedStylesheetBaseURI.isEmpty() && !hrefURI.isAbsolute() && StringUtils.isEmpty(base)) { final XPathException resolutionException = new XPathException(fnTransform, ErrorCodes.XTSE0165, "transform using a relative href, \n" + @@ -266,8 +265,7 @@ private XPathException originalXPathException(final String prefix, @Nonnull fina cause = e; while (cause != null) { - if (cause instanceof net.sf.saxon.trans.XPathException) { - final net.sf.saxon.trans.XPathException xPathException = (net.sf.saxon.trans.XPathException)cause; + if (cause instanceof final net.sf.saxon.trans.XPathException xPathException) { final StructuredQName from = xPathException.getErrorCodeQName(); if (from != null) { final QName errorCodeQName = new QName(from.getLocalPart(), from.getURI(), from.getPrefix()); diff --git a/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl b/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl new file mode 100644 index 00000000000..9fb29146f97 --- /dev/null +++ b/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + +
+
+

Contents

+
+ +
+
+ + + + + + + +
  • + + + + + + + + + + +
      + +
    +
    +
  • +
    + + + + + + +
    +
    + +
    diff --git a/exist-core/src/test/xquery/xquery3/transform/fnTransformIssue4609.xqm b/exist-core/src/test/xquery/xquery3/transform/fnTransformIssue4609.xqm new file mode 100644 index 00000000000..931444c89ed --- /dev/null +++ b/exist-core/src/test/xquery/xquery3/transform/fnTransformIssue4609.xqm @@ -0,0 +1,111 @@ +(: + : eXist-db Open Source Native XML Database + : Copyright (C) 2001 The eXist-db Authors + : + : info@exist-db.org + : http://www.exist-db.org + : + : This library is free software; you can redistribute it and/or + : modify it under the terms of the GNU Lesser General Public + : License as published by the Free Software Foundation; either + : version 2.1 of the License, or (at your option) any later version. + : + : This library is distributed in the hope that it will be useful, + : but WITHOUT ANY WARRANTY; without even the implied warranty of + : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + : Lesser General Public License for more details. + : + : You should have received a copy of the GNU Lesser General Public + : License along with this library; if not, write to the Free Software + : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + :) +xquery version "3.1"; + +module namespace testTransform="http://exist-db.org/xquery/test/function_transform"; +import module namespace xmldb="http://exist-db.org/xquery/xmldb"; + +declare namespace test="http://exist-db.org/xquery/xqsuite"; + +declare variable $testTransform:doc := document { + + + + + + </titleStmt> + <publicationStmt> + <p>Test document</p> + </publicationStmt> + <sourceDesc> + <p>born digital</p> + </sourceDesc> + </fileDesc> + </teiHeader> + <text> + <front> + <div xml:id="pressrelease" type="section" subtype="press-release"> + <head>Press Release</head> + </div> + </front> + <body> + <div type="compilation" xml:id="comp"> + <head>Main Book</head> + <div type="chapter" xml:id="ch1"> + <head>Chapter One</head> + <div type="document" n="1" xml:id="d1"/> + <div type="document" n="2" xml:id="d2"/> + <div type="document" n="3" xml:id="d3"/> + <div type="document" n="4" xml:id="d4"/> + <div type="document" n="5" xml:id="d5"/> + <div type="document" n="6" xml:id="d6"/> + <div type="document" n="7" xml:id="d7"/> + </div> + <div type="chapter" xml:id="ch2"> + <head>Chapter Two</head> + <div type="document" n="8" xml:id="d8"/> + <div type="document" n="9" xml:id="d9"/> + <div type="document" n="10" xml:id="d10"/> + <div type="document" n="11" xml:id="d11"/> + <div type="document" n="12" xml:id="d12"/> + <div type="document" n="13" xml:id="d13"/> + <div type="document" n="14" xml:id="d14"/> + <div type="document" n="15" xml:id="d15"/> + </div> + <div type="chapter" xml:id="ch3"> + <head>Chapter Three</head> + <div type="document" n="16" xml:id="d16"/> + <div type="document" n="17" xml:id="d17"/> + <div type="document" n="18" xml:id="d18"/> + <div type="document" n="19" xml:id="d19"/> + <div type="document" n="20" xml:id="d20"/> + <div type="document" n="21" xml:id="d21"/> + </div> + <div type="chapter" xml:id="ch4"> + <head>Chapter Four</head> + <div type="document" n="22" xml:id="d22"/> + <div type="document" n="23" xml:id="d23"/> + <div type="document" n="24" xml:id="d24"/> + <div type="document" n="25" xml:id="d25"/> + <div type="document" n="26" xml:id="d26"/> + <div type="document" n="27" xml:id="d27"/> + <div type="document" n="28" xml:id="d28"/> + </div> + </div> + </body> + </text> +</TEI> +}; + +declare + %test:assertEquals("<div class=""toc""><div class=""toc__header""><h4 class=""title"">Contents</h4></div><nav aria-label=""Side navigation,,,"" class=""toc__chapters""><ul class=""chapters js-smoothscroll""><li data-tei-id=""pressrelease""><a href=""/output/pressrelease"">Press Release</a></li><li data-tei-id=""comp""><a href=""/output/comp"">Main Book</a> (Documents 1 - 28)<ul class=""chapters__nested""><li data-tei-id=""ch1"" data-tei-documents=""d1 d2 d3 d4 d5 d6 d7""><a href=""/output/ch1"">Chapter One</a> (Documents 1 - 7)</li><li data-tei-id=""ch2"" data-tei-documents=""d8 d9 d10 d11 d12 d13 d14 d15""><a href=""/output/ch2"">Chapter Two</a> (Documents 8 - 15)</li><li data-tei-id=""ch3"" data-tei-documents=""d16 d17 d18 d19 d20 d21""><a href=""/output/ch3"">Chapter Three</a> (Documents 16 - 21)</li><li data-tei-id=""ch4"" data-tei-documents=""d22 d23 d24 d25 d26 d27 d28""><a href=""/output/ch4"">Chapter Four</a> (Documents 22 - 28)</li></ul></li></ul></nav></div>") +function testTransform:issue-4609() { + let $create-collection := xmldb:create-collection("/db", "fn_transform_issue_4609") + let $doc-store := xmldb:store("/db/fn_transform_issue_4609", "input.xml", $testTransform:doc) + + (: this works :) + let $result := ( fn:transform(map{ + "stylesheet-location": 'resource:/org/exist/xquery/tei-toc.xsl', + "source-node": doc('/db/fn_transform_issue_4609/input.xml') + })) + return $result?output +}; From f209fd71a19b8497b0beea78337ee5106c67535a Mon Sep 17 00:00:00 2001 From: Alan Paxton <alan.paxton@gmail.com> Date: Tue, 25 Apr 2023 16:55:20 +0100 Subject: [PATCH 2/2] [ignore] add missing licence text --- .../resources/org/exist/xquery/tei-toc.xsl | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl b/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl index 9fb29146f97..ad2b95eab84 100644 --- a/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl +++ b/exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl @@ -1,3 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + eXist-db Open Source Native XML Database + Copyright (C) 2001 The eXist-db Authors + + info@exist-db.org + http://www.exist-db.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://www.tei-c.org/ns/1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="xs math xd tei" version="3.0"> <xsl:param name="heading" as="xs:boolean" select="true()"/>