在 XSLT 2.0 中包装具有不同属性的节点

  • 本文关键字:属性 节点 XSLT 包装 xslt
  • 更新时间 :
  • 英文 :


我有这样或不同的输入XML文档:

<X3D version="3.2">
<Scene>
<Background skyColor="1 1 1"/>
<Viewpoint position="0 0 4"/>
<Transform DEF="body_0">
<Inline url="body_0.x3d"/>
<Transform DEF="body_1" translation="0,0.2,0">
<Inline url="body_1.x3d"/>
<Transform DEF="body_2" translation="0,0,0">
<Inline url="body_2.x3d"/>
<Transform DEF="body_3" translation="0,0,0">
<Inline url="body_3.x3d"/>
<Transform DEF="body_4" translation="0.5,0,0">
<Inline url="body_4.x3d"/>
<Transform DEF="body_5" translation="0,0,0">
<Inline url="body_5.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
<Transform DEF="body_6" translation="0,0,0">
<Inline url="body_6.x3d"/>
<Transform DEF="body_7" translation="0,0,0">
<Inline url="body_7.x3d"/>
<Transform DEF="body_8" translation="0.5,0,0">
<Inline url="body_8.x3d"/>
<Transform DEF="body_9" translation="0,0,0">
<Inline url="body_9.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Scene>
</X3D>

我需要将具有某些属性 DEF 的节点包装到另一个节点。例如,属性在变量$find中计算。所以我有 xslt 样式表:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:template match="/">
<xsl:variable name="find" select="concat('body_','3')"/>
<xsl:for-each-group select="//Transform" 
group-adjacent="@DEF = $find">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<Transform rotation="1 0 0 1.57">
<xsl:sequence select="current-group()"/>
</Transform>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>

</xsl:template>
</xsl:stylesheet>

我希望看到下一个代码的输出文档:

<X3D version="3.2">
<Scene>
<Background skyColor="1 1 1"/>
<Viewpoint position="0 0 4"/>
<Transform DEF="body_0">
<Inline url="body_0.x3d"/>
<Transform DEF="body_1" translation="0,0.2,0">
<Inline url="body_1.x3d"/>
<Transform DEF="body_2" translation="0,0,0">
<Inline url="body_2.x3d"/>

<Transform  rotation="1 0 0 1.57">
<Transform DEF="body_3" translation="0,0,0">
<Inline url="body_3.x3d"/>
<Transform DEF="body_4" translation="0.5,0,0">
<Inline url="body_4.x3d"/>
<Transform DEF="body_5" translation="0,0,0">
<Inline url="body_5.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform> 

</Transform>
<Transform DEF="body_6" translation="0,0,0">
<Inline url="body_6.x3d"/>
<Transform DEF="body_7" translation="0,0,0">
<Inline url="body_7.x3d"/>
<Transform DEF="body_8" translation="0.5,0,0">
<Inline url="body_8.x3d"/>
<Transform DEF="body_9" translation="0,0,0">
<Inline url="body_9.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Scene>
</X3D>

但是样式表没有任何效果或节点太多。 我知道很大程度上取决于我在 select 属性中指定的参数,但我仍然无法找到解决方案 我怎样才能丰富它?

接下来,我尝试检查一下使用它。 在下面的代码中,我使用在 tamplate "getlistOfBody" 中形成的字符串列表

<xsl:variable name="listOfBodies">
<xsl:call-template name="getlistOfBodies">
</xsl:call-template>
</xsl:variable>

<xsl:template match="*[Transform]">  
<xsl:call-template name="wrap">
<xsl:with-param name="search" select="$listOfBodies" /> 
<!-- examples of $listOfBodies: "'body_2', 'body_5','body_6'" -->
</xsl:call-template>
</xsl:template>
<xsl:template name="wrap" > 
<xsl:param name="search" select="0"/>
<xsl:copy>
<xsl:for-each-group select="* | @*" group-adjacent="@DEF = $search">
<!-- ... ->

所以我想根据$search看到下一个输出: (设 $search = "'body_2'","body_6")

<?xml version="1.0" encoding="UTF-8"?>
<X3D version="3.2">
<Scene>
<Background skyColor="1 1 1"/>
<Viewpoint position="0 0 4"/>
<Transform DEF="body_0">
<Inline url="body_0.x3d"/>
<Transform DEF="body_1" translation="0,0.2,0">
<Inline url="body_1.x3d"/>
			
<Transform rotation="1 0 0 1.57">
<Transform DEF="body_2" translation="0,0,0">
<Inline url="body_2.x3d"/>
<Transform DEF="body_3" translation="0,0,0">
<Inline url="body_3.x3d"/>
<Transform DEF="body_4" translation="0.5,0,0">
<Inline url="body_4.x3d"/>
<Transform DEF="body_5" translation="0,0,0">
<Inline url="body_5.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
			</Transform>
			
			<Transform rotation="1 0 0 1.57">
<Transform DEF="body_6" translation="0,0,0">
<Inline url="body_6.x3d"/>
<Transform DEF="body_7" translation="0,0,0">
<Inline url="body_7.x3d"/>
<Transform DEF="body_8" translation="0.5,0,0">
<Inline url="body_8.x3d"/>
<Transform DEF="body_9" translation="0,0,0">
<Inline url="body_9.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Scene>
</X3D>

如果 $search = "'body_2','body_3'",则应用两个不同的转换包装两个节点(DEF='body_2',DEF='body_3')。如果变量中的字符串数为 6,则应用六个转换包装六个节点。 是这样的...

如果您在正确的级别使用分组并通过标识转换处理其余部分(例如,在带有xsl:mode on-no-match="shallow-copy"的 XSLT 3 中),则得到

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:param name="search" as="xs:string">body_3</xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*[Transform/@DEF = $search]">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent="@DEF = $search">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<Transform rotation="1 0 0 1.57">
<xsl:apply-templates select="current-group()"/>
</Transform>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>              
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

根据您的注释和编辑,听起来好像您根本不想包装相邻的元素,而只是想将某些元素包装到新Transform中,如以下代码所示:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:param name="def-list" as="xs:string*" select="'body_2','body_3'"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Transform[@DEF = $def-list]">
<Transform rotation="1 0 0 1.57">
<xsl:next-match/>
</Transform>
</xsl:template>
</xsl:stylesheet>

所以参数现在是一个字符串序列(xs:string*),任何具有等于序列中一个值的DEF属性的Transform元素都被包装到一个新的Transform元素中。

在线样品在 https://xsltfiddle.liberty-development.net/gWcDMeu

最新更新