用段落制作一张桌子

时间:2014-09-24 13:55:23

标签: xml xslt xslt-2.0

我有以下的XML。

<?xml version="1.0" encoding="UTF-8"?>
<root>
<para align="center">BETWEEN</para>
<para columns="1">Column1 data</para>
<para columns="1">Column1 data</para>
<para columns="1">Column1 data</para>
<para columns="2">Column2 data</para>
<para columns="3">Column3 data</para>
<para align="center">AND</para>
<para columns="1">Column1 data</para>
<para columns="1">Column1 data</para>
<para columns="1">Column1 data</para>
<para columns="2">Column2 data</para>
<para columns="3">Column3 data</para>
<para columns="2">Column2 data</para>
<para columns="2">Column2 data</para>
<para columns="2">Column2 data</para>
<para columns="2">Column2 data</para>
<para columns="2">Column2 data</para>
<para columns="2">Column2 data</para>
<para align="center">Between</para>
<para align="center">____________________</para>
</root>

这里实际上我想将para转换为表格列,因为我已经尝试过XSLT。但问题在于,每个段都会创建一个新表。

此处columns属性指出数据属于哪一列,如果columns="1"表示只有一行和一列。如果它是columns="2",则表明数据属于第二列中含有内容的同一行,如果前面有columns="1",那么同一行的第1列中应该有内容,否则列1应该留空。

我尝试的代码可以找到here

预期输出

    <table>
        <tr>
            <td>Column1 data</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Column1 data</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Column1 data</td>
            <td>Column 2 data</td>
            <td>Column 3 data</td>
        </tr>
    </table>
    <div class="para align-center">AND</div>
   <table>
        <tr>
            <td>Column1 data</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Column1 data</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Column1 data</td>
            <td>Column 2 data</td>
            <td>Column 3 data</td>
        </tr>
    </table>
   <table>
        <tr>
            <td>Column1 data</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Column1 data</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Column1 data</td>
            <td>Column 2 data</td>
            <td>Column 3 data</td>
        </tr>
    </table>

   <table>
        <tr>
            <td></td>
            <td>Column2 data</td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td>Column 2 data</td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td>Column 2 data</td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td>Column2 data</td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td>Column 2 data</td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td>Column 2 data</td>
            <td></td>
        </tr>
    </table>
    <div class="para align-center">BETWEEN</div>

请让我知道如何解决这个问题。

感谢。

1 个答案:

答案 0 :(得分:1)

如果您真正使用XSLT 2.0(链接示例中的处理器是2.0处理器,但您的XSLT @version是1.0),您应该能够使用xsl:for-each-group。您可以将para元素分组到表中,然后将它们分组到这些表中的行中。

可能有更好的方法可以做到这一点,但我只有几分钟时间尝试一下。希望这足以让你开始。

XML输入(稍微修改以进行测试)

<root>
    <para align="center">BETWEEN</para>
    <para columns="1">Column1 data</para>
    <para columns="1">Column1 data</para>
    <para columns="1">Column1 data</para>
    <para columns="2">Column2 data</para>
    <para columns="3">Column3 data</para>
    <para align="center">AND</para>
    <para columns="1">Column1 data</para>
    <para columns="1">Column1 data</para>
    <para columns="1">Column1 data</para>
    <para columns="2">Column2 data</para>
    <para columns="3">Column3 data</para>
    <para columns="2">Column2 data</para>
    <para columns="2">Column2 data</para>
    <para columns="2">Column2 data</para>
    <para columns="2">Column2 data</para>
    <para columns="2">Column2 data</para>
    <para columns="2">Column2 data</para>
    <!--Added for testing-->
    <para columns="1">Column1 data</para>
    <para columns="3">Column3 data</para>
    <!--=================-->
    <para align="center">Between</para>
    <para align="center">____________________</para>
</root>

XSLT 2.0

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs">
    <xsl:output indent="yes" method="html"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="max-cols" select="max(/*/para/@columns)"/>

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

    <xsl:template match="/*">
        <xsl:for-each-group select="para" group-ending-with="para[@columns][@columns > following-sibling::para[@columns][1]/@columns]">
            <xsl:apply-templates select="current-group()[not(@columns)][following-sibling::para[generate-id()=generate-id((current-group()[@columns])[1])]]"/>
            <table>
                <xsl:for-each-group select="current-group()[@columns]" group-starting-with="para[preceding-sibling::para[1]/@columns >= @columns]">
                    <tr>
                        <xsl:call-template name="empty-cols">
                            <xsl:with-param name="col-cnt" select="xs:integer(current-group()[position()=1]/@columns - 1)"/>
                        </xsl:call-template>
                        <xsl:apply-templates select="current-group()"/>
                        <xsl:call-template name="empty-cols">
                            <xsl:with-param name="col-cnt" select="xs:integer($max-cols - current-group()[last()]/@columns)"/>
                        </xsl:call-template>
                    </tr>                        
                </xsl:for-each-group>
            </table>
            <xsl:apply-templates select="current-group()[not(@columns)][preceding-sibling::para[generate-id()=generate-id((current-group()[@columns])[last()])]]"/>                        
        </xsl:for-each-group>
    </xsl:template>

    <xsl:template name="empty-cols">
        <xsl:param name="col-cnt" as="xs:integer"/>
        <xsl:for-each select="1 to $col-cnt">
            <td/>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="para[not(@columns)]">
        <div class="para{if (string(@align)) then concat(' align-',@align) else ''}">
            <xsl:apply-templates/>
        </div>
    </xsl:template>

    <xsl:template match="para[@columns]">
        <xsl:call-template name="empty-cols">
            <xsl:with-param name="col-cnt" select="if (preceding-sibling::para[1][@columns][current()/@columns >= @columns - 1]) then xs:integer((@columns - 1) - preceding-sibling::para[1][@columns]/@columns) else xs:integer(0)"/>
        </xsl:call-template>        
        <td>
            <xsl:apply-templates/>
        </td>
    </xsl:template>

</xsl:stylesheet>

<强>输出

<div class="para align-center">BETWEEN</div>
<table>
   <tr>
      <td>Column1 data</td>
      <td></td>
      <td></td>
   </tr>
   <tr>
      <td>Column1 data</td>
      <td></td>
      <td></td>
   </tr>
   <tr>
      <td>Column1 data</td>
      <td>Column2 data</td>
      <td>Column3 data</td>
   </tr>
</table>
<div class="para align-center">AND</div>
<table>
   <tr>
      <td>Column1 data</td>
      <td></td>
      <td></td>
   </tr>
   <tr>
      <td>Column1 data</td>
      <td></td>
      <td></td>
   </tr>
   <tr>
      <td>Column1 data</td>
      <td>Column2 data</td>
      <td>Column3 data</td>
   </tr>
</table>
<table>
   <tr>
      <td></td>
      <td>Column2 data</td>
      <td></td>
   </tr>
   <tr>
      <td></td>
      <td>Column2 data</td>
      <td></td>
   </tr>
   <tr>
      <td></td>
      <td>Column2 data</td>
      <td></td>
   </tr>
   <tr>
      <td></td>
      <td>Column2 data</td>
      <td></td>
   </tr>
   <tr>
      <td></td>
      <td>Column2 data</td>
      <td></td>
   </tr>
   <tr>
      <td></td>
      <td>Column2 data</td>
      <td></td>
   </tr>
</table>
<table>
   <tr>
      <td>Column1 data</td>
      <td></td>
      <td>Column3 data</td>
   </tr>
</table>
<div class="para align-center">Between</div>
<div class="para align-center">____________________</div>