我有一个xml如下所示,我想复制n次,同时增加一个元素和一个属性。
<Person position=1>
<name>John</name>
<number>1</number>
<number>1</number>
</Person>
我喜欢下面的内容,增量的数量是变量。
<Person position=1>
<name>John</name>
<number>1</number>
</Person>
<Person position=2>
<name>John</name>
<number>2</number>
</Person>
....
<Person position=n>
<name>John</name>
<number>n</number>
</Person>
任何线索
答案 0 :(得分:4)
予。 XSLT 1.0解决方案:
<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:param name="pTimes" select="5"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
<xsl:with-param name="pPosition" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:param name="pPosition" select="1"/>
<xsl:if test="$pTimes > 0">
<xsl:apply-templates select="*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes -1"/>
<xsl:with-param name="pPosition" select="$pPosition+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Person">
<xsl:param name="pPosition" select="1"/>
<Person position="{$pPosition}">
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</Person>
</xsl:template>
<xsl:template match="number">
<xsl:param name="pPosition" select="1"/>
<number><xsl:value-of select="$pPosition"/></number>
</xsl:template>
</xsl:stylesheet>
将此转换应用于以下XML文档:
<t>
<Person position="1">
<name>John</name>
<number>1</number>
</Person>
</t>
生成了想要的结果:
<Person position="1">
<name>John</name>
<number>1</number>
</Person>
<Person position="2">
<name>John</name>
<number>2</number>
</Person>
<Person position="3">
<name>John</name>
<number>3</number>
</Person>
<Person position="4">
<name>John</name>
<number>4</number>
</Person>
<Person position="5">
<name>John</name>
<number>5</number>
</Person>
<强> II。 XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pNumTimes" as="xs:integer" select="5"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vDoc" select="/"/>
<xsl:for-each select="1 to $pNumTimes">
<xsl:apply-templates select="$vDoc/*/*">
<xsl:with-param name="pPosition" select="."/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="Person">
<xsl:param name="pPosition" select="1"/>
<Person position="{$pPosition}">
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</Person>
</xsl:template>
<xsl:template match="number">
<xsl:param name="pPosition" select="1"/>
<number><xsl:value-of select="$pPosition"/></number>
</xsl:template>
</xsl:stylesheet>
<强> III。使用DVD样式的递归来避免大N上的堆栈溢出(XSLT 1.0)
<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:param name="pTimes" select="5"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
<xsl:with-param name="pPosition" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:param name="pPosition" select="1"/>
<xsl:if test="$pTimes > 0">
<xsl:choose>
<xsl:when test="$pTimes = 1">
<xsl:apply-templates select="*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vHalf" select="floor($pTimes div 2)"/>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:call-template>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes - $vHalf"/>
<xsl:with-param name="pPosition" select="$pPosition + $vHalf"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="Person">
<xsl:param name="pPosition" select="1"/>
<Person position="{$pPosition}">
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</Person>
</xsl:template>
<xsl:template match="number">
<xsl:param name="pPosition" select="1"/>
<number><xsl:value-of select="$pPosition"/></number>
</xsl:template>
</xsl:stylesheet>
深度递归的问题是调用堆栈耗尽导致堆栈溢出。在不同的系统上,这种情况会发生在不同的嵌套级别,但这通常在N = 1000左右。
上述转变实际上没有这样的问题。 DVC的最大递归深度为log2(N),,这意味着如果我们需要重复动作1000000(1M)次,则最大递归深度仅为19。
<强> IV。最后,如何完全避免递归(XSLT 1.0)
对于已知的,不是太大的N,以下非递归技术效果很好:
<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:param name="pTimes" select="5"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:variable name="vCurrent" select="."/>
<xsl:if test="$pTimes > 0">
<xsl:for-each select=
"document('')//node() | document('')//@* | document('')//namespace::*">
<xsl:if test="not( position() > $pTimes )">
<xsl:apply-templates select="$vCurrent/*">
<xsl:with-param name="pPosition" select="position()"/>
</xsl:apply-templates>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="Person">
<xsl:param name="pPosition" select="1"/>
<Person position="{$pPosition}">
<xsl:apply-templates>
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
</Person>
</xsl:template>
<xsl:template match="number">
<xsl:param name="pPosition" select="1"/>
<number><xsl:value-of select="$pPosition"/></number>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
这个很容易:
<xsl:template match="/">
<xsl:variable name="n">20</xsl:variable>
<xsl:call-template name="loop">
<xsl:with-param name="n" select="$n"/>
<xsl:with-param name="counter" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="loop">
<xsl:param name="n"/>
<xsl:param name="counter"/>
<xsl:if test="$counter <= $n">
<Person position="{$counter}">
<xsl:copy-of select="//name"/>
<number>
<xsl:value-of select="$counter"/>
</number>
</Person>
<xsl:call-template name="loop">
<xsl:with-param name="n" select="$n"/>
<xsl:with-param name="counter" select="$counter+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
将变量n
设置为您需要的多次迭代。