I need to search for a range of elements based on ID numbers. If the ID number is found, I’ll process it. If the ID is not found, it’ll get filled in with a default value. I’m using XSLT 2.0 in Saxon 9.4 HE.
Here’s a very simplified example. The input XML looks like this:
<root>
<item>
<id>1</id>
</item>
<item>
<id>2</id>
</item>
<item>
<id>4</id>
</item>
</root>
If I’m searching for items whose ID is 1, 2, or 3, I’d like to get the following output. Note that I don’t want any output for item 4.
Found 1
Found 2
Didn't find 3
My first attempt was with a for-each loop but it doesn’t even compile. The error I get is “XPTY0020: Axis step child::element(”:id) cannot be used here: the context item is an atomic value” from the line “”.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="ids" select="(1, 2, 3)"/>
<xsl:template match="/root">
<xsl:for-each select="$ids">
<xsl:choose>
<xsl:when test="count(item/id = .) > 0">
Found <xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
Didn't find <xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
After that I realized I could easily find the matching ones with the following, but I can’t puzzle out a way to find the missing ones.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="ids" select="(1, 2, 3)"/>
<xsl:template match="/">
<xsl:apply-templates select="root/item[id=$ids]"/>
</xsl:template>
<xsl:template match="item">
Found <xsl:value-of select="id"/>
</xsl:template>
</xsl:stylesheet>
BTW, the output also needs to be sorted by ID, which means that dumping a list of all the items that were found, followed by a list of the ones that were not found won’t work. Is this even possible or should I take the easy/wimpy road and change my input?
Here is an example:
[edit]
Your initial attempt was right as for as processing the sequence of ids is concerned, but you need to store the main input document outside of the for-each as inside the context item is an id number value and without the outer variable you wouldn’t be able to access the item elements in the document.
And for efficiency, I added the key.