在表格中处理更多的人

时间:2017-04-04 10:25:24

标签: xml xslt xslt-2.0

我正在进行html到xml的数据转换,我的问题是当一个条目包含比所有受影响的所有后续行更多的行应该自动增加那里的列号。

输入xml

<?xml version="1.0" encoding="UTF-8"?>
<table>
    <tr>
        <td rowspan="2">Name</td>
        <td colspan="2">Marks</td>
    </tr>
    <tr>
        <td>56</td>
        <td>45</td>
    </tr>
    <tr>
        <td>...</td>
        <td>...</td>
        <td>...</td>
    </tr>
</table>

输入xslt

   <xsl:template match="table">
    <table>
        <xsl:apply-templates/>
    </table>
</xsl:template>
<xsl:template match="tr">
    <row>
        <xsl:apply-templates/>
    </row>
</xsl:template>
<xsl:template match="td">
    <xsl:variable name="tdnum" select="count(preceding-sibling::td[not(@colspan)])+sum(preceding-sibling::td/@colspan)+1"/>
    <entry name="col{$tdnum}">
        <xsl:if test="@colspan">
            <xsl:attribute name="namest" select="concat('col', $tdnum)"/>
            <xsl:attribute name="nameend" select="concat('col', ($tdnum + @colspan - 1))"/>
        </xsl:if>
        <xsl:if test="@rowspan">
            <xsl:attribute name="morerows" select="@rowspan"/>
        </xsl:if>
        <xsl:apply-templates/>
    </entry>
</xsl:template>

当前输出

<table>
    <row>
        <entry name="col1" morerows="2">Name</entry>
        <entry name="col2" namest="col2" nameend="col3">Marks</entry>
    </row>
    <row>
        <entry name="col1">56</entry>
        <entry name="col2">45</entry>
    </row>
    <row>
        <entry name="col1">...</entry>
        <entry name="col2">...</entry>
        <entry name="col3">...</entry>
    </row>
</table>

预期输出

<table>
<row>
    <entry name="col1" morerows="2">Name</entry>
    <entry name="col2" namest="col2" nameend="col3">Marks</entry>
</row>
<row>
    <entry name="col2">56</entry>
    <entry name="col3">45</entry>
</row>
<row>
    <entry name="col1">...</entry>
    <entry name="col2">...</entry>
    <entry name="col3">...</entry>
</row>

只想重新排列列的编号,因为我在第一个条目中创建了rowpan但是有很多实例出现在第二个或第三个条目中,而不是colname s / b在每个输入的出现时排列。

先谢谢。

3 个答案:

答案 0 :(得分:1)

我认为您的问题在于定义您的需求,而不是编写XSLT代码来实现这些需求。

如果我理解你正在尝试实现的目标(而且我不确定),我会认为你可以通过添加列号($ tdnum)来实现它的最大数量之间的差异表中所有行的列以及当前行中的列数。

要对其进行编码,您可能会发现计算match =“table”模板中的最大列数很有用,并将其作为隧道参数传递给较低级别​​的模板。我会使用函数进行计算:

max(tr/f:col-count(.))

<xsl:function name="f:col-count" as="xs:integer">
  <xsl:param name="row" as="element(tr)"/>
  <xsl:sequence select="sum($row/td/(if (@colspan) then number(@colspan) else 1))"/>
</xsl:function>

答案 1 :(得分:1)

我相信@Rupesh_Kr有一个小错误。

 <xsl:variable name="next-col-count" select="if (not(following-sibling::*)) then '1' else if (@colspan) then $col-count + number(@colspan) - 1 else $col-count + 1"/>

应该是

 <xsl:variable name="next-col-count" select="if (not(following-sibling::*)) then '1' else if (@colspan) then $col-count + number(@colspan) else $col-count + 1"/>

答案 2 :(得分:0)

只需将变量更改为

即可
<xsl:variable name="tdnum" select="count(preceding-sibling::td[not(@colspan)])+sum(preceding-sibling::td/@colspan)+1"/>

<xsl:variable name="tdnum">
        <xsl:call-template name="current-cell-position"></xsl:call-template>

并为此

