Saxon 11.1 URI Resolvers
Added by Vladimir Nesterovsky almost 3 years ago
Hello,
Can you please direct me on how to migrate use of StandardURIResolver in Saxon 11.1?
We relied on "classpath:" scheme to resolve stylesheets inside jars. Now, it seems URIResolver is replaced with ResourceResolver, which doesn't seem to implement the feature.
Thanks
Replies (12)
Please register to reply
Saxon 11.1 - Added by Norm Tovey-Walsh almost 3 years ago
Saxonica Developer Community notifications@plan.io writes:
Can you please direct me on how to migrate use of StandardURIResolver
in Saxon 11.1?We relied on "classpath:" scheme to resolve stylesheets inside jars.
Now, it seems URIResolver is replaced with ResourceResolver, which
doesn't seem to implement the feature.
The ResourceResolver should resolve classpath: URIs. Can you provide an
example where it isn’t working?
Be seeing you,
norm
--
Norm Tovey-Walsh
Saxonica
RE: Saxon 11.1 - Added by Vladimir Nesterovsky almost 3 years ago
It did not work out of the box, so I need to debug. It might be related to something with my setup.
Thanks
RE: Saxon 11.1 - Added by Norm Tovey-Walsh almost 3 years ago
It did not work out of the box, so I need to debug. It might be
related to something with my setup.
I’d certainly like to understand why and help you fix it, so please let
me know what you find and don’t hesitate to ask for help!
Be seeing you,
norm
--
Norm Tovey-Walsh
Saxonica
RE: Saxon 11.1 URI Resolvers - Added by Michael Kay almost 3 years ago
More specifically, it's supposed to work like this, though the detail depends on what kind of resource you're trying to resolve. Let's suppose it's a call to document() in XSLT.
-
The code goes first to see if the
XsltTransformer
has aResourceResolver
. It won't have one unless the user has supplied one. If there isn't one, go to the next step. If it has one, call it. If it returns aSource
, use it; if not, go to the next step. -
Then we go to the
ResourceResolver
registered atConfiguration
level. By default this invokes the catalog-based resolver, which also handles classpath and data URIs. But you can set your own resolver at this level to override this. -
If the Configuration-level
ResourceResolver
returns null, the final fallback is to aDirectResourceResolver
which resolves URIs "natively" e.g. viaURL.openConnection()
.
Complicating this is what happens with legacy APIs that are still supported, such as setURIResolver() on the XsltTransformer
or the JAXP TransformerFactory
. Generally these are equivalent to a call on setResourceResolver() at the same level, for example setURIResolver() at TransformerFactory results in a call on Configuration.setResourceResolver(), which means the catalog-based resolver (with its classpath and data functionality) isn't invoked. If you want your URIResolver to fall back to that functionality, then either (a) define it at local level, or (b) set the Configuration-level resolver to a composite resolver that first does your local logic, then does the standard logic.
There's a class ChainedResourceResolver
that allows you to chain together two (or more) ResourceResolver
s in this way. There are also classes like ResourceResolverWrappingURIResolver
that might help the transition; and the StandardURIResolver
is still present in the product if you want to use it, though its name is now a misnomer.
RE: Saxon 11.1 - Added by Vladimir Nesterovsky almost 3 years ago
Ok, I figured out what has happened. In my pipeline I'm using my custom URIResolver. My goal was to "fix" "classpath:" resolution.
Consider two snapshots comparing how it works in Saxon and in custom resolvers:
@Test
public void testSaxonResolver()
throws Exception
{
String base = "classpath:my/class/path/";
String relativeURI = "my-style.xslt";
URI absoluteURI = null;
// Based on Saxon's ResolveURI.java
if (base.startsWith("classpath:"))
{
absoluteURI = new URI(relativeURI);
if (!absoluteURI.isAbsolute())
{
absoluteURI = new URI("classpath:" + relativeURI);
}
}
// This produces "classpath:my-style.xslt"
assertNotNull(absoluteURI);
}
@Test
public void testCustomResolver()
throws Exception
{
String base = "classpath:my/class/path/";
String relativeURI = "my-style.xslt";
String absoluteURI = null;
if (base.startsWith("classpath:"))
{
URI uri = new URI(relativeURI);
if (!uri.isAbsolute())
{
absoluteURI = "classpath:" +
new URI(base.substring("classpath:".length())).
resolve(uri).
toString();
}
}
// This produces "classpath:my/class/path/my-style.xslt"
assertNotNull(absoluteURI);
}
Saxon resolver produced "classpath:my-style.xslt" for "my-style.xslt" against "classpath:my/class/path/". Custom resolver produced "classpath:my/class/path/my-style.xslt" for "my-style.xslt" against "classpath:my/class/path/".
Custom resolver works better for my setup.
It was like this even in the past but I was able to replace resolver. But now I am not sure where should I plug my patch.
So, where may I implement such "fix"?
RE: Saxon 11.1 URI Resolvers - Added by Vladimir Nesterovsky almost 3 years ago
Complicating this is what happens with legacy APIs that are still supported, such as setURIResolver() on the XsltTransformer or the JAXP TransformerFactory
I'll try to figure out how to set it.
For some reason code I have always used Configuration and set resolver there.
In current version configuration.setURIResolver()
does not exists any more.
Thanks.
RE: Saxon 11.1 - Added by Norm Tovey-Walsh almost 3 years ago
Saxon resolver produced "classpath:my-style.xslt" for "my-style.xslt"
against "classpath:my/class/path/". Custom resolver produced
"classpath:my/class/path/my-style.xslt" for "my-style.xslt" against
"classpath:my/class/path/".Custom resolver works better for my setup.
That looks like a bug to me, https://saxonica.plan.io/issues/5271
It was like this even in the past but I was able to replace resolver.
But now I am not sure where should I plug my patch.So, where may I implement such "fix"?
You can still provide your own resolver.
Be seeing you,
norm
--
Norm Tovey-Walsh
Saxonica
RE: Saxon 11.1 URI Resolvers - Added by Vladimir Nesterovsky almost 3 years ago
I've switched off any custom resolvers and made sure that absolute paths are used for "classpath:" protocol, and now I'm certain that it does not work in Saxon 11.1, and that it worked in Saxon 10.x.
I get following error once processor tries to resolve <xsl:include href="classpath:..."
:
[java] Error on line 1 column 149 of META-INF:
[java] XTSE0165 I/O error reported by XML parser processing
[java] classpath:META-INF/stylesheets/postprocess/postprocess.xslt: unknown protocol: classpath.
[java] Caused by java.net.MalformedURLException: unknown protocol: classpath
[java] [1]:javax.xml.transform.TransformerConfigurationException: net.sf.saxon.s9api.SaxonApiException: I/O error reported by XML parser processing classpath:META-INF/stylesheets/postprocess/postprocess.xslt: unknown protocol: classpath
[java] [1] at net.sf.saxon.jaxp.SaxonTransformerFactory.newTemplates(SaxonTransformerFactory.java:187)
[java] [1] ... 3 more
[java] [1] Caused by: net.sf.saxon.s9api.SaxonApiException: I/O error reported by XML parser processing classpath:META-INF/stylesheets/postprocess/postprocess.xslt: unknown protocol: classpath
[java] [1] at net.sf.saxon.s9api.XsltCompiler.compile(XsltCompiler.java:937)
[java] [1] at net.sf.saxon.jaxp.SaxonTransformerFactory.newTemplates(SaxonTransformerFactory.java:185)
[java] [1] ... 3 more
[java] [1] Caused by: net.sf.saxon.trans.XPathException: I/O error reported by XML parser processing classpath:META-INF/stylesheets/postprocess/postprocess.xslt: unknown protocol: classpath
[java] [1] at net.sf.saxon.resource.ActiveSAXSource.deliver(ActiveSAXSource.java:229)
[java] [1] at net.sf.saxon.event.Sender.send(Sender.java:104)
[java] [1] at net.sf.saxon.style.StylesheetModule.sendStylesheetSource(StylesheetModule.java:152)
[java] [1] at net.sf.saxon.style.StylesheetModule.loadStylesheetModule(StylesheetModule.java:112)
[java] [1] at net.sf.saxon.style.UseWhenFilter.processIncludeImport(UseWhenFilter.java:324)
[java] [1] at net.sf.saxon.style.UseWhenFilter.startElement(UseWhenFilter.java:250)
[java] [1] at net.sf.saxon.event.Stripper.startElement(Stripper.java:105)
[java] [1] at net.sf.saxon.event.CommentStripper.startElement(CommentStripper.java:51)
[java] [1] at net.sf.saxon.event.ProxyReceiver.startElement(ProxyReceiver.java:140)
[java] [1] at net.sf.saxon.event.Valve.startElement(Valve.java:63)
[java] [1] at net.sf.saxon.event.ReceivingContentHandler.startElement(ReceivingContentHandler.java:377)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:518)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(AbstractXMLDocumentParser.java:183)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:351)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2725)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:541)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1224)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
[java] [1] at net.sf.saxon.resource.ActiveSAXSource.deliver(ActiveSAXSource.java:188)
[java] [1] at net.sf.saxon.resource.ActiveStreamSource.deliver(ActiveStreamSource.java:65)
[java] [1] at net.sf.saxon.event.Sender.send(Sender.java:104)
[java] [1] at net.sf.saxon.style.StylesheetModule.sendStylesheetSource(StylesheetModule.java:156)
[java] [1] at net.sf.saxon.style.StylesheetModule.loadStylesheet(StylesheetModule.java:226)
[java] [1] at net.sf.saxon.style.Compilation.compileSingletonPackage(Compilation.java:113)
[java] [1] at net.sf.saxon.s9api.XsltCompiler.compile(XsltCompiler.java:932)
[java] [1] ... 4 more
[java] [1] Caused by: java.net.MalformedURLException: unknown protocol: classpath
[java] [1] at java.base/java.net.URL.<init>(URL.java:679)
[java] [1] at java.base/java.net.URL.<init>(URL.java:568)
[java] [1] at java.base/java.net.URL.<init>(URL.java:515)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:649)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:150)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:860)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1224)
[java] [1] at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
[java] [1] at net.sf.saxon.resource.ActiveSAXSource.deliver(ActiveSAXSource.java:188)
[java] [1] ... 33 more
I seems processor assumes java.net.URL
should handle the protocol by itself, while java.net.URL
does not agree with it.
Nor I register any special protocol handlers.
Note: for thing to start to work at all, I have to add maven dependency:
<dependency>
<groupId>org.xmlresolver</groupId>
<artifactId>xmlresolver</artifactId>
<version>4.1.2</version>
</dependency>
RE: Saxon 11.1 URI Resolvers - Added by Martin Honnen almost 3 years ago
As for the Maven dependency missing, I think Norm has pushed Saxon 11.1.1 to Maven to fix that.
RE: Saxon 11.1 - Added by Norm Tovey-Walsh almost 3 years ago
Hello Vladimir,
I’ve been investigating the classpath: issue. I’m not sure I really
understand your test:
String base = "classpath:my/class/path/";
String relativeURI = "my-style.xslt";
URI absoluteURI = null;
if (base.startsWith("classpath:"))
This will always be true.
{
absoluteURI = new URI(relativeURI);
This will always produce “my-style.xslt” as a URI.
if (!absoluteURI.isAbsolute())
That will never be absolute.
{
absoluteURI = new URI("classpath:" + relativeURI);
This will always produce “classpath:my-style.xslt”.
}
}
I rewrote your test as follows:
String base = "classpath:my/class/path/";
String relativeURI = "my-style.xslt";
URI absoluteURI, resolvedURI;
absoluteURI = new URI(base);
Now absoluteURI is “classpath:my/class/path/” as a URI.
resolvedURI = absoluteURI.resolve(relativeURI);
And here we find the heart of the problem. The Java URI class resolves
this incorrectly. :-(
There’s a utility class in XML Resolver that does the right thing, so
maybe I noticed this at one point and worked around it:
resolvedURI = URIUtils.resolve(absoluteURI, relativeURI);
I’ll have to investigate some more.
Saxonica Developer Community notifications@plan.io writes:
[[PGP Signed Part:Undecided]]
RE: Saxon 11.1 URI Resolvers - Added by Norm Tovey-Walsh almost 3 years ago
Saxonica Developer Community notifications@plan.io writes:
[[PGP Signed Part:Undecided]]
RE: Saxon 11.1 URI Resolvers - Added by Vladimir Nesterovsky almost 3 years ago
My test was for exposition only.
What I want to tell is that, with Saxon 11.1, I could not create xslt stored inside class path and refer relatively to other xslt, also stored in class path. In my case I have structure:
- META-INF/stylesheets/lib1/a.xslt
- META-INF/stylesheets/lib2/b.xslt
where a.xslt includes relatively b.xslt. In my case xslts might be stored in different jars.
In fact my latest tests show that even absolute "classpath:..." references do not work in latest version, as it expects that there is "classpath:" protocol handler registered.
Please register to reply