使用 XSLT 将电子表格导出到 XML 时处理重复行

Handling repeating rows when exporting spreadsheet to XML using XSLT

我有一个非常大的电子表格,我正试图将其导出到 XML。在转换过程中,将跳过任何包含重复单元格的行。所以如果一行有 1 2 2 2 3 4 5 只有前 2 个将被复制到 XML 文件。我发现这是因为电子表格存储重复行的方式。我需要我的 XSLT 文件来处理连续的重复单元格而不是跳过它们。

我正在使用 LibreOffice Calc 进行转换。

这是我的示例 .xslt 文件中执行繁重工作的部分:

<xsl:template match="office:spreadsheet/table:table">

   <xsl:for-each select="table:table-row[position() &gt; 0]">

   <xsl:text>&#xa;</xsl:text>
   <xsl:text>&#xa;</xsl:text>

   <Column>

     <xsl:text>&#xa;</xsl:text>

     <p1><xsl:value-of select="table:table-cell[1]/text:p" /></p1> 
     <p1><xsl:value-of select="table:table-cell[2]/text:p" /></p1> 
     <p2><xsl:value-of select="table:table-cell[3]/text:p" /></p2> 
     <p3><xsl:value-of select="table:table-cell[4]/text:p" /></p3> 
     <p4><xsl:value-of select="table:table-cell[5]/text:p" /></p4> 
     <p5><xsl:value-of select="table:table-cell[6]/text:p" /></p5> 
     <p6><xsl:value-of select="table:table-cell[7]/text:p" /></p6> 

      <xsl:text>&#xa;</xsl:text>

      </Column>
   </xsl:for-each>
</xsl:template>

编辑:这是我的示例电子表格在 LibreOffice 中的样子:

1   2   3   4   5
6   7   8   9   10
12  12  13  14  15
15  15  15  15  15
17  17  18  18  17

以及生成的 XML 文件:

<?xml version="1.0"?>
<root>

<Column>
<p1>1</p1><p1>2</p1><p2>3</p2><p3>4</p3><p4>5</p4><p5/><p6/>
</Column>

<Column>
<p1>6</p1><p1>7</p1><p2>8</p2><p3>9</p3><p4>10</p4><p5/><p6/>
</Column>

<Column>
<p1>12</p1><p1>13</p1><p2>14</p2><p3>15</p3><p4/><p5/><p6/>
</Column>

<Column>
<p1>15</p1><p1/><p2/><p3/><p4/><p5/><p6/>
</Column>

 <Column>
 <p1>17</p1><p1>18</p1><p2>17</p2><p3/><p4/><p5/><p6/>
 </Column></root>

在 Open Document *.ods 中,相同的文件单元格不会被冗余存储。相反,第一个单元格将有一个属性 table:number-columns-repeated,它告诉重复的次数:<table:table-cell table:number-columns-repeated="2" ...>.

所以 XSLT 将其转换为 XML 需要所有元素必须重复生成元素。由于我们需要使用 XSLT 1.0,这并不像它应该的那么简单。我们需要一个递归调用自身的模板。

还有您的编号元素名称 p1p2、... 并没有让事情变得更容易。为了实现这一点并根据结果输出元素而不是输入元素进行编号,我们必须首先将输出元素收集在一个变量中,然后对该集合进行编号。

而且您的元素名称令人困惑。您所说的 Column 是行, p 元素是单元格。所以我相应地重命名了它们。

所以有以下 sheet:

并使用以下的导出 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:exsl="http://exslt.org/common" 
 xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
 xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" exclude-result-prefixes="office table text exsl">

 <xsl:template match="/">
  <xsl:element name="sheet">
   <xsl:apply-templates select="/*/office:body" />
  </xsl:element>
 </xsl:template>

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

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

 <xsl:template match="office:spreadsheet/table:table">

  <xsl:for-each select="table:table-row">
   <xsl:element name="row">

   <xsl:variable name="thecells">

    <xsl:for-each select="table:table-cell">

     <xsl:variable name="repeated">
      <xsl:choose>
       <xsl:when test="@table:number-columns-repeated">
        <xsl:value-of select="@table:number-columns-repeated" />
       </xsl:when>
       <xsl:otherwise>
        <xsl:text>1</xsl:text>
       </xsl:otherwise>
      </xsl:choose>
     </xsl:variable>

     <xsl:call-template name="repeatecells">
      <xsl:with-param name="start" select="1" />
      <xsl:with-param name="end" select="$repeated"/>
     </xsl:call-template>

    </xsl:for-each>

   </xsl:variable>

   <xsl:for-each select="exsl:node-set($thecells)/cell">
    <xsl:element name="{concat('cell', position())}"><xsl:value-of select="current()" /></xsl:element>
   </xsl:for-each>

   </xsl:element>
  </xsl:for-each>

 </xsl:template>

 <xsl:template name="repeatecells">
  <xsl:param name="start"/>
  <xsl:param name="end"/>

  <xsl:if test="not($start > $end)">
   <xsl:choose>
    <xsl:when test="$start = $end">
     <xsl:element name="cell"><xsl:value-of select="text:p" /></xsl:element>
    </xsl:when>
    <xsl:otherwise>
     <xsl:variable name="mid" select= "floor(($start + $end) div 2)"/>
     <xsl:call-template name="repeatecells">
      <xsl:with-param name="start" select="$start"/>
      <xsl:with-param name="end" select="$mid"/>
     </xsl:call-template>
     <xsl:call-template name="repeatecells">
      <xsl:with-param name="start" select="$mid+1"/>
      <xsl:with-param name="end" select="$end"/>
     </xsl:call-template>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:if>
 </xsl:template>

</xsl:stylesheet>

结果:

<?xml version="1.0"?>
<sheet>
<row><cell1>P1</cell1><cell2>P2</cell2><cell3>P3</cell3><cell4>P4</cell4><cell5>P5</cell5><cell6>P6</cell6></row>
<row><cell1>1</cell1><cell2>1</cell2><cell3>1</cell3><cell4>1</cell4><cell5>2</cell5><cell6>2</cell6></row>
<row><cell1>1</cell1><cell2>2</cell2><cell3>2</cell3><cell4>2</cell4><cell5>2</cell5><cell6>3</cell6></row>
<row><cell1>1</cell1><cell2>1</cell2><cell3>1</cell3><cell4>2</cell4><cell5>2</cell5><cell6>2</cell6></row>
<row><cell1/><cell2>1</cell2><cell3>1</cell3><cell4/><cell5>2</cell5><cell6>2</cell6></row>
<row><cell1>1</cell1><cell2/><cell3/><cell4>2</cell4><cell5/><cell6/></row></sheet>