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

时间:2018-03-09 18:08:54

标签: 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>
&#13;
&#13;
&#13;

我需要将具有特定属性DEF的节点包装到另一个节点。例如,属性在变量$ find中计算。所以我有xslt-stylesheet:

&#13;
&#13;
<?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>
&#13;
&#13;
&#13;

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

&#13;
&#13;
<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>
&#13;
&#13;
&#13;

但样式表没有任何影响或节点太多。 我知道很多依赖于我在select属性中指定的参数,但我仍然无法找到解决方案 我怎么能丰富它?

接下来我试着给出一个使用它的例子。 在下面的代码中,我使用了一个在tamplate&#34; getlistOfBodies&#34;

中形成的字符串列表。

&#13;
&#13;
<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">
    <!-- ... ->
&#13;
&#13;
&#13;

所以我希望看到下一个输出取决于$ search: (让$ search =&#34;&#39; body_2&#39;,&#39; body_6&#39;&#34;)

&#13;
&#13;
<?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>
&#13;
&#13;
&#13;

如果$ search =&#34;&#39; body_2&#39;,&#39; body_3&#39;&#34;然后应该用两个不同的翻译包裹两个节点(DEF =&#39; body_2&#39;,DEF =&#39; body_3&#39;)。如果变量中的字符串数为6,那么六个节点应该包含六个变换。 它是这样的......

1 个答案:

答案 0 :(得分:1)

如果你使用正确级别的分组并通过身份转换处理其余的分组(例如在带有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*),任何Transform元素的DEF元素等于序列中的一个值被包装成一个新的{ {1}}元素。

https://xsltfiddle.liberty-development.net/gWcDMeu

上的在线示例