Project

Profile

Help

Bug #2843

closed

Transformer.URIResolver should default to TransformerFactory.URIResolver

Added by Michael Kay over 7 years ago. Updated almost 7 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
JAXP Java API
Sprint/Milestone:
-
Start date:
2016-07-16
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
9.7, trunk
Fix Committed on Branch:
9.7, trunk
Fixed in Maintenance Release:
Platforms:

Description

Raised by Jorge Williams on the saxon-help malling list at SourceForge.

It seems that Transformer.getURIResolver() returns null, rather than returning the URIResolver set on the TransformerFactory.

Actions #1

Updated by Michael Kay over 7 years ago

  • Subject changed from Transformer.ErrorListener should default to TransformerFactory.ErrorListener to Transformer.URIResolver should default to TransformerFactory.URIResolver
Actions #2

Updated by Michael Kay over 7 years ago

A bit of investigation into the places in the code where a URIResolver can be set (or got):

  • Setting the configuration property FeatureKeys.URI_RESOLVER_CLASS has the effect of instantiating the specified class and calling Configuration.setURIResolver() supplying this instance.

  • Getting the configuration property FeatureKeys.URI_RESOLVER_CLASS has the effect of calling Configuration.getURIResolver() and returning

the class name of the returned instance.

  • Calling Configuration.setURIResolver() sets the internal variable Configuration.uriResolver, and also sets the uriResolver held in Configuration.defaultXsltCompilerInfo.

  • Calling Configuration.getURIResolver() returns the value of the internal variable Configuration.uriResolver if it is non-null; otherwise it returns the value of Configuration.systemURIResolver which is initialized to an instance of net.sf.saxon.lib.StandardURIResolver and is never modified.

  • Setting the configuration property FeatureKeys.XSL_STATIC_URI_RESOLVER_CLASS instantiates the supplied class and sets the uriResolver held in Configuration.defaultXsltCompilerInfo to this instance.

  • Getting the configuration property FeatureKeys.XSL_STATIC_URI_RESOLVER_CLASS gets the uriResolver held in Configuration.defaultXsltCompilerInfo and returns its class name.

  • The field Configuration.defaultXsltCompilerInfo.uriResolver is initialized to an instance of net.sf.saxon.lib.StandardURIResolver.

  • xsl:include and xsl:import use the URIResolver held in the CompilerInfo

  • xsl:import-schema, contrary to the documentation, appears to use the URIResolver held in the Configuration, ignoring any URIResolver set at the XsltCompiler level.

  • The Controller object has a userURIResolver field which is set/got by its setURIResolver() and getURIResolver() methods. It also has a standardURIResolver field which is initialized to the value of Configuration.systemURIResolver(), which (as we have seen) is always an instance of net.sf.saxon.lib.StandardURIResolver.

  • The XPathContext object has a uriResolver field. It's not entirely clear what purpose this serves. It is set only by the XPathDynamicContext class, that is, when running free-standing XPath expressions (at the level of the sxpath package). Its main purpose appears to be the provision of a finer-grained URI resolver for use when running XSD assertions.

  • The doc() and document() functions use the URIResolver held in the XPathContext object, which defaults to the one held in the Controller; if there is no user-set URIResolver in the Controller, they use the systemURIResolver instead.

At the s9api level:

  • Instantiating an XsltCompiler creates a new CompilerInfo whose URIResolver is initially defaulted from the instance held in Configuration.defaultXsltCompilerInfo.

  • Calling XsltCompiler.setURIResolver() modifies the setting in the contained CompilerInfo. (The documentation for this method explicitly says that this URIResolver is NOT used at run-time for resolving calls on document()

  • Calling XsltCompiler.getURIResolver() returns this setting.

  • Calling XsltTransformer.setURIResolver() or Xslt30Transformer.setURIResolver() sets the URIResolver held in the Controller

  • Calling XsltTransformer.getURIResolver() or Xslt30Transformer.getURIResolver() gets the URIResolver held in the Controller

At the JAXP level:

  • Setting TransformerFactory.setURIResolver() calls Configuration.setURIResolver()

  • Getting TransformerFactory.getURIResolver() calls Configuration.getURIResolver()

  • The TransformerImpl object, which implements JAXP Transformer, has its own URIResolver field, and also holds a s9api XsltTransformer. Calling setURIResolver on the TransformerImpl sets the local URIResolver field, and also calls XsltTransformer.setURIResolver(). The local field is initially null. Calling TransformerImpl.getURIResolver() returns the value of the local field.

Actions #3

Updated by Michael Kay over 7 years ago

So I think the specific issue in this bug report is probably that there is a difference between

(a) the URIResolver actually used to resolve a call on document() - which will be the one set on the TransformerFactory

(b) the URIResolver returned by Transformer.getURIResolver() - which is null

In general I think the most natural reading of the JAXP specification is that Transformer.getURIResolver() should return the resolver that will actually be used. The only tricky part is interpreting what the specification means with respect to setting the URIResolver to null. The spec says "the transformer will no longer have a resolver". But what happens when "the transformer has no resolver"? Does document() then fail, or does it use the fallback resolver? If it uses the fallback resolver and if Transformer.getURIResolver() is supposed to always return the resolver that will actually be used by document(), then getURIResolver() can never return null, because there is always a fallback. The JAXP spec is clear that getURIResolver() can return null, but it gives no suggestions as to when this might happen.

As so often happens with JAXP, the Javadoc seems to lack precision (the absence of an approved test suite exacerbates this).

I think what I shall do is as follows:

  • Initialize the value of TransformerImpl.uriResolver to the value of Configuration.uriResolver.

This means that:

  • If TransformerImpl.setURIResolver() is NOT called, getURIResolver() will return the value set on the factory, which is the same as the value that will actually be used.

  • If TransformerImpl.setURIResolver() IS called with a non-null resolver, getURIResolver() will return the value that was set, which is the same as the value that will actually be used.

  • If TransformerImpl.setURIResolver() is called with a NULL resolver, getURIResolver() will return null, while the value actually used by document() will still be the resolver set on the factory.

Actions #4

Updated by Michael Kay over 7 years ago

  • Status changed from New to Resolved
  • Applies to branch 9.8 added
  • Fix Committed on Branch 9.7, 9.8 added

Patched as suggested on the 9.7 and 9.8 branches.

Actions #5

Updated by O'Neil Delpratt over 7 years ago

  • % Done changed from 0 to 100

Bug fix applied in the Saxon 9.7.0.8 maintenance release.

Actions #6

Updated by O'Neil Delpratt over 7 years ago

  • Status changed from Resolved to Closed
  • Fixed in Maintenance Release 9.7.0.8 added
Actions #7

Updated by O'Neil Delpratt almost 7 years ago

  • Applies to branch trunk added
  • Applies to branch deleted (9.8)
Actions #8

Updated by O'Neil Delpratt almost 7 years ago

  • Fix Committed on Branch trunk added
  • Fix Committed on Branch deleted (9.8)

Please register to edit this issue

Also available in: Atom PDF