将子属性添加到xslt 1.0中的父元素

时间:2015-06-16 07:26:08

标签: xml xslt xpath xslt-1.0

我有多个元素包含uniqueId(生成并存储在变量中)。 我已经递归地添加了元素(object class = Bundle with unique id)和xsl,如下所示

<xsl:template match="visualChildren">
    <object class="Set" >
        <installChildren>
        <xsl:call-template name="Bundle">
            <xsl:with-param name="i" select="1"/>
            <xsl:with-param name="limit" select="4" />
        </xsl:call-template>
        </installChildren>
    </object>
</xsl:template>

<xsl:template name="Bundle">
     <xsl:param name="i"/>
     <xsl:param name="limit"/>

    <xsl:variable name="BundleObjId">
         <xsl:value-of select="php:function('GenerateObjId')"/>
    </xsl:variable>

    <xsl:if test="$i &lt;= $limit">
        <object class="Bundle" objectID="{$BundleObjId}">
             <property></property>
         </object>
    </xsl:if>
    <xsl:call-template name="Bundle">
        <xsl:with-param name="i" select="$i+1"/>
        <xsl:with-param name="limit" select="$limit" />
    </xsl:call-template>
</xsl:template> 

这会产生以下结果

<visualChildren>
    <object class="Set" >
        <installChildren>
            <object class="Bundle" objectID="33110emc908m">
                <property></property>
            </object>
            <object class="Bundle" objectID="43110emc9667m">
                <property></property>
            </object>
        </installChildren>
    </object>
</visualChildren>

现在我需要填充BundleObjId作为父级的兄弟,以便引用它。

必需的输出是:

<visualChildren>
    <object class="Set" >
        <installChildren>
            <object class="Bundle" objectID="33110emc908m">
                <property></property>
            </object>
            <object class="Bundle" objectID="43110emc9667m">
                 <property></property>
            </object>
        </installChildren>
    </object>
    <object RefId=33110emc908m /> 
    <object RefId=43110emc9667m /> 
 </visualChildren>

请通过添加到现有的xsl来帮助我实现xslt 1.0。

2 个答案:

答案 0 :(得分:0)

问题是你从1迭代到N,而不是遍历节点集。在该迭代中,您调用一个函数,其返回值不依赖于上下文(显然,它生成一个随机字符串)。因此,您没有机会在2次不同的迭代中重复相同的ID。在XSLT 1.0中,您无法生成ID的中间列表,然后遍历该列表。我看到3个解决方案:

  • 如果php:function('GenerateObjId')可以被generate-id()替换,则代之以迭代节点,并使用后者(它将为2个相同的节点生成相同的ID)

  • 如果您的处理器支持exsl:node-set()(大多数情况下,文档here),请生成所需的ID列表,作为具有单个父元素的简单XML元素列表,存储它在变量中,然后使用exsl:node-set()迭代(两次)

  • 如果可以,切换到XSLT 2.0(您可以在其中应用以前的解决方案,而不需要exsl:node-set(),因为在XSLT 2.0中,您可以使用XSLT 1.0中的结果树作为输入到XPath表达式)

最后一个“解决方案”(如果以上都不可能):

  • 根据Modified Identity Transform模式将第二个变换应用于第一次变换的结果:

```     &lt; xsl:stylesheet xmlns:xsl =“http://www.w3.org/1999/XSL/Transform”version =“1.0”&gt;

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

   <xsl:template match="object[@class = 'Set']">
      <xsl:copy-of select="."/>
      <xsl:for-each select="installChildren/object">
         <object RefId="{ @objectID }"/>
      </xsl:for-each>
   </xsl:template>

</xsl:stylesheet>

```

答案 1 :(得分:0)

在没有看到输入的情况下提供答案很困难。我相信你需要做以下事情:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="visualChildren">
    <xsl:variable name="bundles">
        <xsl:call-template name="create-bundles">
            <xsl:with-param name="n" select="4" />
        </xsl:call-template>
    </xsl:variable>

    <visualChildren>
        <object class="Set" >
            <installChildren>
                <xsl:for-each select="exsl:node-set($bundles)/object">
                    <object class="Bundle" objectID="{@RefId}">
                        <property/>
                    </object>
                </xsl:for-each>
            </installChildren>
        </object>
        <xsl:copy-of select="$bundles"/>
    </visualChildren>
</xsl:template>

<xsl:template name="create-bundles">
    <xsl:param name="n"/>
    <xsl:if test="$n > 0">
        <object RefId="{php:function('GenerateObjId')}"/>
        <xsl:call-template name="create-bundles">
            <xsl:with-param name="n" select="$n - 1" />
        </xsl:call-template>
    </xsl:if>
</xsl:template> 

</xsl:stylesheet>

给出人为输入:

<?xml version="1.0" encoding="UTF-8"?>
<visualChildren/>

结果将类似于:

<?xml version="1.0" encoding="UTF-8"?>
<visualChildren>
  <object class="Set">
    <installChildren>
      <object class="Bundle" objectID="123456">
        <property/>
      </object>
      <object class="Bundle" objectID="987654">
        <property/>
      </object>
      <object class="Bundle" objectID="456321">
        <property/>
      </object>
      <object class="Bundle" objectID="789456">
        <property/>
      </object>
    </installChildren>
  </object>
  <object RefId="123456"/>
  <object RefId="987654"/>
  <object RefId="456321"/>
  <object RefId="789456"/>
</visualChildren>