создать список для элементов, имеющих голову - PullRequest
0 голосов
/ 08 января 2012

Входной 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> с головой, <l> должен закрыться, и этот элемент становится <p>, и когда снова встречается любой com / head , <l> должен создать.

1 Ответ

0 голосов
/ 08 января 2012

I. Это 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

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, но при реализации группировки используются ключи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...