我需要遍历字符串中的字符以构建XML结构。
目前,我这样做:
<xsl:template name="verticalize">
<xsl:param name="text">Some text</xsl:param>
<xsl:for-each select="tokenize(replace(replace($text,'(.)','$1\\n'),'\\n$',''),'\\n')">
<xsl:element name="para">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
这会产生类似:
<para>S</para>
<para>o</para>
<para>m</para>
<para>e</para>
<para> </para>
<para>t</para>
<para>e</para>
<para>x</para>
<para>t</para>
这适用于Xpath 2.0。但我需要在XPath 1.0环境中应用相同的处理,其中replace()
方法不可用。
你知道实现这个目标的方法吗?
答案 0 :(得分:17)
<xsl:template name="letters">
<xsl:param name="text" select="'Some text'" />
<xsl:if test="$text != ''">
<xsl:variable name="letter" select="substring($text, 1, 1)" />
<para><xsl:value-of select="$letter" /></para>
<xsl:call-template name="letters">
<xsl:with-param name="text" select="substring-after($text, $letter)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
答案 1 :(得分:8)
如果字符串长度不是很大,您可以使用递归调用的模板来实现此目的,将要处理的字符的索引作为参数传递给模板。
像这样:
<xsl:template name="verticalize">
<xsl:param name="text">Some text</xsl:param>
<xsl:param name="index" select="1" />
<xsl:if test="string-length($text) >= $index">
<xsl:element name="para">
<xsl:value-of select="substring($text, $index, 1)"/>
</xsl:element>
<xsl:call-template name="verticalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="index" select="$index+1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
如果字符串比这长,你可以使用类似的方法但使用分而治之的算法,这样你的最大递归深度为log2(字符串长度),如下所示:
<xsl:template name="verticalize">
<xsl:param name="text">Some text</xsl:param>
<xsl:param name="left" select="1" />
<xsl:param name="right" select="string-length($text)" />
<xsl:choose>
<xsl:when test="$left = $right">
<xsl:element name="para">
<xsl:value-of select="substring($text, $left, 1)"/>
</xsl:element>
</xsl:when>
<xsl:when test="$left < $right">
<xsl:variable name="middle" select="floor(($left+$right) div 2)" />
<xsl:call-template name="verticalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="left" select="$left" />
<xsl:with-param name="right" select="$middle" />
</xsl:call-template>
<xsl:call-template name="verticalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="left" select="$middle+1" />
<xsl:with-param name="right" select="$right" />
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
答案 2 :(得分:7)
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vText" select="'Some Text'"/>
<xsl:template match="/">
<xsl:for-each select="string-to-codepoints($vText)">
<para><xsl:sequence select="codepoints-to-string(.)"/></para>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
对于那些学习XSLT 2.0 / XPath 2.0的人,请注意:
使用标准XPath 2.0函数string-to-codepoints()
和codepoints-to-string()
。
在XSLT 2.0中,select
的{{1}}属性的值可以是任何项目的序列,而不仅仅是节点。
答案 3 :(得分:2)
FXSL library提供了许多用于列表处理的通用函数。几乎所有这些都具有用于操作字符串的模拟(将字符串视为字符列表)。
以下是使用str-foldl
函数/模板的示例:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dvc-foldl-func="dvc-foldl-func"
exclude-result-prefixes="xsl dvc-foldl-func"
>
<xsl:import href="dvc-str-foldl.xsl"/>
<dvc-foldl-func:dvc-foldl-func/>
<xsl:variable name="vFoldlFun" select="document('')/*/dvc-foldl-func:*[1]"/>
<xsl:output encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:call-template name="dvc-str-foldl">
<xsl:with-param name="pFunc" select="$vFoldlFun"/>
<xsl:with-param name="pStr" select="123456789"/>
<xsl:with-param name="pA0" select="0"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="dvc-foldl-func:*">
<xsl:param name="arg1" select="0"/>
<xsl:param name="arg2" select="0"/>
<xsl:value-of select="$arg1 + $arg2"/>
</xsl:template>
</xsl:stylesheet>
此转换计算作为$pStr
参数传递的字符串中的字符总和,并生成正确的结果:
45
使用str-map
模板/功能,我们提供以下简单明了的解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:testmap="testmap"
exclude-result-prefixes="xsl testmap"
>
<xsl:import href="str-dvc-map.xsl"/>
<!-- to be applied on any xml source -->
<testmap:testmap/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vTestMap" select="document('')/*/testmap:*[1]"/>
<xsl:call-template name="str-map">
<xsl:with-param name="pFun" select="$vTestMap"/>
<xsl:with-param name="pStr" select="'Some Text'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="split" match="*[namespace-uri() = 'testmap']">
<xsl:param name="arg1"/>
<para><xsl:value-of select="$arg1"/></para>
</xsl:template>
</xsl:stylesheet>
当应用于任何XML文件(未使用)时,会生成所需的正确结果:
<para>S</para>
<para>o</para>
<para>m</para>
<para>e</para>
<para> </para>
<para>T</para>
<para>e</para>
<para>x</para>
<para>t</para>