Необходимо разделить одну таблицу по столбцу и преобразовать в 3 таблицы

#xml #xslt #xslt-2.0

#xml #xslt #xslt-2.0

Вопрос:

Мне нужно разделить столбцы таблицы и создать новую таблицу на преобразованном xml.

Входной XML, который у меня есть:

 <table frame="none">
   <tgroup cols="9">
      <colspec colname="column-0" colnum="1" colsep="1" rowsep="1" />
      <colspec colname="column-1" colnum="2" colsep="1" rowsep="1" />
      <colspec colname="column-2" colnum="3" colsep="1" rowsep="1" />
      <colspec colname="column-3" colnum="4" colsep="1" rowsep="1" />
      <colspec colname="column-4" colnum="5" colsep="1" rowsep="1" />
      <colspec colname="column-5" colnum="6" colsep="1" rowsep="1" />
      <colspec colname="column-6" colnum="7" colsep="1" rowsep="1" />
      <colspec colname="column-7" colnum="8" colsep="1" rowsep="1" />
      <colspec colname="column-8" colnum="9" colsep="1" rowsep="1" />
      <thead>
         <row>
            <entry colname="column-0" colsep="1" rowsep="1" />
            <entry colname="column-1" colsep="1" rowsep="1">
               <p>
                  <b>AAAA</b>
               </p>
            </entry>
            <entry colname="column-2" colsep="1" rowsep="1">
               <p>
                  <b>BBBBBBBB</b>
                  [%]
               </p>
            </entry>
            <entry colname="column-3" colsep="1" rowsep="1">
               <p>
                  <b>CCCC</b>
               </p>
            </entry>
            <entry colname="column-4" colsep="1" rowsep="1">
               <p>
                  <b>DDDDDDD</b>
                  [%]
               </p>
            </entry>
            <entry colname="column-5" colsep="1" rowsep="1">
               <p>
                  <b>EEEE</b>
                  [%]
               </p>
            </entry>
            <entry colname="column-6" colsep="1" rowsep="1">
               <p>
                  <b>FFFF</b>
                  [%]
               </p>
            </entry>
            <entry colname="column-7" colsep="1" rowsep="1">
               <p>
                  <b>GGGG</b>
                  [%]
               </p>
            </entry>
            <entry colname="column-8" colsep="1" rowsep="1">
               <p>
                  <b>
                     HHH
                     <b>1</b>
                  </b>
               </p>
            </entry>
         </row>
      </thead>
      <tbody>
         <row>
            <entry colname="column-0" colsep="1" rowsep="1">
               <p>5°C/ambient RH 1.5 months</p>
            </entry>
            <entry colname="column-1" colsep="1" rowsep="1">
               <p>101.6</p>
            </entry>
            <entry colname="column-2" colsep="1" rowsep="1">
               <p>amp;<0.2</p>
            </entry>
            <entry colname="column-3" colsep="1" rowsep="1">
               <p>0.1</p>
            </entry>
            <entry colname="column-4" colsep="1" rowsep="1">
               <p>0.2</p>
            </entry>
            <entry colname="column-5" colsep="1" rowsep="1">
               <p>0.2</p>
            </entry>
            <entry colname="column-6" colsep="1" rowsep="1">
               <p>0.2</p>
            </entry>
            <entry colname="column-7" colsep="1" rowsep="1">
               <p>0.1</p>
            </entry>
            <entry colname="column-8" colsep="1" rowsep="1">
               <p>0.6</p>
            </entry>
         </row>
      </tbody>
   </tgroup>
</table>
 

Необходимо разделить входной xml на 3 xml (Colspec от 0 до 2, от 3 до 5, от 6 до 8), например, 3 colspec, 3 строки, 3 записи.

Первый XML:

 <table frame="none">
   <tgroup cols="9">
      <colspec colname="column-0" colnum="1" colsep="1" rowsep="1" />
      <colspec colname="column-1" colnum="2" colsep="1" rowsep="1" />
      <colspec colname="column-2" colnum="3" colsep="1" rowsep="1" />
      <thead>
         <row>
            <entry colname="column-0" colsep="1" rowsep="1" />
            <entry colname="column-1" colsep="1" rowsep="1">
               <p>
                  <b>AAAA</b>
               </p>
            </entry>
            <entry colname="column-2" colsep="1" rowsep="1">
               <p>
                  <b>BBBBBBBB</b>
                  [%]
               </p>
            </entry>
          </row>
      </thead>
      <tbody>
         <row>
            <entry colname="column-0" colsep="1" rowsep="1">
               <p>5°C/ambient RH 1.5 months</p>
            </entry>
            <entry colname="column-1" colsep="1" rowsep="1">
               <p>101.6</p>
            </entry>
            <entry colname="column-2" colsep="1" rowsep="1">
               <p>amp;<0.2</p>
            </entry>
          </row>
      </tbody>
   </tgroup>
</table>
 

Например, мне нужны еще два выходных xml для colspec с 3 по 5 и с 6 по 8.

