How to compare against multiple strings in xslt

2019-01-18 22:00发布

问题:

For comparing an xml string value against multiple strings, I am doing the following.

<xsl:if test="/Lines/@name = 'John' or /Lines/@name = 'Steve' or /Lines/@name = 'Marc' " >

Can any one tell me, instead of using 'or' in the above case, how can I check whether a string is existing in an set of strings using xslt.

Thanks.

回答1:

Three ways of doing this:

  1. Use a pipe (or other appropriate character) delimited string

...

 <xsl:template match=
  "Lines[contains('|John|Steve|Mark|',
                  concat('|', @name, '|')
                 )
         ]
  ">
     <!-- Appropriate processing here -->
 </xsl:template>

.2. Test against an externally passed parameter. If the parameter is not externally set, and we are using XSLT 1.0, the xxx:node-set() extension function needs to be used to convert it to normal node-set, before accessing its children

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <!-- externally-specified parameter -->
 <xsl:param name="pNames">
  <n>John</n>
  <n>Steve</n>
  <n>Mark</n>
 </xsl:param>

 <xsl:template match="Lines">
  <xsl:if test="@name = $pNames/*">
     <!-- Appropriate processing here -->
    </xsl:if>
 </xsl:template>
</xsl:stylesheet>

.3. In XSLT 2.0 compare against a sequence of strings

 <xsl:template match="Lines[@name=('John','Steve','Mark')]">
     <!-- Appropriate processing here -->
 </xsl:template>


回答2:

XSLT 2.0 only: <xsl:if test="/Lines/@name = ('John', 'Steve', 'Marc')">

With XSLT 1.0 you can't write a literal expression representing a sequence of strings or a set of strings but if you know the literal values then you can construct a set of nodes e.g.

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0"
  xmlns:data="http://example.com/data"
  exclude-result-prefixes="data">

  <data:data xmlns="">
    <value>John</value>
    <value>Steve</value>
    <value>Marc</value>
  </data:data>

  <xsl:variable name="values" select="document('')/xsl:stylesheet/data:data/value"/>

  <xsl:template match="...">
     <xsl:if test="/Lines/@name = $values">..</xsl:if>
  </xsl:template>

</xsl:stylesheet>


回答3:

Yep - I use substring - put all your name in a string - xsl:variable - then if contains true, the name is there

e.g.

 <xsl:variable name="months">**janfebmaraprmajjunjulaugsepoktnovdec</xsl:variable>


 <xsl:if test="contains($months,'feb')"> do stuff ...


回答4:

XPath has a some $x in (1,2,..) satisfies $x>10 expression that could be useful for this. See: http://www.java2s.com/Code/XML/XSLT-stylesheet/everyandsomeoperator.htm



回答5:

For space-separated words you can use index-of(tokenize("list of allowed", "\s+"), "needle")) or match to go with regular expressions, although I am pretty sure there is something smarter than this.



回答6:

Other possiblity:

XPath 2.0 (XSLT 2.0)

matches(/Lines/@name, 'John|Steve|Marc')

In XSLT 1.0 you have the similar function matches provided by EXSLT.

Notice

This is not exact match against the string, but a regex match, which in your case seems appropriate anyway.



标签: xml xslt