I have the xpath query:
<xsl:variable name="fbids">
<xsl:sequence select="
feature_relationship[type_id/cvterm[name='molec_deletes' or name='deletes']]
/object_id/feature/feature_synonym/synonym_id/synonym/synonym_sgml"/>
</xsl:variable>
This query does not return a sequence of matching nodes as a sequence itself, it returns them as children of a single #documentfragment. Even if no elements satisfy this query, $fbids is still set to an empty #documentfragment.
This screws up my code whereas the following loop, instead of iterating once per matched element, runs once through for the #documentfragment and that's it. How can I force this to return a nice element()* type?
Thanks!
<xsl:variable name="fbids"> <xsl:sequence select=" feature_relationship[type_id/cvterm[name='molec_deletes' or name='deletes']] /object_id/feature/feature_synonym/synonym_id/synonym/synonym_sgml"/> </xsl:variable>
This query does not return a sequence of matching nodes as a sequence itself, it returns them as children of a single #documentfragment.
Yes, because there is a sequence inside the body of the variable and the variable has no type specified. The default type in such case is: document-node()
.
Solution:
Specify the variable without a body and provide the XPath expression in the select
attribute of xsl:variable
:
<xsl:variable name="fbids" select="
feature_relationship[type_id/cvterm[name='molec_deletes' or name='deletes']]
/object_id/feature/feature_synonym/synonym_id/synonym/synonym_sgml"/>
It is still a good practice to specify the wanted type of the variable using the as
attribute.
A complete answer also must cover the case when the value of the variable (a sequence of elements) is dynamically created inside its body.
Again specifying the type of the variable is key to the solution.
Here is a small and complete example:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:variable name="vMapped" as="element()*">
<xsl:for-each select="num">
<num><xsl:value-of select=".*2"/></num>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$vMapped">
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
the variable named $vMapped
gets its dynamically created value inside its body. The rest of the code successfully uses this variable as a sequence of elements -- each of the elements in this sequence is accessed and copied to the output:
<num>2</num>
<num>4</num>
<num>6</num>
<num>8</num>
<num>10</num>
<num>12</num>
<num>14</num>
<num>16</num>
<num>18</num>
<num>20</num>