XSL я пробовал:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output omit-xml-declaration="yes" indent="yes" />
   <xsl:strip-space elements="*" />
   <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
   </xsl:template>
   <xsl:template match="/">
      <xsl:apply-templates select="node()|@*" />
      <xsl:result-document href="file:///C://xslttransform//table3.xml">
         <xsl:apply-templates select="node()|@*" />
         <xsl:apply-templates select="/topic/body/table/tgroup/colspec" />
         <xsl:apply-templates select="/topic/body/table/tgroup/thead" />
         <xsl:apply-templates select="/topic/body/table/tgroup/tbody" />
      </xsl:result-document>
      <xsl:result-document href="file:///C://xslttransform//table2.xml">
         <xsl:apply-templates select="node()|@*" />
      </xsl:result-document>
      <xsl:result-document href="file:///C://xslttransform//table1.xml">
         <xsl:apply-templates select="node()|@*" />
      </xsl:result-document>
   </xsl:template>
   <xsl:template match="/topic/body/table/tgroup/colspec">
      <xsl:message>Test11</xsl:message>
      <xsl:if test=".[@colname='column-0']">
         <xsl:message>Test22</xsl:message>
         <xsl:variable name="columnfontoId">
            <xsl:value-of select="./@id" />
         </xsl:variable>
         <colspec colname="column-0" colnum="1" colsep="1" id="{$columnfontoId}" rowsep="1" />
      </xsl:if>
      <xsl:if test=".[@colname='column-1']">
         <xsl:message>Test22</xsl:message>
         <xsl:variable name="columnfontoId">
            <xsl:value-of select="./@id" />
         </xsl:variable>
         <colspec colname="column-1" colnum="2" colsep="1" id="{$columnfontoId}" rowsep="1" />
      </xsl:if>
      <xsl:if test=".[@colname='column-2']">
         <xsl:message>Test22</xsl:message>
         <xsl:variable name="columnfontoId">
            <xsl:value-of select="./@id" />
         </xsl:variable>
         <colspec colname="column-2" colnum="3" colsep="1" id="{$columnfontoId}" rowsep="1" />
      </xsl:if>
   </xsl:template>
   <xsl:template match="/topic/body/table/tgroup/thead">
      <xsl:variable name="columnfontoId">
         <xsl:value-of select="./@id" />
      </xsl:variable>
      <thead id="{$columnfontoId}">
         <xsl:for-each select="row">
            <xsl:variable name="columnfontoId">
               <xsl:value-of select="./@id" />
            </xsl:variable>
            <row id="{$columnfontoId}">
               <xsl:for-each select="entry">
                  <xsl:if test=".[@colname='column-0' or @colname='column-1' or @colname='column-2']">
                     <xsl:message>Test333</xsl:message>
                     <xsl:copy-of select="." />
                  </xsl:if>
               </xsl:for-each>
            </row>
         </xsl:for-each>
      </thead>
   </xsl:template>
   <xsl:template match="/topic/body/table/tgroup/tbody">
      <xsl:variable name="columnfontoId">
         <xsl:value-of select="./@id" />
      </xsl:variable>
      <tbody id="{$columnfontoId}">
         <xsl:for-each select="row">
            <xsl:variable name="columnfontoId">
               <xsl:value-of select="./@id" />
            </xsl:variable>
            <row id="{$columnfontoId}">
               <xsl:for-each select="entry">
                  <xsl:if test=".[@colname='column-0' or @colname='column-1' or @colname='column-2']">
                     <xsl:message>Test333</xsl:message>
                     <xsl:copy-of select="." />
                  </xsl:if>
               </xsl:for-each>
            </row>
         </xsl:for-each>
      </tbody>
   </xsl:template>
</xsl:stylesheet>
 

Ответ №1:

Разделение можно выполнить следующим образом:

 <?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="#all"
    version="3.0">
    
  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>
    
  <xsl:param name="block-size" as="xs:integer" select="3"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="table">
      <xsl:for-each-group select="tgroup/colspec" group-adjacent="(position() - 1) idiv $block-size">
          <xsl:apply-templates select="../.." mode="split"/>
      </xsl:for-each-group>
  </xsl:template>
  
  <xsl:mode name="split" on-no-match="shallow-copy"/>
  
  <xsl:template match="colspec | entry" mode="split">
      <xsl:if test="@colname = current-group()/@colname">
          <xsl:next-match/>
      </xsl:if>
  </xsl:template>
  
</xsl:stylesheet>
 

https://xsltfiddle .liberty-development.net/jxNakAK

Для вывода каждой результирующей таблицы в отдельный файл измените шаблон для table в режиме без имени и добавьте один для table в split режиме:

  <xsl:template match="table">
      <xsl:for-each-group select="tgroup/colspec" group-adjacent="(position() - 1) idiv $block-size">
          <xsl:apply-templates select="../.." mode="split">
            <xsl:with-param name="pos" select="position()"/>
          </xsl:apply-templates>
      </xsl:for-each-group>
  </xsl:template>
  
  <xsl:mode name="split" on-no-match="shallow-copy"/>
  
  <xsl:template match="table" mode="split">
    <xsl:param name="pos"/>
    <xsl:result-document href="table-{$pos}.xml">
      <xsl:next-match/>
    </xsl:result-document>
  </xsl:template>