定义模板
    <xsl:template name="current-cell-position">
    <xsl:message select="count(preceding::td)"></xsl:message>
    <xsl:choose>
        <xsl:when test="generate-id(parent::tr) = generate-id(ancestor::table[1]/descendant::tr[1])">
            <xsl:value-of select="sum(preceding-sibling::*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1)) + 1"/>                
        </xsl:when>
        <xsl:when test="sum(parent::tr/*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1)) = sum(ancestor::table[1]/descendant::tr[1]/*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))">
            <xsl:value-of select="sum(preceding-sibling::*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1)) + 1"/>
        </xsl:when>
        <xsl:when test="ancestor::table[1]//*[@rowspan][1]">
            <xsl:apply-templates
                select="(parent::tr/preceding-sibling::tr[sum(*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))
                = sum(ancestor::table/descendant::tr[1]/*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))][1]/*[1])[1]"
                mode="find-matrix-column">
                <xsl:with-param name="stop-id">
                    <xsl:value-of select="generate-id(.)"/>
                </xsl:with-param>
                <xsl:with-param name="row-count" select="
                    if (parent::tr/preceding-sibling::tr[sum(*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))
                    = sum(ancestor::table/descendant::tr[1]/*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))][1])
                    then (count(parent::tr/preceding-sibling::tr[sum(*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))
                    = sum(ancestor::table/descendant::tr[1]/*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))][1]/preceding-sibling::tr) + 1)  else 1"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:when test="not(preceding-sibling::*[matches(local-name(.), '^(td|th)$')]|preceding-sibling::th)">1</xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="sum(preceding-sibling::*[matches(local-name(.), '^(td|th)$')]/(if (@colspan) then number(@colspan) else 1))"></xsl:value-of>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="*" mode="find-matrix-column">
    <xsl:param name="stop-id"/>
    <xsl:param name="matrix"/>
    <xsl:param name="row-count"/>
    <xsl:param name="col-count">1</xsl:param>
    <xsl:variable name="current-position" select="concat('[R', $row-count, ':C', $col-count, ']')"/>
    <xsl:choose>
        <xsl:when test="contains($matrix,$current-position)">
            <xsl:apply-templates select="." mode="find-matrix-column">
                <xsl:with-param name="stop-id" select="$stop-id"/>
                <xsl:with-param name="matrix" select="$matrix"/>
                <xsl:with-param name="row-count" select="$row-count"/>
                <xsl:with-param name="col-count" select="$col-count + 1"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:when test="generate-id(.)=$stop-id">
            <xsl:value-of select="$col-count"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:variable name="next-col-count" select="if (not(following-sibling::*)) then '1' else if (@colspan) then $col-count + number(@colspan) - 1 else $col-count + 1"/>
            <xsl:variable name="new-matrix-values">
                <xsl:if test="@rowspan">
                    <xsl:call-template name="add-to-matrix">
                        <xsl:with-param name="start-row" select="number($row-count)"/>
                        <xsl:with-param name="end-row" select="number($row-count) + number(@rowspan) - 1"/>
                        <xsl:with-param name="start-col" select="number($col-count)"/>
                        <xsl:with-param name="end-col" select="if (@colspan) then number($col-count) + number(@colspan) - 1 else number($col-count)"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:variable>
            <xsl:choose>
                <xsl:when test="following-sibling::*">
                    <xsl:apply-templates select="following-sibling::*[1]" mode="find-matrix-column">
                        <xsl:with-param name="stop-id" select="$stop-id"/>
                        <xsl:with-param name="matrix">
                            <xsl:value-of select="$matrix"/>
                            <xsl:value-of select="$new-matrix-values"/>
                        </xsl:with-param>
                        <xsl:with-param name="row-count" select="$row-count"/>
                        <xsl:with-param name="col-count" select="$next-col-count"/>
                    </xsl:apply-templates>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="../following-sibling::tr[1]/*[1]" mode="find-matrix-column">
                        <xsl:with-param name="stop-id" select="$stop-id"/>
                        <xsl:with-param name="matrix">
                            <xsl:value-of select="$matrix"/>
                            <xsl:value-of select="$new-matrix-values"/>
                        </xsl:with-param>
                        <xsl:with-param name="row-count" select="$row-count + 1"/>
                        <xsl:with-param name="col-count" select="1"/>
                    </xsl:apply-templates>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>


<xsl:template name="add-to-matrix">
    <xsl:param name="start-row"/>
    <xsl:param name="end-row"/>
    <xsl:param name="current-row" select="$start-row"/>
    <xsl:param name="start-col"/>
    <xsl:param name="end-col"/>
    <xsl:param name="current-col" select="$start-col"/>
    <xsl:choose>
        <xsl:when test="$current-col > $end-col"/>
        <xsl:when test="$current-row > $end-row">
            <xsl:call-template name="add-to-matrix">
                <xsl:with-param name="start-row" select="$start-row"/>
                <xsl:with-param name="end-row" select="$end-row"/>
                <xsl:with-param name="current-row" select="$start-row"/>
                <xsl:with-param name="start-col" select="$start-col"/>
                <xsl:with-param name="end-col" select="$end-col"/>
                <xsl:with-param name="current-col" select="$current-col + 1"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>[R</xsl:text><xsl:value-of select="$current-row"/>:C<xsl:value-of select="$current-col"/><xsl:text>]</xsl:text>
            <xsl:call-template name="add-to-matrix">
                <xsl:with-param name="start-row" select="$start-row"/>
                <xsl:with-param name="end-row" select="$end-row"/>
                <xsl:with-param name="current-row" select="$current-row + 1"/>
                <xsl:with-param name="start-col" select="$start-col"/>
                <xsl:with-param name="end-col" select="$end-col"/>
                <xsl:with-param name="current-col" select="$current-col"/>
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

如果有任何想法比建议好。