Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix missing fn:transform global parameters #4883

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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);
}
Expand All @@ -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);
Expand All @@ -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" +
Expand Down Expand Up @@ -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());
Expand Down
89 changes: 89 additions & 0 deletions exist-core/src/test/resources/org/exist/xquery/tei-toc.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?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()"/>
<xsl:param name="documentID" as="xs:string" select="/tei:TEI/@xml:id"/>

<xsl:output indent="true"/>

<xsl:mode on-no-match="shallow-skip" use-accumulators="#all"/>
<xsl:mode name="html" on-no-match="text-only-copy"/>

<xsl:accumulator name="document-nos" initial-value="()" as="xs:string*">
<xsl:accumulator-rule match="tei:div[@type eq 'document']" select="($value, @n)" phase="end"/>
</xsl:accumulator>

<xsl:accumulator name="document-ids" initial-value="()" as="xs:string*">
<xsl:accumulator-rule match="tei:div[tei:div/@type = 'document']" select="()"/>
<xsl:accumulator-rule match="tei:div[@type eq 'document']" select="($value, @xml:id)" phase="end"/>
</xsl:accumulator>

<xsl:template match="tei:TEI">
<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">
<xsl:apply-templates select="tei:text"/>
</ul>
</nav>
</div>
</xsl:template>

<xsl:template match="tei:div[@xml:id][not(@type = ('document'))]">
<xsl:variable name="accDocs" as="xs:string*" select="accumulator-after('document-nos')"/>
<xsl:variable name="prevDocs" as="xs:string*" select="accumulator-before('document-nos')"/>
<xsl:variable name="docs" as="xs:string*" select="$accDocs[not(. = $prevDocs)]"/>
<xsl:variable name="prevDocIDs" as="xs:string*" select="accumulator-before('document-ids')"/>
<xsl:variable name="docIDs" as="xs:string*" select="accumulator-after('document-ids')[not(. = $prevDocIDs)]"/>
<li data-tei-id="{@xml:id}">
<xsl:if test="exists($docIDs) and tei:div[@type='document']">
<xsl:attribute name="data-tei-documents" select="string-join($docIDs, ' ')"/>
</xsl:if>

<a href="/{$documentID}/{@xml:id}">
<xsl:apply-templates mode="html" select="tei:head"/>
</a>
<xsl:value-of select="(' (Document' || 's'[count($docs) gt 1] || ' ' || $docs[1] || ' - '[count($docs) gt 1] || $docs[last()][count($docs) gt 1] || ')')[exists($docs)]"/>

<xsl:where-populated>
<ul class="chapters__nested">
<xsl:apply-templates/>
</ul>
</xsl:where-populated>
</li>
</xsl:template>

<xsl:template match="tei:div[@xml:id eq 'toc']" priority="2"/>

<xsl:template match="tei:head/tei:note" mode="html"/>

<xsl:template match="tei:lb" mode="html">
<br/>
</xsl:template>

</xsl:stylesheet>
Original file line number Diff line number Diff line change
@@ -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 {
<TEI xmlns="http://www.tei-c.org/ns/1.0" xml:id="output">
<teiHeader>
<fileDesc>
<titleStmt>
<title/>
</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
};