Project

Profile

Help

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 almost 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 almost 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.

    (1-2/2)

    Please register to reply