如何输出比输入更多的列

时间:2017-01-01 10:13:08

标签: xml excel xslt xslt-1.0 openxml

鉴于此Open XML片段:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:html="http://www.w3.org/TR/REC-html40">

    <Worksheet ss:Name="Sheet5">
      <Table ss:ExpandedColumnCount="7" ss:ExpandedRowCount="4">
        <Column ss:Index="2" ss:AutoFitWidth="0" ss:Width="59.25"/>
        <Column ss:Index="5" ss:AutoFitWidth="0" ss:Width="75"/>
        <Column ss:AutoFitWidth="0" ss:Width="31.5"/>
      </Table>
    </Worksheet>

</Workbook>

...我可以使用什么XSLT 1.0模板解决方案(如果可能的话避免循环)来生成这个HTML输出片段:

<table>
  <colgroup>
    <col style="width:45pt;">
    <col style="width:59.25pt;">
    <col style="width:45pt;">
    <col style="width:45pt;">
    <col style="width:75pt;">
    <col style="width:31.5pt;">
    <col style="width:45pt;">
  </colgroup>
</table>

请注意, ss:ExpandedColumnCount 属性指定了总列数。另请注意,源中的标记不包含 ss:Index 是一种特殊情况,它指定上一个索引之后的下一列索引;在这种情况下,它的计算结果为6.所有其他列的宽度均为45pt。

在我的环境中,别无选择,只能使用MSXML2引擎。

这只是在Open XML中编码的MS Excel工作表上的范围选择的任意示例,有时也称为OOXML。我正在寻找XLST在一般情况下执行此转换。

2 个答案:

答案 0 :(得分:2)

我不确定你究竟是什么意思&#34; 尽可能避免循环&#34;。我当然不知道如何在不使用递归的情况下实现这一目标。事实上,我相信你需要在两个地方使用它:

  • 首先,生成一个覆盖列宽的列表,其中每个节点都有一个索引值;

  • 然后,生成所需数量的col元素。

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
exclude-result-prefixes="ss"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="ss:Table">
    <xsl:variable name="col-widths-rtf">
        <xsl:apply-templates select="ss:Column[1]" mode="col-widths"/>
    </xsl:variable>
    <table>
        <colgroup>
            <xsl:call-template name="colgroup">
                <xsl:with-param name="n" select="@ss:ExpandedColumnCount"/>
                <xsl:with-param name="col-widths" select="exsl:node-set($col-widths-rtf)/width"/>
            </xsl:call-template>
        </colgroup>
    </table>
</xsl:template>

<xsl:template match="ss:Column" mode="col-widths">
    <xsl:param name="last-index" select="0"/>
    <xsl:variable name="index">
        <xsl:choose>
            <xsl:when test="@ss:Index">
                <xsl:value-of select="@ss:Index"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$last-index + 1"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <width index="{$index}">
        <xsl:value-of select="@ss:Width"/>
    </width>
    <!-- sibling recursion -->
    <xsl:apply-templates select="following-sibling::ss:Column[1]" mode="col-widths">
        <xsl:with-param name="last-index" select="$index"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template name="colgroup">
    <xsl:param name="n"/>
    <xsl:param name="col-widths"/>
    <xsl:variable name="override" select="$col-widths[@index=$n]" />
    <xsl:variable name="width">
        <xsl:choose>
            <xsl:when test="$override">
                <xsl:value-of select="$override"/>
            </xsl:when>
            <xsl:otherwise>45</xsl:otherwise>
        </xsl:choose>       
    </xsl:variable>
    <xsl:if test="$n > 1">
        <!-- recursive call -->
        <xsl:call-template name="colgroup">
            <xsl:with-param name="n" select="$n - 1"/>
            <xsl:with-param name="col-widths" select="$col-widths"/>
        </xsl:call-template>
    </xsl:if>
    <col style="width:{$width}pt;"/>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

我认为可以在没有扩展功能的情况下完成,并且在一次通过中,但我可能错了,因为我还没有在所有可能的情况下对以下XSLT进行全面测试,但无论如何都要试一试。 ..

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
    exclude-result-prefixes="ss">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="ss:Table">
    <table>
        <colgroup>
          <xsl:call-template name="Columns" />
        </colgroup>
    </table>
</xsl:template>

<xsl:template name="Columns">
  <xsl:param name="MaxColumns" select="@ss:ExpandedColumnCount" />
  <xsl:param name="Column" select="ss:Column[1]" />
  <xsl:param name="ColumnNumber" select="1" />

  <xsl:if test="$ColumnNumber &lt;= $MaxColumns">
    <xsl:variable name="IsMatch" select="$Column/@ss:Index = $ColumnNumber or $Column[not(@ss:Index)]" />
    <xsl:variable name="width">
      <xsl:choose>
        <xsl:when test="$IsMatch">
          <xsl:value-of select="$Column/@ss:Width" />
        </xsl:when>
        <xsl:otherwise>45</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>  
    <col style="width:{$width}pt;"></col>
    <xsl:call-template name="Columns">
      <xsl:with-param name="MaxColumns" select="$MaxColumns" />
      <xsl:with-param name="Column" select="$Column[not($IsMatch)]|$Column[$IsMatch]/following-sibling::ss:Column[1]" />
      <xsl:with-param name="ColumnNumber" select="$ColumnNumber + 1" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>
</xsl:stylesheet>