How to group elements in xsl1.0 and 2.0?

2019-08-15 02:22发布

Such an example

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <a id='a1' name='a1 is a Chinese pig'/>
    <b text='b1'/>
    <d test='test0' location='L0' text='c0'/>
    <a id='a2' name='a2 is a Japanese pig'/>
    <b text='b2'/>
    <c test='test1' location='L1' text='c1 is a red pig'/>
    <c test='test2' location='L2' text='c2 is a green pig'/>
    <a id='a3' name='a3 is a American dog'/>
    <b text='b3'/>
    <c test='test3' location='L3' text='c3 is a lovely dog'/>
    <c test='test4' location='L4' text='c4 is a ugly dog'/>
    <c test='test5' location='L5' text='c5 is a smart dog'/>
    <a id='a4' name='a4 is a Japanese bird'/>
    <b text='b4'/>
    <c test='test6' location='L6' text='c6 is a lovely bird'/>
    <c test='test7' location='L7' text='c7 is a ugly bird'/>
    <c test='test8' location='L8' text='c8 is a smart bird'/>   
    <a id='a5' name='a5 is a American pig'/>
    <b text='b2'/>
    <c test='test10' location='L10' text='c10 is a red pig'/>
    <c test='test11' location='L11' text='c11 is a green pig'/>
    <a id='a6' name='a6 is a Chinese dog'/>
    <b text='b3'/>
    <c test='test12' location='L12' text='c12 is a lovely dog'/>
    <c test='test14' location='L14' text='c14 is a ugly dog'/>
    <c test='test15' location='L15' text='c15 is a smart dog'/>
    <a id='a7' name='a7 is a Chinese bird'/>
    <b text='b4'/>
    <c test='test16' location='L16' text='c16 is a lovely bird'/>
    <c test='test17' location='L17' text='c17 is a ugly bird'/>
    <c test='test18' location='L18' text='c18 is a smart bird'/>        
</root>

I apply a xsl1.0 like this

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text" indent="yes"/>

   <xsl:key name="lookup" match="c" use="generate-id(preceding-sibling::a[1])" />
   <xsl:template match="/root">
      <xsl:apply-templates select="a[key('lookup', generate-id())]" />
   </xsl:template>

   <xsl:template match="a">dog:<xsl:value-of select="concat(@name[contains(.,'dog')], ':&#13;', '&#13;')" />
      <xsl:apply-templates select="key('lookup', generate-id())" />
   </xsl:template>

   <xsl:template match="c">
      <xsl:apply-templates select="@*" />
      <xsl:value-of select="'&#13;'" />
   </xsl:template>

   <xsl:template match="c/@*">
      <xsl:value-of select="concat(local-name(), ':', ., ':&#13;')" />
   </xsl:template>
</xsl:stylesheet>

I want a output like this,the rule is

  1. if there is one or more following c elements between a element and the next a , then we ouput these c elements
  2. then according to the @name, check that value contain some string like pig,dog or bird ,these are key words, not just a hard code work here. we could group these information ,because there are more pigs,birds and dogs.not matter they are chinese or japanese or else,we group according to the dogs,bird ,pig these category we know before.

The output I want is like this

case1:the following are  all pigs:

a2 is a Japanese pig

test:test1
location:L1
text:c1 is a red pig
test:test2
location:L2
text:c2 is a green pig

a5 is a American pig

test:test10
location:L10
text:c10 is a red pig
test:test11
location:L11
text:c11 is a green pig

case2:the following are  all dogs:

a3 is a American dog

test:test3
location:L3
text:c3 is a lovely dog

test:test4
location:L4
text:c4 is a ugly dog

test:test5
location:L5
text:c5 is a smart dog

a6 is a Chinese dog

test:test12
location:L12
text:c12 is a lovely dog

test:test14
location:L14
text:c14 is a ugly dog

test:test15
location:L15
text:c15 is a smart dog    

case3:the following are  all birds:

a4 is a Japanese bird
test:test6
location:L6
text:c6 is a lovely bird

test:test7
location:L7
text:c7 is a ugly bird

