如果有一种策略可以为模板创建一个通用的模板,使用它可以执行任何转换操作,那将是非常壮观的。如果我可以在不使用任何递归迭代器的情况下摆脱困境,如果在 XSLT 1.0 中隐藏了一些用于此目的的函数的瑰宝,那将同样壮观。
无论如何,我怎样才能做到这一点?我需要求助于 WET 方法,还是有更好的方法?
想要的 DRY-ness 是FXSL的模板/功能的一个微不足道的应用iter
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/" xmlns:myRepeat="f:myRepeat"
exclude-result-prefixes="xsl f myRepeat">
<xsl:import href="iter.xsl"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<myRepeat:myRepeat/>
<xsl:variable name="vFunRepeat" select="document('')/*/myRepeat:*[1]"/>
<xsl:variable name="vAdditive" select="/*/*[1]"/>
<xsl:template match="/*">
<xsl:call-template name="iter">
<xsl:with-param name="pTimes" select="@count"/>
<xsl:with-param name="pFun" select="$vFunRepeat"/>
<xsl:with-param name="pX" select="/.."/>
</xsl:call-template>
</xsl:template>
<xsl:template match="myRepeat:*" mode="f:FXSL">
<xsl:param name="arg1"/>
<xsl:copy-of select="$arg1 | $vAdditive"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<items count="3">
<item>
<name>Name</name>
<description>Description</description>
</item>
</items>
产生了想要的正确结果:
<item>
<name>Name</name>
<description>Description</description>
</item>
<item>
<name>Name</name>
<description>Description</description>
</item>
<item>
<name>Name</name>
<description>Description</description>
</item>
请注意:
您根本不必编写任何递归模板。
与大多数其他 FXSL 的模板一样,该iter
模板非常通用且功能强大,无需程序员一次又一次地编写和调试递归。
FXSL 提供了所需的 DRY-ness 并激发了更抽象的思维——因此更强大的构造——函数、折叠、迭代等。
碰巧这个问题在 XSLT 2.0 ( <xsl:for-each select="1 to @count">
) 中有一个简单的解决方案,但是还有许多其他问题,在 XSLT 2.0 中的解决方案并不那么简单。FXSL 通过使用最通用和最强大的高阶函数(折叠、地图、扫描、拉链等)的通用和强大实现来帮助解决任何此类“困难”问题。
二、使用Piez 方法(当 的值存在已知上限时@count
)
<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="*"/>
<xsl:variable name="vStyle" select="document('')"/>
<xsl:variable name="vNodes" select=
"$vStyle//node()|$vStyle//@* | $vStyle//namespace::*"/>
<xsl:variable name="vAdditive" select="/*/*[1]"/>
<xsl:template match="/*">
<xsl:for-each select="$vNodes[not(position() > current()/@count)]">
<xsl:copy-of select="$vAdditive"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当此转换应用于同一个 XML 文档(如上)时,会产生相同的正确结果:
<item>
<name>Name</name>
<description>Description</description>
</item>
<item>
<name>Name</name>
<description>Description</description>
</item>
<item>
<name>Name</name>
<description>Description</description>
</item>
请注意:
当可以使用 Piez 方法时,可以完全避免递归。
免责声明:
我很高兴在 11 到 12 年前开发 FXSL,从那时起我已经提到过数千次,包括两篇会议论文,却不知道我应该提供免责声明:)