Xslt 需要查找具有最大表单元格数的表行

Xslt 需要查找具有最大表单元格数的表行,xslt,Xslt,嗨 我正在使用XSLT1.0。我的输入看起来像 <table> <tr> <td/> <td/> <td/> </tr> <tr> <td/> <td/> <td/> </tr> <tr> <td/> <td/> <td/> <td/> </tr> <

嗨 我正在使用XSLT1.0。我的输入看起来像

<table>
<tr>
  <td/>
  <td/>
  <td/>
</tr>
<tr>
  <td/>
  <td/>
  <td/>
</tr>
<tr>
  <td/>
  <td/>
  <td/>
  <td/>
</tr>
</table>


我想知道节点中td的最大数量。在这种情况下,td的最大数量在第3个tr中,因此我的输出应该是4。需要一个模板来完成此操作。提前感谢

您需要使用递归。基本上,下面列出的running max模板针对表的每个tr子元素运行。它首先应用于第一个子tr元素,计算td元素的数量,将其与正在运行的最大值进行比较,然后继续对以下同级(如果有)执行相同的操作

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="/">
    <xsl:variable name="count">
      <xsl:apply-templates select="table"/>
    </xsl:variable>
  </xsl:template>

  <xsl:template match="table">
    <xsl:apply-templates select="tr[1]" mode="running-max"/>
  </xsl:template>

  <xsl:template match="tr" mode="running-max">
    <xsl:param name="max" select="'0'"/>
    <xsl:variable name="size" select="count(td)"/>
    <xsl:variable name="newmax">
      <xsl:choose>
        <xsl:when test="$size &gt; $max">
          <xsl:value-of select="$size"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$max"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="following-sibling::tr">
        <xsl:apply-templates select="following-sibling::tr[position()=1]" mode="running-max">
          <xsl:with-param name="max" select="$newmax"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$newmax"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

下面是一个不使用递归的示例。它只使用xsl:for-each循环遍历TR元素,按每个元素中TD元素的数量排序。第一个是最大值

最大值放在一个名为maxCells的变量中,例如,该变量是表的一个属性

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">
        <xsl:apply-templates select="table"/>
    </xsl:template>

    <xsl:template match="table">
        <!-- Variable holding the maximum number of cells in a row -->
        <xsl:variable name="maxCells">
            <xsl:for-each select="tr">
                <xsl:sort select="count(td)" order="descending"/>
                <xsl:if test="position() = 1">
                    <xsl:value-of select="count(td)"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>

        <!-- Copy the table, adding the maximum cells as an attribute -->
        <xsl:copy>
            <xsl:attribute name="MaxCells">
                <xsl:value-of select="$maxCells"/>
            </xsl:attribute>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

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

将此样式表应用于上面提供的HTML表时,输出如下:

<table MaxCells="4">
    <tr>
        <td/>
        <td/>
        <td/>
    </tr>
    <tr>
        <td/>
        <td/>
        <td/>
    </tr>
    <tr>
        <td/>
        <td/>
        <td/>
        <td/>
    </tr>
</table>

我想知道您是否真的在尝试计数单元格或列。你认为下表的正确结果是什么?

<table>
    <tr><td colspan="2"/><td/></tr>
    <tr><td/><td colspan="2"/></tr>
</table>

如果你只是在计算细胞数,那么你期望有2个——这就是前面两个答案所提供的。然而,该表实际上有三列,因此如果这是您正在寻找的(比如什么时候),那么您需要稍微调整@Tim C的解决方案:在元素和元素中用sum(td/@colspan)+count(td[not(@colspan)]替换count(td)

不幸的是,即使这样,计算也无法在所有情况下提供正确的列计数。例如,当给定以下条件时,它会得到2而不是3:

<table>
    <tr><td rowspan="2"/><td/></tr>
    <tr><td/><td/></tr>
</table>

我不知道如何解决这个问题。我也从未在实时数据中见过它(敲敲木头)

还有一件事。我的因果报应不足以对@Tim C的答案发表评论,但我需要写下这句话以免忘记:样式表是错误的,因为它按词汇对单元格计数进行排序(即,它认为“120”


我只想让表模板中变量的最大td数与自身匹配。如何重写它。在变量中捕获结果。@Wilred Springer:递归是不必要的,正如@Tim-C的答案所示。他的解决方案也是更有效的。@vignesh:我建议使用非递归解决方案。我必须同意th Dimitre的评论。尽管如此,我将在这里留下我的答案供将来参考;在某些情况下,您只需要递归。@vingesh为+1。对于每个解决方案,您唯一不能使用
xsl的两种情况是:(a)您没有XPath表达式范围之外的节点序列(b)值函数步骤。对于(a)您可以使用最大计算组合标记化。对于(b)您可以运行两阶段转换。这!再加上一些表模型,您还有更多行可以添加列。。。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:variable name="table-temp">
        <xsl:apply-templates select="*:table"/>
    </xsl:variable>

    <xsl:template match="/">
        <root>
        <xsl:for-each select="$table-temp/table/descendant::tr">
            <cout>
            <xsl:value-of select="count(child::td)"/>
            </cout>
        </xsl:for-each>
        </root>
    </xsl:template>

    <xsl:template match="*:table">
        <xsl:element name="table">
            <xsl:attribute name="style"/>
            <xsl:apply-templates/>
        </xsl:element>

    </xsl:template>
    <xsl:template match="*:tbody">
        <xsl:element name="tbody">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="*:thead">
        <xsl:element name="thead">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*:tr">
        <xsl:element name="tr">
            <xsl:attribute name="style"/>
            <xsl:variable name="rowspan">
                <xsl:if test="preceding-sibling::*:tr/child::*:td/@rowspan">
                    <xsl:value-of select="sum(preceding-sibling::*:tr/child::*:td/@rowspan)"/>
                </xsl:if>
                <xsl:if test="preceding-sibling::*:tr/child::*:th/@rowspan">
                    <xsl:value-of select="sum(preceding-sibling::*:tr/child::*:th/@rowspan)"/>
                </xsl:if>
            </xsl:variable>
            <xsl:variable name="td-pos" select="preceding-sibling::tr[child::td/@rowspan]/position()"/>
            <xsl:variable name="th-pos" select="preceding-sibling::tr[child::th/@rowspan]/position()"/>

            <xsl:for-each select="1 to $td-pos[last()]">
                <xsl:element name="td"/>
            </xsl:for-each>
            <xsl:for-each select="1 to $th-pos[last()]">
                <xsl:element name="td"/>
            </xsl:for-each>

            <xsl:if test="child::*:td/@colspan|child::*:th/@colspan">
                <xsl:variable name="num">
                    <xsl:if test="child::*:th/@colspan">
                        <xsl:value-of select="sum(child::*:th/@colspan)-1"/>
                    </xsl:if>
                    <xsl:if test="child::*:td/@colspan">
                        <xsl:value-of select="sum(child::*:td/@colspan)-1"/>
                    </xsl:if>
                </xsl:variable>
                <xsl:for-each select="1 to $num">
                    <xsl:element name="td">
                        <xsl:attribute name="style"/>
                    </xsl:element>
                </xsl:for-each>
            </xsl:if>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*:td">
        <xsl:element name="td">
            <xsl:attribute name="style"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*:th">
        <xsl:element name="td">
            <xsl:attribute name="style"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>