我正在编写一个XSLT转换(用于XSL-FO),并且需要为字符串值中的每个字母重复一些内容,例如:
如果字符串存储在MyData/MyValue
字符串中(例如MyData.MyValue =“something”),我需要像这样的for-each:
<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>
有什么想法吗?
答案 0 :(得分:12)
您可以使用调用模板并传递参数,然后使用递归来调用模板,直到没有字符为止。
示例在下面添加。
在这个xml上
<?xml version="1.0" encoding="utf-8"?>
<data>
<node>something</node>
</data>
和这个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) > 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>
然后你就可以在if语句中操作来做更多事情了!
答案 1 :(得分:7)
你可以尝试这种经常被证明有效的丑陋黑客:
<xsl:for-each select="//*[position() <= string-length(MyData/MyValue)]">
<someTags>
<xsl:value-of select="substring(MyData/MyValue, position(), 1)"/>
</someTags>
</xsl:for-each>
如果//*
匹配的节点多于字符串中的字符数,那么这将有效...当然,对于那些读后代码的穷人来说,这也应该得到奇怪的评论...... - )
注意:我知道那里有XSLT纯粹主义者。但是当你需要完成工作而不关心XSLT的超级冗长时,那么有时候这些技巧真棒! IMO
还注意:我在这里提出了一个性能问题,看看迭代或递归是否表现更好:XSLT iteration or recursion performance
答案 2 :(得分:4)
我不确定迭代的可行性。您可以使用其他答案中显示的递归。这是我的提议(除了我使用模板匹配模式而不是命名模板之外的其他方面没有太大区别):
<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>
答案 3 :(得分:3)
您可以使用递归:
<?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> </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>
输出:
s o m e t h i n g
答案 4 :(得分:3)
好问题,+ 1。
这是str-map
中{/ 3}}的模板/函数:
<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>
当此转换应用于任何XML文档(未使用)时,生成所需结果:
sssooommmeeettthhhiiinnnggg
答案 5 :(得分:2)
已发布了几个XSLT 1.0解决方案(因为这是原始海报所需的)。但是,为了比较,以下是使用xsl:analyze-string在XSLT 2.0中完成此操作的方法:
<xsl:analyze-string select="MyData/MyValue" regex=".">
<xsl:matching-substring>
<someTags>
<xsl:value-of select="."/>
</someTags>
</xsl:matching-substring>
</xsl:analyze-string>