XSLT for each letter in a string

I am writing an XSLT transformation (for XSL-FO) and I need to repeat something for each letter in a string value, for example:

If the string is stored in the string MyData/MyValue (for example, MyData.MyValue = "something"), I need for each, like this one:

 <xsl:for-each select="MyData/MyValue"> <!-- What goes here to iterate through letters? --> <someTags> <xsl:value-of select="Letter" /> <!-- What goes here to output current letter? --> </someTags> </xsl:for-each> 

Any ideas?

+7
source share
6 answers

you can use the call pattern and transfer parameters, and then use recursion to call the pattern until there are no characters left.

added below.

on this xml

 <?xml version="1.0" encoding="utf-8"?> <data> <node>something</node> </data> 

and this xslt

 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" > <xsl:output method="xml" indent="yes"/> <xsl:template match="data/node"> <xsl:call-template name="for-each-character"> <xsl:with-param name="data" select="."/> </xsl:call-template> </xsl:template> <xsl:template name="for-each-character"> <xsl:param name="data"/> <xsl:if test="string-length($data) &gt; 0"> <someTags> <xsl:value-of select="substring($data,1,1)"/> </someTags> <xsl:call-template name="for-each-character"> <xsl:with-param name="data" select="substring($data,2)"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> 

you can manipulate the if statement to do other things!

+10
source

You can try this dirty hack hack that has proven that it works again and again:

 <xsl:for-each select="//*[position() &lt;= string-length(MyData/MyValue)]"> <someTags> <xsl:value-of select="substring(MyData/MyValue, position(), 1)"/> </someTags> </xsl:for-each> 

This will work if //* matches more nodes than the number of characters in your line ... Of course, this also deserves an odd line of comment for a poor colleague reading your code afterwards ... ;-)

Note I know there are XSLT purists. But when you need to do this work and don’t worry about XSLT hyper verbosity, sometimes these tricks are awesome! IMO

Note also . I posed a performance issue here to make sure iteration or recursion works better: XSLT iteration or recursion performance

+7
source

I am not sure about the possibility of iteration. You can use recursion as shown in other answers. This is my suggestion (not much different from others, except that I use pattern matching patterns and unnamed patterns):

  <xsl:template match="MyData/MyValue"> <xsl:param name="sub" select="."/> <xsl:variable name="subsub" select="substring($sub,1,1)"/> <xsl:if test="boolean($subsub)"> <someTags> <xsl:value-of select="$subsub"/> </someTags> <xsl:apply-templates select="self::node()"> <xsl:with-param name="sub" select="substring($sub,2)"/> </xsl:apply-templates> </xsl:if> </xsl:template> 
+4
source

You can use recursion:

 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <xsl:call-template name="get-letters"> <xsl:with-param name="input">something</xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template name="get-letters"> <xsl:param name="input"/> <xsl:if test="string-length($input)"> <xsl:value-of select="substring($input, 1, 1)"/> <xsl:text>&#xA0;</xsl:text> <xsl:call-template name="get-letters"> <xsl:with-param name="input" select="substring($input, 2)"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> 

Conclusion: s o m e t h i n g

+3
source

Good question, +1.

This is what the str-map template / function from FXSL is for :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net/" xmlns:testmap="testmap" exclude-result-prefixes="xsl f testmap"> <xsl:import href="str-dvc-map.xsl"/> <!-- to be applied on any xml source --> <testmap:testmap/> <xsl:output method="text"/> <xsl:template match="/"> <xsl:variable name="vFunTripple" select="document('')/*/testmap:*[1]"/> <xsl:call-template name="str-map"> <xsl:with-param name="pFun" select="$vFunTripple"/> <xsl:with-param name="pStr" select="'something'"/> </xsl:call-template> </xsl:template> <xsl:template name="trippleChar" match="testmap:*" mode="f:FXSL"> <xsl:param name="arg1"/> <xsl:value-of select="concat($arg1,$arg1,$arg1)"/> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to any XML document (not used), the desired result is created :

 sssooommmeeettthhhiiinnnggg 
+3
source

Several XSLT 1.0 solutions have been published (as this is what the original poster needs). For comparison, here's how to do it in XSLT 2.0 using xsl: analy-string :

 <xsl:analyze-string select="MyData/MyValue" regex="."> <xsl:matching-substring> <someTags> <xsl:value-of select="."/> </someTags> </xsl:matching-substring> </xsl:analyze-string> 
+2
source

All Articles