与此类似:Duplicate Element x number of times with XSLT
......但又向前迈进了一步。
我已经有一个xml文档,每个'记录'一次。如果每个记录都有指定的次数需要重复(每个记录不同),那么XSLT是否可以实现?
所以例如:
<?xml version="1.0" standalone="yes"?>
<Parent>
<Record name="1">
<repeat>10</repeat>
<Child1>Value 1</Child1>
<Child2>Value 2</Child2>
</Record>
<Record name="2">
<repeat>5</repeat>
<Child1>Value 1</Child1>
<Child2>Value 2</Child2>
</Record>
<Record name="3">
<repeat>8</repeat>
<Child1>Value 1</Child1>
<Child2>Value 2</Child2>
</Record>
<Record name="4">
<repeat>26</repeat>
<Child1>Value 1</Child1>
<Child2>Value 2</Child2>
</Record>
</Parent>
XLST可以使用repeat标签复制每条记录,以便记录1插入10次,记录2插入5次,等等......?
我问我可能要为每个学生订购一些自己设计的学校圣诞卡打印版本!
答案 0 :(得分:1)
使用XSLT 3(由Saxon 9.8所有版本或Altova 2017和2018支持),您可以将其写成紧凑的
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:mode on-no-match="shallow-copy" streamable="yes"/>
<xsl:output indent="yes"/>
<xsl:template match="Parent">
<xsl:copy>
<xsl:copy-of select="Record!copy-of()!(let $r := . return (1 to repeat)!$r)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者用
简单处理Record
元素可能更好
<xsl:template match="Record">
<xsl:copy-of select="copy-of()!(let $r := . return (1 to repeat)!$r)"/>
</xsl:template>
此外,正如评论中正确指出的那样,正常处理不需要copy-of()
,仅用于流式传输,因此如果streamable="yes"
上没有xsl:mode
,则可以编写模板如
<xsl:template match="Record">
<xsl:copy-of select="(1 to repeat)!current()"/>
</xsl:template>
使用XSLT 2可以使用
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record">
<xsl:copy-of select="for $n in 1 to repeat return current()"/>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
如果使用XSLT 1.0,则升级到XSLT 2.0 ......
但是如果这不可能,那么在XSLT 1.0中你可以使用一个递归的命名模板
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()" name="Identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record">
<xsl:call-template name="Repeat">
<xsl:with-param name="repeat" select="repeat" />
</xsl:call-template>
</xsl:template>
<xsl:template match="repeat" />
<xsl:template name="Repeat">
<xsl:param name="repeat" />
<xsl:call-template name="Identity" />
<xsl:if test="$repeat > 1">
<xsl:call-template name="Repeat">
<xsl:with-param name="repeat" select="$repeat - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
出于示例目的,我的示例包括从输出中删除repeat
。
在XSLT 2.0中,你可以这样做..
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()" name="Identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record">
<xsl:variable name="Record" select="." />
<xsl:for-each select="1 to xs:integer(repeat)">
<xsl:apply-templates select="$Record" mode="Repeat" />
</xsl:for-each>
</xsl:template>
<xsl:template match="repeat" />
<xsl:template match="*" mode="Repeat">
<xsl:call-template name="Identity" />
</xsl:template>
</xsl:stylesheet>