Project

Profile

Help

Bug #4097

closed

Base URI of a copied node

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

Status:
Closed
Priority:
Normal
Assignee:
Category:
XSLT conformance
Sprint/Milestone:
-
Start date:
2019-01-16
Due date:
% Done:

100%

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

Description

T. Hatanaka reports:

With the attached files, Saxon 9.8 outputs:

C:>java -jar SaxonEE9-8-0-15J\saxon9ee.jar -s:test.xml -t -xsl:test.xsl Saxon-EE 9.8.0.15J from Saxonica Java version 1.8.0_191 Using license serial number V006911 ...

   <test>
      <original>file:/C://test.xml</original>
      <built-in>file:/C://test.xsl</built-in>
      <traditional>file:/C://test.xsl</traditional>
   </test>

9.9 outputs differently:

C:>java -jar SaxonEE9-9-0-2J\saxon9ee.jar -s:test.xml -t -xsl:test.xsl Saxon-EE 9.9.0.2J from Saxonica ...

   <test>
      <original>file:/C://test.xml</original>
      <built-in/>
      <traditional>file:/C://test.xml</traditional>
   </test>

So I'm at a loss what is the expected behavior.

Actions #1

Updated by Michael Kay over 5 years ago

The base URI is not being set (or is being set to null) for an element node that is created using the built-in shallow copy template. In this case (assuming the resulting node is parentless), the base URI of the original node should be retained.

The immediate cause is that in TinyBuilder.startElement(), the code that sets base URI has been changed:

Old code

//        if (!pipe.isLocationIsCodeLocation() && location.getSystemId() != null) {
//            tt.setSystemId(nodeNr, location.getSystemId());
//        } 

New code:

        if (isUseEventLocation() && location.getSystemId() != null) {
            tt.setSystemId(nodeNr, location.getSystemId());
        }

That is, the decision to copy the systemId of the event location to become the base URI of the new element node now depends on a setting on the Builder, rather than a setting on the PipelineConfiguration.

The reason for the change was to fix a problem connected with the base URI of nodes derived from xi:include processing. I'm afraid that the algorithms for computing base URI are very fragile; the rules are highly contextual and it's hard to get all the right information to the right place to make the necessary decisions.

Actions #2

Updated by Michael Kay over 5 years ago

The code for explicit construction of element nodes (e.g. using xsl:element or xsl:copy) has this logic:

            if (elemOut.getSystemId() == null) {
                elemOut.setSystemId(getNewBaseURI(context, copiedNode));
            }

and I suspect we need the same thing for built-in template rules. In the case of xsl:copy, getNewBaseURI() returns the base URI of the source node. The logic here is that the base URI for the receiver, and hence for the whole constructed tree, is determined by the base URI of the outermost element, so it is set for the receiver if no base URI has already been set for a parent node.

However, this logic feels incorrect for the case where we are copying a sequence of element nodes that have different base URIs -- it looks to me as if the result nodes will all take their base URI from the first one. Perhaps this needs (yet another) test case.

Actions #3

Updated by Michael Kay over 5 years ago

Adding the logic to initialize systemId of the receiver fixes the supplied test case, but unfortunately my suspicions are confirmed that it only works for the first top-level element in a sequence. If I change the test to:

      <xsl:template as="element(test)" match="document-node()">
		<xsl:variable name="baa" select="doc('baa.xml')/*"/>
		<test>
			<xsl:for-each select="element(foo)">
				<original1>
					<xsl:value-of select="base-uri()" />
				</original1>
				<original2>
					<xsl:value-of select="base-uri($baa)" />
				</original2>

				<xsl:variable as="element(*)*" name="built-in">
					<xsl:apply-templates mode="built-in-shallow-copy" select="., $baa" />
				</xsl:variable>
				<built-in1>
					<xsl:value-of select="base-uri($built-in[1])" />
				</built-in1>
				<built-in2>
					<xsl:value-of select="base-uri($built-in[2])" />
				</built-in2>

				<xsl:variable as="element(*)*" name="traditional">
					<xsl:apply-templates mode="traditional-identity" select="., $baa" />
				</xsl:variable>
				<traditional1>
					<xsl:value-of select="base-uri($traditional[1])" />
				</traditional1>
				<traditional2>
					<xsl:value-of select="base-uri($traditional[2])" />
				</traditional2>
			</xsl:for-each>
		</test>
	</xsl:template>

I get the output:

<test>
   <original1>file:/Users/mike/bugs/2019/4097-hatanaka/test/test.xml</original1>
   <original2>file:/Users/mike/bugs/2019/4097-hatanaka/test/baa.xml</original2>
   <built-in1>file:/Users/mike/bugs/2019/4097-hatanaka/test/test.xml</built-in1>
   <built-in2>file:/Users/mike/bugs/2019/4097-hatanaka/test/test.xml</built-in2>
   <traditional1>file:/Users/mike/bugs/2019/4097-hatanaka/test/test.xml</traditional1>
   <traditional2>file:/Users/mike/bugs/2019/4097-hatanaka/test/test.xml</traditional2>
</test>
Actions #4

Updated by Michael Kay over 5 years ago

We can fix this by setting systemId=null in SequenceWriter after an endDocument() or endElement() event that takes the nesting depth down to zero. Whether this breaks anything else is another question...

Actions #5

Updated by Michael Kay over 5 years ago

The change appears to cause no regression, so I will commit it, and add some new test cases.

Actions #6

Updated by Michael Kay over 5 years ago

  • Status changed from New to Resolved
  • Applies to branch 9.9 added
  • Fix Committed on Branch 9.9 added

I have added XSLT 3.0 test case base-uri-053 which tests all the various options.

Further changes were needed to get the correct behaviour on document nodes as well as element nodes, and on built-in deep copy as well as shallow copy.

Actions #7

Updated by O'Neil Delpratt about 5 years ago

  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 9.9.1.1 added

Bug fix applied to the Saxon 9.9.1.1 maintenance release.

Actions #8

Updated by O'Neil Delpratt about 5 years ago

  • Status changed from Resolved to Closed
Actions #9

Updated by Michael Kay about 5 years ago

  • Status changed from Closed to In Progress

Re-opened because one aspect of the new test base-uri-053 is failing with -export:off, though it succeeds with -export:on.

The failure occurs on the case where xsl:copy/ is called to copy a document node. (Built-in template rules are not involved...). The export=on and export=off paths are (worryingly!) different: with export=off, preservingTypes is false, with export=on, it is true.

(I was wondering how this passed the 9.9.1.1 release. The answer is that the new test hadn't yet been committed, so it wasn't included in the release tests)

Actions #10

Updated by Michael Kay about 5 years ago

  • Category set to XSLT conformance
  • Status changed from In Progress to Resolved
  • Applies to branch trunk added
  • Fix Committed on Branch trunk added

Fixed by adding

                if (out.getSystemId() == null) {
                    out.setSystemId(source.getBaseURI());
                }

to the logic for shallow copy of document nodes.

I haven't established why the export and non-export cases are following different paths; that seems an orthogonal problem.

Actions #11

Updated by O'Neil Delpratt almost 5 years ago

  • Status changed from Resolved to Closed

Please register to edit this issue

Also available in: Atom PDF