Tuesday, November 4, 2008

fn:contains -> multiple strings to compare with

An XSLT user asked following question on xsl-list:

I want to have something that does this: contains('$d/ris:organ/text()', 'Hamburg' or 'Koblenz' or 'xxx'...) ===> Compare 1 String with multpile strings.

instead of: contains('$d/ris:organ/text()','Hamburg') or contains('$d/ris:organ/text()','Koblenz')...

Andrew Welch suggested following answer:

some $x in ('Hamburg', 'Koblenz', 'xxx') satisfies
contains($d/ris:organ/text(), $x)


This uses the XPath 2.0 quantified expression, "some".

This is cool.

I was prompted to share Andrew's answer here, because I thought of a lengthy and perhaps inefficient solution for this (I feel a bit stupid, actually :) ):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://my-functions"
version="2.0">

<xsl:output indent="yes" omit-xml-declaration="yes" />

<xsl:template match="/">
<xsl:variable name="str" select="'hello xxx dd'" />
<xsl:variable name="list" select="('Hamburg','Koblenz','xxx')" />

<xsl:if test="my:contains($str, $list)">
matches
</xsl:if>

</xsl:template>

<!-- a custom 'contains' implementation -->
<xsl:function name="my:contains" as="xs:boolean">
<xsl:param name="str" as="xs:string" />
<xsl:param name="list" as="xs:string+" />

<xsl:variable name="temp" as="xs:boolean*">
<xsl:for-each select="$list">
<xsl:if test="contains($str, .)">
<xsl:sequence select="xs:boolean('true')" />
</xsl:if>
</xsl:for-each>
</xsl:variable>

<xsl:sequence select="if ($temp[1] = xs:boolean('true')) then
xs:boolean('true') else xs:boolean('false')" />

</xsl:function>

</xsl:stylesheet>

No comments: