简体   繁体   中英

split nodes based on xml comment nodes using xslt 2.0

I have an XML document which needs some XSLT transformation. Here is the XML:

<docs>
  <!-comment->
  <doc>
     <node add="1"/>
     <node add="2"/>
     <!-comment->
     <node add="3"/>
     <node add="4"/>
     <node add="5"/>
     <!-comment->
     <node add="6"/>
     <node add="7"/>
     <node add="8"/>
  </doc>
</docs>

After transformation, the above structure should look like this:

<docs>
  <!-comment->
  <doc>
     <node add="1"/>
     <node add="2"/>
  </doc>
  <!-comment->
  <doc>
     <node add="3"/>
     <node add="4"/>
     <node add="5"/>
  </doc>
  <!-comment->
  <doc>
     <node add="6"/>
     <node add="7"/>
     <node add="8"/>
  </doc>
</docs>

The code that I have so far is:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@* | node()" mode="#all">
        <xsl:copy>
            <xsl:apply-templates select="@* , node()" mode="#current"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="docs">
       <xsl:for-each select="comment">
            <doc>
             <xsl:copy-of select="following-sibling::node[not(following-sibling::comment)]"/>
            <doc>
       <xsl:for-each>
    </xsl:template>

This code does copy the nodes but it copies all the nodes which come after the comment(which is wrong). Structurally, I can tell what I am doing wrong but I can't come up with a correct pattern which would group the nodes and place them accordingly. Also, the number of nodes can change for different XML.

The XSLT element xsl:for-each-group was invented for these scenarios. See https://www.saxonica.com/html/documentation/xsl-elements/for-each-group.html for more information.

My solution:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="node()|@*">
    <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="doc">
    <xsl:for-each-group select="node|comment()" group-starting-with="comment()">
       <xsl:copy-of select="current-group()[self::comment()]"/>
       <doc>
          <xsl:copy-of select="current-group()[self::element()]"/>
       </doc>
    </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM