XSLT:多次复制嵌套元素

时间:2018-10-19 05:35:09

标签: xml xslt

我试图多次复制其中一个嵌套元素。我搜索并遇到XSLT: copy object xml multiple times while incrementing attribute and value。这很接近,但不是我要找的答案。这就是我想做的

XML输入:

<Company xmlns="http://test.com" >
    <Group document="dump" >
        <dump>asdfasd</dump>
        <dump2>asdfasdf</dump2>
        <Person>
            <record>1</record>
            <dump2>asdfasdf</dump2>
            <properties>
                <name>John</name>
                <number>1</number>
            </properties>
        </Person>
    </Group>
</Company>

并输出为以下内容:

<Company xmlns="http://test.com">
   <Group document="dump">
      <dump>asdfasd</dump>
      <dump2>asdfasdf</dump2>
      <Person>
         <record>1</record>
         <dump2>asdfasdf</dump2>
         <properties>
            <name>John</name>
            <number>1</number>
         </properties>
      </Person>
      ...
      <Person>
         <record>n</record>
         <dump2>asdfasdf</dump2>
         <properties>
            <name>John</name>
            <number>n</number>
         </properties>
      </Person>
   </Group>
</Company>

使用我的xslt:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:t="http://test.com"
>
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <xsl:param name="pTimes" select="2"/>

     <xsl:template match="node()|@*">
      <xsl:param name="pPosition" select="1"/>
      <xsl:copy>
       <xsl:apply-templates select="node()|@*">
         <xsl:with-param name="pPosition" select="$pPosition"/>
       </xsl:apply-templates>
      </xsl:copy>
     </xsl:template>

     <xsl:template match="t:Person">
         <xsl:copy>
             <xsl:copy-of select="@*"/>
             <xsl:call-template name="applyNTimes">
                 <xsl:with-param name="pTimes" select="$pTimes"/>
                 <xsl:with-param name="pPosition" select="1"/>
             </xsl:call-template>
          </xsl:copy>
     </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="t:record">
         <xsl:param name="pPosition" select="1"/>

         <xsl:copy>
              <xsl:value-of select="$pPosition"/>
          </xsl:copy>
     </xsl:template>

     <xsl:template match="t:number">
          <xsl:param name="pPosition" select="1"/>
            <xsl:copy>
              <xsl:value-of select="$pPosition"/>
            </xsl:copy>
     </xsl:template>
</xsl:stylesheet>

这就是我所拥有的

<Company xmlns="http://test.com">
   <Group document="dump">
      <dump>asdfasd</dump>
      <dump2>asdfasdf</dump2>
      <Person position="1">
         <record>1</record>
         <dump2>asdfasdf</dump2>
         <properties>
            <name>John</name>
            <number>1</number>
         </properties>
         <record>2</record>
         <dump2>asdfasdf</dump2>
         <properties>
            <name>John</name>
            <number>2</number>
         </properties>
      </Person>
   </Group>
</Company>

如何防止Person元素在复制时消失?

1 个答案:

答案 0 :(得分:0)

在这种情况下,解决方案是将人的xsl:copy从匹配t:Person的模板中移到applyNTimes模板中(在pTimes为1的情况下)。

尝试使用此XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://test.com" version="1.0">
   <xsl:output omit-xml-declaration="yes" indent="yes"></xsl:output>
   <xsl:strip-space elements="*"></xsl:strip-space>
   <xsl:param name="pTimes" select="2"></xsl:param>

   <xsl:template match="node()|@*">
      <xsl:param name="pPosition" select="1"></xsl:param>
      <xsl:copy>
         <xsl:apply-templates select="node()|@*">
            <xsl:with-param name="pPosition" select="$pPosition"></xsl:with-param>
         </xsl:apply-templates>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="t:Person">
      <xsl:call-template name="applyNTimes">
         <xsl:with-param name="pTimes" select="$pTimes"></xsl:with-param>
         <xsl:with-param name="pPosition" select="1"></xsl:with-param>
      </xsl:call-template>
   </xsl:template>

   <xsl:template name="applyNTimes">
      <xsl:param name="pTimes" select="0"></xsl:param>
      <xsl:param name="pPosition" select="1"></xsl:param>
      <xsl:if test="$pTimes &gt; 0">
         <xsl:choose>
            <xsl:when test="$pTimes = 1">
               <xsl:copy>
                  <xsl:apply-templates select="*">
                     <xsl:with-param name="pPosition" select="$pPosition"></xsl:with-param>
                  </xsl:apply-templates>
               </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
               <xsl:variable name="vHalf" select="floor($pTimes div 2)"></xsl:variable>
               <xsl:call-template name="applyNTimes">
                  <xsl:with-param name="pTimes" select="$vHalf"></xsl:with-param>
                  <xsl:with-param name="pPosition" select="$pPosition"></xsl:with-param>
               </xsl:call-template>
               <xsl:call-template name="applyNTimes">
                  <xsl:with-param name="pTimes" select="$pTimes - $vHalf"></xsl:with-param>
                  <xsl:with-param name="pPosition" select="$pPosition + $vHalf"></xsl:with-param>
               </xsl:call-template>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:if>
   </xsl:template>

   <xsl:template match="t:record|t:number">
      <xsl:param name="pPosition" select="1"></xsl:param>
      <xsl:copy>
         <xsl:value-of select="$pPosition"></xsl:value-of>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

请注意,如果您可以使用XSLT 2.0,则由于支持“从1到n”的构造(以及存在“隧道”功能,从而避免了必须在每个模板中显式传递参数),事情变得容易得多。 )。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:t="http://test.com" 
                version="2.0">

   <xsl:output omit-xml-declaration="yes" indent="yes"></xsl:output>
   <xsl:strip-space elements="*"></xsl:strip-space>

   <xsl:param name="pTimes" select="2"></xsl:param>

   <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
   </xsl:template>

   <xsl:template match="t:Person">
      <xsl:variable name="person" select="." />
      <xsl:for-each select="1 to $pTimes">
        <xsl:apply-templates select="$person" mode="repeat">
           <xsl:with-param name="pPosition" select="position()" tunnel="yes" />
        </xsl:apply-templates>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="t:Person" mode="repeat">
     <xsl:copy>
       <xsl:apply-templates />
     </xsl:copy>
   </xsl:template>

   <xsl:template match="t:record|t:number">
      <xsl:param name="pPosition" select="1" tunnel="yes"></xsl:param>
      <xsl:copy>
         <xsl:value-of select="$pPosition"></xsl:value-of>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>