Problem with composite key which raises "a sequence of more than one item is not allowed as the @use attribute of xsl:key" warning and then an error about a circular definition
Added by Martin Honnen over 6 years ago
I thought I had a nice XSLT 3 approach to https://stackoverflow.com/questions/51564679/xslt-merging-data-between-two-parts-of-xml-conditionally-into-the-second-part with a composite key with the various key values being defined in the sequence constructor:
<xsl:key name="map" match="Message1/Response/CE//*[action = 'New']" composite="yes">
<xsl:sequence select="ancestor::CE/id"/>
<xsl:sequence select="node-name()"/>
<xsl:variable name="pos" as="xs:integer">
<xsl:number/>
</xsl:variable>
<xsl:sequence select="$pos"/>
</xsl:key>
When I try to use that in
<xsl:template match="Message2/Response/CE//*[key('map', (ancestor::CE/id, node-name(), count((., preceding-sibling::*[node-name() = node-name(current())]))))]">
<xsl:copy-of select="key('map', (ancestor::CE/id, node-name(), count((., preceding-sibling::*[node-name() = node-name(current())]))))"/>
</xsl:template>
Altova handles it fine but Saxon (Saxon-HE 9.8.0.14J) tells me
Warning at char 8 in xsl:template/@match on line 22 column 162 of test2018072701.xsl: XPTY0004: An error occurred matching pattern {element()[key("map", data(Block(docOrder(reverse(ancestor::element(Q{}CE))/child::element(Q{}id)), node-name(.), count(Block(., reverse(preceding-sibling::element()[node-name(.) = node-name(($Q{http://www.w3.org/2005/xpath-functions}current) treat as node())]))))))]}: A sequence of more than one item is not allowed as the @use attribute of xsl:key (, human_information, 1)
and
Error at char 28 in xsl:template/@match on line 22 column 162 of test2018072701.xsl: XTDE0640: Key definition is circular at xsl:apply-templates (file:/C:/SomePath/test2018072701.xsl#19) processing /Messages/Message2[1] in built-in template rule for /Messages in the unnamed mode Key definition is circular
The warning about the sequence of more than one item not being allowed seems wrong given XSLT 3, I am not sure about the circular key, whether that is caused by the warning or some other issue.
As Altova runs it, I wonder whether the issue at least needs test coverage for better interoperability.
The full XSLT is
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="map" match="Message1/Response/CE//*[action = 'New']" composite="yes">
<xsl:sequence select="ancestor::CE/id"/>
<xsl:sequence select="node-name()"/>
<xsl:variable name="pos" as="xs:integer">
<xsl:number/>
</xsl:variable>
<xsl:sequence select="$pos"/>
</xsl:key>
<xsl:template match="Messages">
<xsl:apply-templates select="Message2"/>
</xsl:template>
<xsl:template match="Message2/Response/CE//*[key('map', (ancestor::CE/id, node-name(), count((., preceding-sibling::*[node-name() = node-name(current())]))))]">
<xsl:copy-of select="key('map', (ancestor::CE/id, node-name(), count((., preceding-sibling::*[node-name() = node-name(current())]))))"/>
</xsl:template>
</xsl:stylesheet>
the XML taken from SO is
<?xml version="1.0" encoding="UTF-8"?>
<Messages>
<Message1>
<Response>
<CE>
<id>1</id>
<human>
<name>Frank</name>
<human_information>
<action>New</action>
<title>Doctor</title>
</human_information>
<phone>
<action>Old</action>
<phone_number>1234567</phone_number>
</phone>
</human>
</CE>
</Response>
<Response>
<CE>
<id>2</id>
<human>
<name>Bob</name>
<human_information>
<action>New</action>
<title>Artist</title>
</human_information>
<phone>
<action>Old</action>
<phone_number>13579</phone_number>
</phone>
</human>
</CE>
</Response>
<Response>
<CE>
<id>3</id>
<human>
<name>Alice</name>
<human_information>
<action>Old</action>
<title>Designer</title>
</human_information>
<phone>
<action>New</action>
<phone_number>9876543</phone_number>
</phone>
</human>
</CE>
</Response>
</Message1>
<Message2>
<Response>
<CE>
<id>2</id>
<human>
<name>Bob</name>
<human_information>
<title>Artist</title>
</human_information>
<phone>
<phone_number>13579</phone_number>
</phone>
<phone>
<phone_number>24680</phone_number>
</phone>
</human>
</CE>
</Response>
<Response>
<CE>
<id>3</id>
<human>
<name>Alice</name>
<human_information>
<title>Designer</title>
</human_information>
<phone>
<phone_number>9876543</phone_number>
</phone>
<phone>
<phone_number>0909090</phone_number>
</phone>
</human>
</CE>
</Response>
</Message2>
</Messages>
the task, as described there, as far as I understand it, is to find Message1/Response/CE//*[action = 'New']
items to replace the corresponding Message2/Response/CE//*@
item.
Replies (2)
RE: Problem with composite key which raises "a sequence of more than one item is not allowed as the @use attribute of xsl:key" warning and then an error about a circular definition - Added by Michael Kay over 6 years ago
Saxon is incorrectly setting the required type of the "use" expression to anyAtomicType?
rather than anyAtomicType*
in the case where the expression is computed in the body of the xsl:key rather than in an "@use" attribute.
The error is detected during pattern evaluation, and is therefore recovered as required by §5.5.4 in the spec.
The "circularity" error, I think, is spurious: it happens because when we hit the error during pattern evaluation, we leave the key in a state of "under construction", and when a second attempt is made to use the key, and it is found to be "under construction", we wrongly assume that this is caused by a circularity in the definition.
XSLT 3.0 test case key-097 added.
Please register to reply