XSLT:通过增加属性和值来生成多个对象 [英] XSLT: generate multiple object by incrementing attribute and value

查看:53
本文介绍了XSLT:通过增加属性和值来生成多个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个如下的xml,我想复制n次,同时增加其元素之一和其属性之一.

I have a xml as below that I'd like to copy n times while incrementing one of its element and one of its attribute.

<Person position=1>
<name>John</name>
<number>1</number>
<number>1</number>
</Person>

并且我想要下面类似的东西,其增量数是一个变量.

and I'd like something like below with the number of increment to be a variable.

<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>

任何线索

推荐答案

I. 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左右.

The problem with deep recursion is the exhaustion of the call stack resulting in stack overflow. On different systems this happens with different levels of nesting, but this is typical at around N = 1000.

上面的转换实际上没有这样的问题. DVC的最大递归深度为log2(N),这意味着如果我们需要重复执行动作1000000(1M)次,则最大递归深度仅为19.

The above transformation practically has no such problem. The maximum recursion depth with DVC is log2(N), which means that if we need to repeat the action 1000000 (1M) times, the maximum recursion depth is only 19.

IV.最后,如何完全避免递归(XSLT 1.0)

对于已知的N不太大的情况,以下非递归技术效果很好:

For known, not too big N, the following non-recursive technique works well:

<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>

这篇关于XSLT:通过增加属性和值来生成多个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