为具有头部的元素创建列表

时间:2012-01-07 22:49:29

标签: xslt

输入XML:

  <root>    
     <com>    
        <head>A</head>    
        <body>Type A</body>    
    </com>    
     <com>    
        <head>B</head>    
        <body>Type B</body>    
    </com>    
    <com>    
        <head>C</head>    
        <body>Type C</body>        
    </com>   
     <com>    
        <head>D</head>   
        <body>Type D</body>    
    </com>    
     <com>      
        <body>Type No</body>    
    </com>   
  <plom>xml type X</plom>  
     <plom>xml type Y</plom> 
     <com>    
        <head>a</head>    
        <body>Type a</body>    
    </com>     
     <com>             <head>b</head>    
        <body>Type c</body>    
    </com>    
  </root>      

必需的输出XML:

  <root>                            
     <l>                  
       <li>               
         <lab>A</lab>             
         <text>Type A</text>          
      </li>               
       <li>               
         <lab>B</lab>             
         <text>Type B</text>          
      </li>               
       <li>               
         <lab>C</lab>             
         <text>Type C</text>          
      </li>               
       <li>               
         <lab>D</lab>             
         <text>Type D</text>          
      </li>               
      </l>                
      <p>Type No</p>              
      <p>xml type X</p>           
      <p>xml type Y</p>       
      <l>             
       <li>           
         <lab>a</lab>         
         <text>Type a</text>      
      </li>           
       <li>           
         <lab>b</lab>         
         <text>Type b</text>      
      </li>           
     </l>             
  </root>               

请帮助我从上面显示的输入中获取所需的输出。要求是:如果 com / head 即将到来,则应在 l / li 中输出。但是当找到除<com><com>以外的任何元素({1}}时,该元素应该关闭,该元素变为<l>,再次 com / head ,应该创建<p>

1 个答案:

答案 0 :(得分:0)

<强>予。这个XSLT 2.0转换:

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

 <xsl:template match="/">
  <root>
   <xsl:for-each-group select="/*/*"
        group-adjacent="boolean(self::com/head)">
       <xsl:apply-templates select="current-group()[1]">
        <xsl:with-param name="pGroup" select="current-group()"/>
       </xsl:apply-templates>
   </xsl:for-each-group>
  </root>
 </xsl:template>

 <xsl:template match="com[head]">
  <xsl:param name="pGroup"/>
   <l>
    <xsl:apply-templates select="$pGroup" mode="inGroup"/>
   </l>
 </xsl:template>

 <xsl:template match="com[head]" mode="inGroup">
   <li>
    <lab><xsl:value-of select="head"/></lab>
    <type><xsl:value-of select="body"/></type>
   </li>
 </xsl:template>

 <xsl:template match="*[not(self::com/head)]">
  <xsl:param name="pGroup"/>

  <xsl:apply-templates select="$pGroup" mode="inGroup"/>
 </xsl:template>

 <xsl:template match="*[not(self::com/head)]" mode="inGroup">
  <p><xsl:value-of select="."/></p>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<root>
    <com>
        <head>A</head>
        <body>Type A</body>
    </com>
    <com>
        <head>B</head>
        <body>Type B</body>
    </com>
    <com>
        <head>C</head>
        <body>Type C</body>
    </com>
    <com>
        <head>D</head>
        <body>Type D</body>
    </com>
    <com>
        <body>Type No</body>
    </com>
    <plom>xml type X</plom>
    <plom>xml type Y</plom>
    <com>
        <head>a</head>
        <body>Type a</body>
    </com>
    <com>
        <head>b</head>
        <body>Type b</body>
    </com>
</root>

生成想要的正确结果

<root>
   <l>
      <li>
         <lab>A</lab>
         <type>Type A</type>
      </li>
      <li>
         <lab>B</lab>
         <type>Type B</type>
      </li>
      <li>
         <lab>C</lab>
         <type>Type C</type>
      </li>
      <li>
         <lab>D</lab>
         <type>Type D</type>
      </li>
   </l>
   <p>Type No</p>
   <p>xml type X</p>
   <p>xml type Y</p>
   <l>
      <li>
         <lab>a</lab>
         <type>Type a</type>
      </li>
      <li>
         <lab>b</lab>
         <type>Type b</type>
      </li>
   </l>
</root>

<强>解释

  1. 使用<xsl:for-each-group group-adjacent="...">。选定的相邻元素组对boolean(self::com/head)具有相同的值 - 全部为true()或全部为false()

  2. 仅指定每组中第一个元素的处理,并将该组中所有元素的序列作为参数提供。

  3. 匹配具有子com的元素head的模板(仅当它是组中的第一个元素时才选择执行),包装处理元素的所有结果在l元素中的组中,然后以模式inGroup启动对组中各个元素的处理。

  4. 匹配任何其他模板的模板(不是具有com子元素的head元素(仅当这是组中的第一个元素时才选择执行)只是启动处理在模式inGroup

  5. 中的组中的各个元素

    <强> II。 XSLT 1.0解决方案:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kComHeadGroup" match="com[head]"
      use="generate-id(following-sibling::*[not(self::com[head])][1])"/>
    
     <xsl:key name="kNonComHeadGroup" match="*[not(self::com/head)]"
      use="generate-id(following-sibling::*[(self::com[head])][1])"/>
    
     <xsl:template match="/">
      <root>
       <xsl:apply-templates select="/*/*[1]"/>
      </root>
     </xsl:template>
    
     <xsl:template match=
      "com[head
         and
           not(preceding-sibling::*[1]/self::com[head])
          ]">
    
       <l>
        <xsl:apply-templates mode="inGroup" select=
        "key('kComHeadGroup',
             generate-id
                (following-sibling::*
                   [not(self::com[head])]
                                        [1]
                )
            )"/>
       </l>
    
       <xsl:apply-templates select=
        "following-sibling::*
                   [not(self::com[head])]
                                        [1]
        "/>
      </xsl:template>
    
     <xsl:template match="com[head]" mode="inGroup">
       <li>
        <lab><xsl:value-of select="head"/></lab>
        <type><xsl:value-of select="body"/></type>
       </li>
     </xsl:template>
    
     <xsl:template match="*[not(self::com/head)]">
      <xsl:apply-templates mode="inGroup" select=
      "key('kNonComHeadGroup',
           generate-id(following-sibling::*[(self::com[head])][1])
          )
      "/>
      <xsl:apply-templates select=
       "following-sibling::com[head][1]"/>
     </xsl:template>
    
     <xsl:template match="*[not(self::com/head)]" mode="inGroup">
      <p><xsl:value-of select="."/></p>
     </xsl:template>
    </xsl:stylesheet>
    

    当应用于同一个XML文档(上图)时,再次生成相同的想要的正确结果:

    <root>
       <l>
          <li>
             <lab>A</lab>
             <type>Type A</type>
          </li>
          <li>
             <lab>B</lab>
             <type>Type B</type>
          </li>
          <li>
             <lab>C</lab>
             <type>Type C</type>
          </li>
          <li>
             <lab>D</lab>
             <type>Type D</type>
          </li>
       </l>
       <p>Type No</p>
       <p>xml type X</p>
       <p>xml type Y</p>
       <l>
          <li>
             <lab>a</lab>
             <type>Type a</type>
          </li>
          <li>
             <lab>b</lab>
             <type>Type b</type>
          </li>
       </l>
    </root>
    

    解释:与XSLT 2.0解决方案中的逻辑完全相同,但分组实现使用密钥。