test:test8
location:L8
text:c8 is a smart bird

a7 is a Chinese bird

test:test16
location:L16
text:c16 is a lovely bird

test:test17
location:L17
text:c17 is a ugly bird

test:test18
location:L18
text:c18 is a smart bird   

The question is how to correct my xsl1.0? Another is this more easy to realize in xsl2.0?

标签: xslt
1条回答
兄弟一词,经得起流年.
2楼-- · 2019-08-15 02:50

with this xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text" indent="yes"/>
   <xsl:template match="/root">
      <p>the followings are birds:</p>
      <xsl:apply-templates select="a[contains(@name, 'bird')][key('bird_lookup', generate-id())]"/>
      <p>the followings are pigs:</p>
      <xsl:apply-templates select="a[contains(@name, 'pig')][key('pig_lookup', generate-id())]"/> 
      <p>the followings are dogs:</p>
      <xsl:apply-templates select="a[contains(@name, 'dog')][key('dog_lookup', generate-id())]"/>                
   </xsl:template>
   <xsl:key name="bird_lookup" match="c" use="generate-id(preceding-sibling::a[1][contains(@name, 'bird')])"/>
   <xsl:template name="bird" match="a[contains(@name, 'bird')]">
      <xsl:value-of select="'&#13;'"/> 
      <xsl:value-of select="@name"/>
      <xsl:value-of select="'&#13;'"/>      
      <xsl:apply-templates select="key('bird_lookup', generate-id())" />
      <xsl:apply-templates select="c/@*"/>
   </xsl:template>

   <xsl:key name="pig_lookup" match="c" use="generate-id(preceding-sibling::a[1][contains(@name, 'pig')])"/>
   <xsl:template name="pig" match="a[contains(@name, 'pig')]">
         <xsl:value-of select="'&#13;'"/> 
      <xsl:value-of select="@name"/>
      <xsl:value-of select="'&#13;'"/>      
      <xsl:apply-templates select="key('pig_lookup', generate-id())" />
      <xsl:apply-templates select="c/@*"/>
   </xsl:template>

      <xsl:key name="dog_lookup" match="c" use="generate-id(preceding-sibling::a[1][contains(@name, 'dog')])"/>
   <xsl:template name="dog" match="a[contains(@name, 'dog')]">
      <xsl:value-of select="'&#13;'"/>     
      <xsl:value-of select="@name"/>
      <xsl:value-of select="'&#13;'"/>      
      <xsl:apply-templates select="key('dog_lookup', generate-id())" />
      <xsl:apply-templates select="c/@*"/>
   </xsl:template>


   <xsl:template match="c">
      <xsl:apply-templates select="@*"/>
      <xsl:value-of select="'&#13;'"/>
   </xsl:template>

   <xsl:template match="c/@*">
      <xsl:value-of select="concat(local-name(), ':', ., '&#13;')"/>
   </xsl:template>

</xsl:stylesheet>

i can get

the followings are birds:
a4 is a Japanese bird
test:test6
location:L6
text:c6 is a lovely bird

test:test7
location:L7
text:c7 is a ugly bird

test:test8
location:L8
text:c8 is a smart bird


a7 is a Chinese bird
test:test16
location:L16
text:c16 is a lovely bird

test:test17
location:L17
text:c17 is a ugly bird

test:test18
location:L18
text:c18 is a smart bird

the followings are pigs:
a2 is a Japanese pig
test:test1
location:L1
text:c1 is a red pig

test:test2
location:L2
text:c2 is a green pig


a5 is a American pig
test:test10
location:L10
text:c10 is a red pig

test:test11
location:L11
text:c11 is a green pig

the followings are dogs:
a3 is a American dog
test:test3
location:L3
text:c3 is a lovely dog

test:test4
location:L4
text:c4 is a ugly dog

test:test5
location:L5
text:c5 is a smart dog


a6 is a Chinese dog
test:test12
location:L12
text:c12 is a lovely dog

test:test14
location:L14
text:c14 is a ugly dog

test:test15
location:L15
text:c15 is a smart dog

how to make this elegant?

查看更多
登录 后发表回答