Skip to content

[bugfix] fn:transform: Conversion and treeIndex problems #5680

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

Open
wants to merge 23 commits into
base: develop-6.x.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ee5a8d9
[feature] add multi-arch images
duncdrum Nov 2, 2024
855cb3d
[feature] multi arch for release
duncdrum Nov 12, 2024
af2d67f
[bugfix] Repair JNLP interface, use correct BC library
dizzzz Nov 11, 2024
5cbb4cc
Merge pull request #5554 from dizzzz/bugfix/port_of_5544_jnlp
line-o Nov 18, 2024
07c2e87
[hotfix] fix and extend TransformFromPkgTest
line-o Dec 9, 2024
56551ac
Merge pull request #5575 from line-o/backport/5574
reinhapa Dec 10, 2024
e4f5e0a
[bugfix] registered import-uris have precedence
line-o Dec 10, 2024
98b2dbc
[bugfix] allow module imports in one-off xqueries
line-o Oct 31, 2024
5f12820
[fix] adjust container v6
duncdrum Jan 2, 2025
c9b87d4
[fix] modify Docker file
duncdrum Jan 3, 2025
8e28333
[ignore] deploy from ci
duncdrum Jan 3, 2025
944ff2d
[ignore] disable experimental
duncdrum Jan 3, 2025
95c16de
[fix] new tag dev6
duncdrum Jan 6, 2025
71a82ca
Merge pull request #5598 from duncdrum/backport-multi-arch-5533
dizzzz Jan 8, 2025
3011d1f
Merge pull request #5586 from line-o/backport/5529
dizzzz Jan 9, 2025
b28dbaf
Merge pull request #5577 from line-o/backport/5576
dizzzz Jan 9, 2025
cbd6427
[bugfix] Update IzPack to 5.2.4 to fix #5661
reinhapa Mar 18, 2025
cdd281c
[bugfix] Backport IzPack validation fixes
reinhapa Mar 18, 2025
3ae1884
Merge pull request #5678 from reinhapa/prei/izpack_524
dizzzz Mar 18, 2025
930c719
[bugfix] fn:transform: treeIndex did not work for nodes without docum…
Mar 18, 2025
196d70c
show xsl file and line number in transform error
Mar 21, 2025
2b32c9c
[bugfix] `XdmValue of(item)` could not handle `NodeProxy` items
Mar 21, 2025
7070f40
[bugfix] another problem in determining tree indexes
Mar 21, 2025
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
19 changes: 16 additions & 3 deletions .github/workflows/ci-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ jobs:
name: Build and Test Images
runs-on: ubuntu-latest
# NOTE (DP): Publish on develop and master, test on PRs against these
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || github.base_ref == 'develop' || github.base_ref == 'master'
# TODO(DP) Reinstate CRONed release builds to update stock apps regularly
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/develop-6.x.x' || github.ref == 'refs/heads/master'|| github.base_ref == 'develop' || github.base_ref == 'develop-6.x.x' || github.base_ref == 'master'
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -15,6 +16,10 @@ jobs:
with:
distribution: liberica
java-version: '8'
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Make buildkit default
uses: docker/setup-buildx-action@v3
id: buildx
Expand Down Expand Up @@ -51,6 +56,14 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: mvn -q -Ddocker.tag=latest -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
working-directory: ./exist-docker
- name: Publish dev6 images
if: github.ref == 'refs/heads/develop-6.x.x'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: mvn -q -Ddocker.tag=dev6 -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
working-directory: ./exist-docker
- name: Publish release images
if: github.ref == 'refs/heads/master'
env:
Expand All @@ -61,11 +74,11 @@ jobs:
working-directory: ./exist-docker
# NOTE (DP): This is for debugging, publishes an experimental image from inside PRs against develop
# - name: Publish experimental images
# if: github.base_ref == 'develop'
# if: github.base_ref == 'develop-6.x.x'
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
# DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
# run: mvn -q -Ddocker.tag=experimental -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
# run: mvn -q -Ddocker.tag=experimental6 -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
# working-directory: ./exist-docker

Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public class SourceFactory {
&& ((location.startsWith("/db") && !Files.exists(Paths.get(firstPathSegment(location))))
|| (contextPath != null && contextPath.startsWith("/db") && !Files.exists(Paths.get(firstPathSegment(contextPath)))))) {
final XmldbURI pathUri;
if (contextPath == null) {
if (contextPath == null || ".".equals(contextPath)) {
pathUri = XmldbURI.create(location);
} else {
pathUri = XmldbURI.create(contextPath).append(location);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class JnlpJarFiles {
"commons-logging-%latest%",
"commons-pool-%latest%",
"jargo-%latest%",
"bcprov-jdk15on-%latest%",
"bcprov-jdk18on-%latest%",
"fastutil-%latest%-min",
"j8fu-%latest%",
"jackson-core-%latest%",
Expand Down
66 changes: 35 additions & 31 deletions exist-core/src/main/java/org/exist/xquery/XQueryContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -574,46 +574,50 @@ public Optional<ExistRepository> getRepository() {
// the repo and its eXist handler
final Optional<ExistRepository> repo = getRepository();

if (!repo.isPresent()) {
return null;
}
// try an internal module
if (repo.isPresent()) {
final Module jMod = repo.get().resolveJavaModule(namespace, this);
if (jMod != null) {
return jMod;
}
final Module jMod = repo.get().resolveJavaModule(namespace, this);
if (jMod != null) {
return jMod;
}

// try an eXist-specific module
if (repo.isPresent()) {
final Path resolved = repo.get().resolveXQueryModule(namespace);

// use the resolved file or return null
if (resolved != null) {

String location = "";

try {

// see if the src exists in the database and if so, use that instead
Source src = repo.get().resolveStoredXQueryModuleFromDb(getBroker(), resolved);
if (src != null) {
// NOTE(AR) set the location of the module to import relative to this module's load path - so that transient imports of the imported module will resolve correctly!
location = Paths.get(XmldbURI.create(moduleLoadPath).getCollectionPath()).relativize(Paths.get(((DBSource)src).getDocumentPath().getCollectionPath())).toString();
} else {
// else, fallback to the one from the filesystem
src = new FileSource(resolved, false);
}
final Path resolved = repo.get().resolveXQueryModule(namespace);

// build a module object from the source
final ExternalModule module = compileOrBorrowModule(prefix, namespace, location, src);
return module;
if (resolved == null) {
return null;
}

} catch (final PermissionDeniedException e) {
throw new XPathException(e.getMessage(), e);
// use the resolved file
try {
// see if the src exists in the database and if so, use that instead
Source src = repo.get().resolveStoredXQueryModuleFromDb(getBroker(), resolved);
String location = "";
if (src == null) {
// fallback to load the source from the filesystem
src = new FileSource(resolved, false);
} else {
final String sourceCollection = ((DBSource)src).getDocumentPath().getCollectionPath();
if (".".equals(moduleLoadPath)) {
// module is a string passed to the xquery context, has therefore no location of its own
location = sourceCollection;
} else {
// NOTE(AR) set the location of the module to import relative to this module's load path
// - so that transient imports of the imported module will resolve correctly!
final Path collectionPath = Paths.get(XmldbURI.create(moduleLoadPath).getCollectionPath());
final Path sourcePath = Paths.get(sourceCollection);
location = collectionPath.relativize(sourcePath).toString();
}
}
}

return null;
// build a module object from the source
return compileOrBorrowModule(prefix, namespace, location, src);

} catch (final PermissionDeniedException | IllegalArgumentException e) {
throw new XPathException(e.getMessage(), e);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import net.sf.saxon.type.BuiltInAtomicType;
import org.exist.dom.QName;
import org.exist.dom.memtree.DocumentImpl;
import org.exist.dom.persistent.NodeProxy;
import org.exist.xquery.ErrorCodes;
import org.exist.xquery.XPathException;
import org.exist.xquery.functions.array.ArrayType;
Expand Down Expand Up @@ -119,6 +120,9 @@ static net.sf.saxon.s9api.QName of(final QNameValue qName) {
}

XdmValue of(final Item item) throws XPathException {
if (item instanceof NodeProxy) {
return ofNode(((NodeProxy) item).getNode());
}
final int itemType = item.getType();
if (Type.subTypeOf(itemType, Type.ATOMIC)) {
return ofAtomic((AtomicValue) item);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,10 @@ 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);
} catch (final SaxonApiException e) {
throw originalXPathException("Could not transform with "+options.xsltSource._1+" line "+e.getLineNumber()+": ", e, ErrorCodes.FOXT0003);
} catch (final UncheckedXPathException e) {
throw originalXPathException("Could not transform with "+options.xsltSource._1+" line "+e.getXPathException().getLocationAsString()+": ", e, ErrorCodes.FOXT0003);
}

} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import net.sf.saxon.s9api.XdmNode;
import org.exist.xquery.value.NodeValue;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

Expand Down Expand Up @@ -64,20 +65,41 @@ static StringBuilder pathTo(final Node node) {
static List<Integer> treeIndex(final Node node) {
final Node parent = node.getParentNode();
if (parent == null) {
return new ArrayList<>();
final List<Integer> index = new ArrayList<>();
// The root element always index 0 within the document node.
// Some node implementations (e.g., org.exist.dom.memtree.NodeImpl) do not always have an associated document.
// In this case, the nodeIndex must get an extra 0 index to be valid for xdmDocument.
if (! (node instanceof Document)) {
index.add(0);
}
return index;
}
final List<Integer> index = treeIndex(parent);
Node sibling = node.getPreviousSibling();
Node sibling = previousSiblingNotAttribute(node);
int position = 0;
while (sibling != null) {
position += 1;
sibling = sibling.getPreviousSibling();
sibling = previousSiblingNotAttribute(sibling);
}
index.add(position);

return index;
}

/**
* A org.exist.dom.persistent.StoredNode returns attributes of an element as previous siblings of the element's children.
* This is not compatible with the way xdmNodeAtIndex works, so we need to compensate for this.
* @param node
* @return the previous sibling of `node` that is not an attribute.
*/
private static Node previousSiblingNotAttribute(Node node) {
Node sibling = node.getPreviousSibling();
if (sibling instanceof Attr) {
return null;
}
return sibling;
}

static XdmNode xdmNodeAtIndex(final XdmNode xdmNode, final List<Integer> index) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this method not be adapted? This loops over children(), are these not including attributes?

if (index.isEmpty()) {
return xdmNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ public class XsltURIResolverHelper {
@Nullable final URIResolver defaultResolver, @Nullable final String base, final boolean avoidSelf) {
final List<URIResolver> resolvers = new ArrayList<>();

// EXpath Pkg resolver
// This resolver needs to be the first one to prevent
// HTTP requests for registered package names (e.g. http://www.functx.com/functx.xsl)
brokerPool.getExpathRepo().map(repo -> resolvers.add(new PkgXsltModuleURIResolver(repo)));

if (base != null) {
// database resolver
resolvers.add(new EXistURISchemeURIResolver(new EXistURIResolver(brokerPool, base)));
}

// EXpath Pkg resolver
brokerPool.getExpathRepo().map(repo -> resolvers.add(new PkgXsltModuleURIResolver(repo)));

// default resolver
if (defaultResolver != null) {
if (avoidSelf) {
Expand Down
Loading
Loading