Reputation: 61
Is it possible to check if a string exists in an array of strings in XSL? I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<ItemsArr>
<it attr="DANCHO">
<title>1</title>
</it>
<it attr="DAN">
<title>2</title>
</it>
<it attr="IVANCHO">
<title>3</title>
</it>
<it attr="DRAGANCHO">
<title>4</title>
</it>
<it attr="PETKANCHO">
<title>5</title>
</it>
<keys>
<itemKey>DANCHO</itemKey>
<itemKey>THISISONLYFORTESTING</itemKey>
</keys>
</ItemsArr>
And the following XSL transformation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<xsl:variable name="items" select="ItemsArr/keys/itemKey"/>
<xsl:for-each select="/ItemsArr/it[contains($items,@attr)]">
<tr>
<td><xsl:value-of select="@attr"/></td>
<td><xsl:value-of select="title"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I want to store all the keys (ItemsArr/Keys) in an array ($items) and then iterate over the it-s, which attr value exists in the $items array. Note that with the above data, both it are selected. If the two keys are swapped (DANCHO and THISISONLYFORTESTING) then nothing is selected.
Upvotes: 2
Views: 5023
Reputation: 630
I know that the following is not a direct answer to the question since I suspect that the desire is to apply a native XSLT construct for the purpose. However, I can say that I solved a similar issue by introducing an extension function (https://www.saxonica.com/html/documentation/extensibility/integratedfunctions/) based on Java code which the Saxon XSLT processor supports. You could alternatively do the same thing in .NET using Saxon or the built-in .NET XSLT processor, using the Python XSLT processor or whatever XSLT processor of your choice supporting extension functions.
The function I wrote would takes three arguments: 1) A delimiter (e.g. comma), 2) a string separated by the delimiter, 3) a string representing what to query. If we assume the function is named ‘contains’, an example of applying the function would be: ‘contains(“1,2,3,6”, “,”, “3”)’. Alternatively, XSLT 2.0 and upwards support defining functions like this, so that would be another approach.
Upvotes: 0
Reputation: 477
You should state your problem not how you think you want to solve it because there is no array data structure in XSLT 1 or 2.
If your problem is to implement a data structure you can look up that is what xsl:key is for. So you should read up on xsl:key and the key function.
and then in your code key("array",pathToLookupValue) will tell you whether the value in the path you supply exists in the key you have set up.
Upvotes: 0
Reputation: 70638
contains
is actually a string function, which checks if the first string "contains" the second string. It is not designed to work on node-sets (in XSLT 1.0, if you pass it a node-set, it will get the text value of the first node in that set. In XSLT 2.0, it would get an error).
The expression you could use instead is simply this...
<xsl:for-each select="/ItemsArr/it[@attr = $items/text()]">
So, it will be true if the attr
attribute matches the text node of any of the items in the node-set.
Alternatively, consider using a key for looking-up the value more efficiently.
<xsl:key name="items" match="itemKey" use="text()" />
Then you would look it up like this
<xsl:for-each select="/ItemsArr/it[key('items', @attr)]">
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="items" match="itemKey" use="text()" />
<xsl:template match="/">
<html>
<body>
<table border="1">
<xsl:variable name="items" select="ItemsArr/keys/itemKey"/>
<xsl:for-each select="/ItemsArr/it[key('items', @attr)]">
<tr>
<td><xsl:value-of select="@attr"/></td>
<td><xsl:value-of select="title"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2