Project

Profile

Help

Failed to load XML files inside XSLT

Added by Yevgeniy Yanavichus over 3 years ago

  1. We have different sets of stylesheets (modules). Each module looks like this:
lib1.xslt
lib2.xslt
...
lib10.xslt

transform.xslt

fileName1.xml
fileName2.xml

Some xslt files can have XML files loaded via:

<xsl:variable name="mapping" select="document(fileName1.xml')/mapping" />
  1. Then we compile modules and get folders like this:
transform.sef

fileName1.xml
fileName2.xml
  1. Each module is in it's own folder:
sef/module1/*
sef/module2/*
sef/module3/*

...
  1. When we run transformation from command line using JAR file and from saxon-node everything is fine

  2. But when we run this modules from s9api by putting these modules to resources folder we're getting messages like this:

Warning on line 715 of lib5.xslt:
  FODC0002: I/O error reported by XML parser processing
  file:/D:/Code/HERE_IT_IS_PATH_TO_ROOT_PROJECT_FOLDER_NOT_TO_THE_RESOURCES_AND_NOT_TO_THE_MODULE_INSIDE_RESOURCES/fileName1.xml:
  D:\Code\HERE_IT_IS_PATH_TO_ROOT_PROJECT_FOLDER_NOT_TO_THE_RESOURCES_AND_NOT_TO_THE_MODULE_INSIDE_RESOURCES\fileName1.xml (The system
  cannot find the file specified)
Warning on line 715 of lib5.xslt:
  FODC0002: Document has been marked not available: fileName1.xml
Warning on line 715 of lib5.xslt:
  FODC0002: Document has been marked not available: fileName1.xml
Warning on line 715 of lib5.xslt:
  FODC0002: Document has been marked not available: fileName1.xml
Warning on line 715 of lib5.xslt:
  FODC0002: Document has been marked not available: fileName1.xml
Warning on line 254 of lib5.xslt:
  FODC0002: Document has been marked not available: fileName1.xml

Any idea how to fix it? Maybe we should use any type of custom url resolvers? I did a brief check of resolvers here: https://www.saxonica.com/documentation9.2/javadoc/net/sf/saxon/FeatureKeys.html, but still not sure which one to use


Replies (8)

Please register to reply

RE: Failed to load XML files inside XSLT - Added by Michael Kay over 3 years ago

Here are a few suggested approaches.

(a) Change the calls on document() in the stylesheet to call resolve-uri() explicitly, perhaps taking the base URI from the value of a stylesheet parameter.

(b) Change the calls on document() to use a classpath URI ("classpath://fileName1.xml") to load them from the Java classpath.

(c) When you generate the SEF file, specify -relocate:on. If you do this, a relative URI passed to the document() function will be interpreted as relative to the location of the SEF file, not relative to the location of the source XSLT module. (However, from your description, I'm not sure this is what you want, as the documents seem to be in a different folder).

(d) Supply a run-time URIResolver (Xslt30Transformer.setURIResolver()) to resolve the references.

RE: Failed to load XML files inside XSLT - Added by Yevgeniy Yanavichus over 3 years ago

I tried first three options but they didn't help. Fourth point is no about s9api as I understood. I'll try to describe this issue from another view:

  1. We have compiled SEF file with siblings XML files nearby:
D:\Code\com\company\project\resources\static\module1\transform.sef
D:\Code\com\company\project\resources\static\module1\file1.xml
D:\Code\com\company\project\resources\static\module1\file2.xml
D:\Code\com\company\project\resources\static\module1\file3.xml

Here we load transform.sef via:

resourceLoader.getResource("classpath:static/sef/module1/transform.sef");

And get exception saying that XML files could not be loaded from folder D:\Code\com\company\project\

  1. When using similar project structure either using saxon-node or from command line it works fine:
D:\Code\project\sef\transform.sef
D:\Code\project\sef\file1.xml
D:\Code\project\sef\file2.xml
D:\Code\project\sef\file3.xml

D:\Code\project\app.js

Here we load transform.sef and don't care about XML files at all

  1. We opened SEF file in text editor and see that we have references to file names like:
file1.xml
file2.xml
file3.xml

We also tried:

./file1.xml
./file2.xml
./file3.xml
  1. I agree that resolve-uri can potentially help - it's creating full path to the XML file. But would be good to have it working in development as well. So, the question is: can we use any kind of URI resolver so that it accepts SEF file name and XML file name and produces final full path to XML (using base path from SEF file name)?

RE: Failed to load XML files inside XSLT - Added by Michael Kay over 3 years ago

A couple of questions:

(a) Did you use the -relocate option when creating the SEF file?

(b) You say you loaded the SEF file using resourceLoader.getResource("classpath:static/sef/module1/transform.sef");. I guess you're talking here about the Spring ResourceLoader. This method returns a Resource object. What do you then do with this Resource object? How do you construct the Source object that is passed to the Saxon XsltCompiler? Does this Source object have a known systemId property? If it doesn't, then Saxon can't know where the SEF file was loaded from, and can't load other things relative to it.

RE: Failed to load XML files inside XSLT - Added by Yevgeniy Yanavichus over 3 years ago

(a) Yes. Full command:

java -jar .\saxon\saxon9ee.jar -xsl:.\xslt\module1\transform.xsl -export:.\sef\module1\transform.sef -target:PE -nogo -relocate:on

(b) Yes, it's Spring project. Here it's full code:

XsltCompiler compiler = getProcessor().newXsltCompiler();

final Resource xslFileResource = resourceLoader.getResource("classpath:static/sef/gp/transform.sef");

// return compiler.loadExecutablePackage(new URI("classpath:static/sef/module1/transform.sef"));

return compiler.compile(new StreamSource(xslFileResource.getInputStream()));

Transformation with commented line also works but I decided to stay with compile (I agree looks strange to compile already precompiled stylesheet but I didn't have too much time investigating that)

I'm not sure about systemId property. Probably no. I guess it's about jaxp, but I decide to stay with s9api (you also recommended that in another thread)

RE: Failed to load XML files inside XSLT - Added by Michael Kay over 3 years ago

OK, try changing the call to

new StreamSource(xslFileResource.getInputStream(), "classpath:static/sef/gp/transform.sef")

That way, Saxon will know the stylesheet location and will be able to resolve other URIs relative to that location.

The only caveat is, it won't be using Spring to locate these resources, so the search might not be identical to the one that Spring will do. Instead, it will be using classLoader.getResourceAsStream() (and if you need to know exactly which classloader, the answer gets complicated). But give that a try. If it doesn't work, you'll have to resort to using your own URIResolver that invokes Spring.

RE: Failed to load XML files inside XSLT - Added by Michael Kay over 3 years ago

In fact, I don't know if this is going to be necessary, but if you want all resource loading to go via Spring (which might be handy for things like system logging and diagnostics), then the way to do it is probably to register your own DynamicLoader with the Saxon Configuration. You could do something like

class SpringDynamicLoader extends net.sf.saxon.trans.DynamicLoader {

    public SpringDynamicLoader(ResourceLoader springLoader) {
        this.springLoader = springLoader;
    }

    @Override public InputStream getResourceAsStream(String name) {
         return resourceLoader.getResource(name).getInputStream();
    }
}

processor.getUnderlyingConfiguration().setDynamicLoader(new SpringDynamicLoader(resourceLoader));

and then Saxon's dereferencing of the URIs for the XML documents will be done via Spring.

RE: Failed to load XML files inside XSLT - Added by Yevgeniy Yanavichus over 3 years ago

Thanks for you responses. I'll try all of them. I just realized my questions could be not completely correct, because Spring is injecting all resources into JAR file. And final resolved path must be classpath, not filesystem path. And I guess your suggestions should work. Otherwise I'll just used fixed paths different for dev/prod environments.

RE: Failed to load XML files inside XSLT - Added by Yevgeniy Yanavichus over 3 years ago

Tried to pass second parameter, and got error saying the same thing but file path now is classpath:file1.xml. Will try another choice later

    (1-8/8)

    Please register to reply