在 xslt 1.0 中向父元素添加子属性
Adding a child attribute to the parent element in xslt 1.0
我有多个包含 uniqueId(生成并存储在变量中)的元素。
我用 xsl 递归地添加了元素(对象 class=Bundle with unique id )如下
<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 <= $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>
请通过将 xslt 1.0 添加到现有 xsl 来帮助我实现此目的。
问题是您从 1 迭代到 N,而不是迭代节点集。在该迭代中,您使用不依赖于上下文的 return 值调用一个函数(显然,它正在生成一个随机字符串)。因此,您没有任何机会在 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 表达式的输入)
最后一个"solution"(如果上面的none是可能的):
- 根据修改后的身份转换模式,对第一次转换的结果应用第二次转换:
```
<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>
```
不看输入内容很难提供答案。我相信您需要执行以下操作:
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>
我有多个包含 uniqueId(生成并存储在变量中)的元素。 我用 xsl 递归地添加了元素(对象 class=Bundle with unique id )如下
<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 <= $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>
请通过将 xslt 1.0 添加到现有 xsl 来帮助我实现此目的。
问题是您从 1 迭代到 N,而不是迭代节点集。在该迭代中,您使用不依赖于上下文的 return 值调用一个函数(显然,它正在生成一个随机字符串)。因此,您没有任何机会在 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 表达式的输入)
最后一个"solution"(如果上面的none是可能的):
- 根据修改后的身份转换模式,对第一次转换的结果应用第二次转换:
```
<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>
```
不看输入内容很难提供答案。我相信您需要执行以下操作:
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>