How to match and wrap identical and adjacent node together in XSLT 1.0?

前端 未结 2 1937
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-15 14:36

I have an XML file that look like this and I\'m trying to wrap \"Para_bb\" node that are adjacent to each other with a div.



        
相关标签:
2条回答
  • 2021-01-15 15:10

    One way to do this in XSLT 1.0 is to have a template that matches the first occurrence of each Para_bb element in a group

    <xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
    

    Then you would call a new template, with a mode specified, just on this first element

        <p>
            <xsl:apply-templates select="." mode="div" />
        </p>
    

    Then, in the template matching Para_bb with the mode specified, you would copy the element, and select the next sibling, but only if it is another Para_bb

    <xsl:template match="Para_bb" mode="div">
        <xsl:call-template name="identity" />
        <xsl:apply-templates select="following-sibling::*[1][self::Para_bb]" mode="div"/>
    </xsl:template>
    

    (Where the named template being called is the standard identity template)

    Try this XSLT

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output method="xml" indent="yes"/>
    
        <xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
            <div class="blackBox">
                <xsl:apply-templates select="." mode="div" />
            </div>
        </xsl:template>
    
        <xsl:template match="Para_bb" />
    
        <xsl:template match="Para_a">
            <p>
                <xsl:apply-templates select="@*|node()"/>
            </p>
        </xsl:template>
    
        <xsl:template match="Para_bb" mode="div">
            <xsl:call-template name="identity" />
            <xsl:apply-templates select="following-sibling::*[1][self::Para_bb]" mode="div"/>
        </xsl:template>
    
        <xsl:template match="@*|node()" name="identity">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
  • 2021-01-15 15:11

    You can define a key as follows:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:output indent="yes"/>
    
    <xsl:key name="group" match="Para_bb[preceding-sibling::*[1][self::Para_bb]]" use="generate-id(preceding-sibling::Para_bb[not(preceding-sibling::*[1][self::Para_bb])][1])"/>
    
    <xsl:template match="Root">
      <body>
        <xsl:apply-templates/>
      </body>
    </xsl:template>
    
    <xsl:template match="Para_a">
      <p>
        <xsl:apply-templates/>
      </p>
    </xsl:template>
    
    <xsl:template match="Para_bb[preceding-sibling::*[1][self::Para_bb]]"/>
    
    <xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
      <div class="blackBox">
        <xsl:copy-of select=". | key('group', generate-id())"/>
      </div>
    </xsl:template>
    
    </xsl:stylesheet>
    

    That transforms

    <Root>
       <Para_a></Para_a>
       <Para_a></Para_a>
       <Para_bb>1</Para_bb>
       <Para_bb>2</Para_bb>
       <Para_bb>3</Para_bb>
       <Para_bb>4</Para_bb>
       <Para_a></Para_a>
       <Para_bb>5</Para_bb>
       <Para_bb>6</Para_bb>
       <Para_a></Para_a>
       <Para_a></Para_a>
       <Para_bb>7</Para_bb>
    </Root>
    

    into

    <body>
    
       <p/>
    
       <p/>
    
       <div class="blackBox">
          <Para_bb>1</Para_bb>
          <Para_bb>2</Para_bb>
          <Para_bb>3</Para_bb>
          <Para_bb>4</Para_bb>
       </div>
    
    
    
    
       <p/>
    
       <div class="blackBox">
          <Para_bb>5</Para_bb>
          <Para_bb>6</Para_bb>
       </div>
    
    
       <p/>
    
       <p/>
    
       <div class="blackBox">
          <Para_bb>7</Para_bb>
       </div>
    
    </body>
    
    0 讨论(0)
提交回复
热议问题