Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to to get the desired base URI when xsl is run from another file?

When my tests are run with XSpec, there is a glaring problem: the base URI of global variables is set to the xspec parent that's running my XSLT and not the XML input itself.

Thus, when my XSL transformation is ran by itself against the XML, everything is fine and the global variables are selecting what they should: elements in the input XML.

However, when it is run via XSpec, the base URI is set to XSpec itself - presumably because the XSLT spec defines base URI as:

If an element or processing instruction occurs in an external entity, the base URI of that element or processing instruction is the URI of the external entity; otherwise, the base URI is the base URI of the document.

Which is a problem for me. I've tried using the xml:base attribute on both the variables and the xsl:stylesheet: but that did not seem to affect the base URI; it only affected fn:static-base-uri(). Also, static-base-uri() always returns the right URI I'd like - so I'd like that value to somehow become the base URI for my global variables.

Once I move the variables into a template and they become local, their base URI is fine. But that'll defeat the entire point of using variables for me, and that is not duplicating select calls.

Any tips on how to solve this?

I'm using XSLT 2.0 with SAXON EE 9.4.0.6 (& HE edition).


Update 1

I've done some more investigating, and it seems XSpec calls Saxon in this manner:

java -cp "%CP%" net.sf.saxon.Transform -o:%RESULT% -s:%XSPEC% -xsl:%TEST_STYLESHEET% -it:{http://www.jenitennison.com/xslt/xspec}main

Which means that -s, the source XML file, is the .xspec stylesheet itself. Makes sense if it has to supply some XML data for a transformation to work, but in this case it is the transformation itself that imports the XML data it works with via fn:doc() - and unfortunately within my xsl's global level, the base uri is wrong and not set to the imported document but to the xspec stylesheet.

So, as a test, I set the Saxon -s flag to the XML input document and tada - the base URI is now correct. But this means that I can't use any other xml within xspec and so isn't a very workable solution.


Update 2

Given some more feedback from Michael Kay (thanks!), I've attached the minimal test case I'm working with. You'll also want to download XSpec 0.4-rc1, but that's not necessary.

Once you've got XSpec, if you're on Windows, xspec-0.4.0rc1/bin/xspec.bat needs to be edited to point to the Saxon jar on line 3.

Otherwise, to run it, you do xspec.bat .\DCM2EA.xspec.

The base URI in global in the output will, ideally, point to NEHTA-00009-Adverse_Reaction-Structure (sample data).xml. Right now, it does not - it points to the .xspec. This is directly influenced by -s:%XSPEC% in xspec.bat on line 73.

The way xspec works is that it creates an intermediary transformation given DCM2EA.xspec and its own tests in xspec/DCM2EA.xsl and runs that transformation (that's why XSpec in this case is optional, you can run xspec - bad attribute name/xspec/DCM2EA.xsl directly).

The issue that I'm having is that base-uri() within the global context in the original DCM2EA.xsl is set to the xspec file, which is wrong. The base-uri() inside a template is set fine (as you see by Base URI now in the output), but it's impractical to move the variables to the local scope.

Specifying the input xml data isn't feasible either because my actual .xspec imports several different files, and I don't want to break up the 190 tests I've got and add such workarounds.

I was hoping that xml:base would help here, but I haven't gotten it to work and am out of solutions.

Thanks for looking!

like image 482
Vadim Peretokin Avatar asked Nov 11 '22 23:11

Vadim Peretokin


1 Answers

Because of my constraints I'm not in a position to check your code or run tests, but your situation reminds me of a situation I had where I replaced the following:

<xsl:variable name="x" as="element()">
  <stuff>
    <more/>
  </stuff>
</xsl:variable>
....  select="$x" ...

with the following:

<xsl:variable name="x" as="element()">
  <wrapper xml:base="something">
    <stuff>
      <more/>
    </stuff>
  </wrapper>
</xsl:variable>
.... select="$x/*" ...

That way <stuff> has the base URI but without an xml:base= attribute, yet I'm selecting <stuff> in both situations. I think my issue was that I needed to set the base URI but the DTD validating the document didn't provide for the attribute ... or something along those lines since that doesn't sound quite right as I've written it.

I hope this helps.

like image 135
G. Ken Holman Avatar answered Dec 16 '22 02:12

G. Ken Holman