xml - 如何正确指定表的 colname?

标签 xml xslt xpath html-table

我的源 xml 看起来像:

<TABLE>
  <ROW>
    <CELL ROWSPAN="3"> Test </CELL>
    <CELL ROWSPAN="2"> Test </CELL>
    <CELL ROWSPAN="1"> Test </CELL>
    <CELL ROWSPAN="3"> Test </CELL>
    <CELL ROWSPAN="1"> Test </CELL>
  </ROW>
  <ROW>
    <CELL ROWSPAN="1"> Test </CELL>
    <CELL ROWSPAN="1"> Test </CELL>
  </ROW>
</TABLE>

正确的转换输出应如下所示:
<tbody>
  <row>
    <entry colname="1"> Test </entry>
    <entry colname="2"> Test </entry>
    <entry colname="3"> Test </entry>
    <entry colname="4"> Test </entry>
    <entry colname="5"> Test </entry>
 </row>
 <row>
   <entry colname="3"> Test </entry>
   <entry colname="5"> Test </entry>
 </row>
</tbody>

如您所见,棘手的部分是第二行元素。由于第一行有多个单元格占据多行,因此会影响第二行的列名,这就是为什么第二行的第一个条目以列名“3”而不是“1”开头的原因。我不知道这里怎么画表格,但是如果你把它画在纸上,你会很容易理解的。

目前,我有以下 xsl 可以部分捕获这个(我省略了其他信息,因为我只有 @colname 有问题)
<xsl:template match="CELL">
   <xsl:if test="../preceding-sibling::ROW[1]/CELL[1]/@ROWSPAN > 1">
     <xsl:attribute name="colname" select="position()+count(../preceding-sibling::ROW[1]/CELL[@ROWSPAN>1])"/>
    ..
   </xsl:if>
</xsl:template>

这不会很好,因为它会将所有具有多行跨度的 CELL 包括在其计数中,因此结果将如下所示:
  <row>
    <entry colname="4"> Test </entry>
    <entry colname="5"> Test </entry>
  </row> 

虽然第一个条目实际上应该从 3 开始。

我发现描述这个问题有点困难,但我会尽力而为,如果需要更多信息,请在下面发表评论。

最佳答案

这个解决方案非常复杂,我有一种唠叨的感觉,可能有更好的方法,但它似乎有效:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="TABLE">
    <tbody>
      <xsl:apply-templates select="ROW[1]" />
    </tbody>
  </xsl:template>

  <xsl:template match="ROW">
    <xsl:param name="occupiedcols" />
    <row>
      <xsl:apply-templates select="CELL[1]">
        <xsl:with-param name="occupiedcols" select="$occupiedcols" />
      </xsl:apply-templates>
    </row>
    <xsl:apply-templates select="following-sibling::ROW[1]">
      <xsl:with-param name="occupiedcols">
        <xsl:apply-templates select="CELL[1]" mode="getoccupied">
          <xsl:with-param name="occupiedcols" select="$occupiedcols" />
        </xsl:apply-templates>
        <xsl:text></xsl:text>
      </xsl:with-param>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="CELL">
    <xsl:param name="occupiedcols" />
    <xsl:param name="col" select="1" />
    <xsl:variable name="thiscol" select="$col + string-length(substring-before(substring($occupiedcols,$col,255),'0'))" />
    <xsl:element name="entry">
      <xsl:attribute name="colname">
        <xsl:value-of select="$thiscol" />
      </xsl:attribute>
    </xsl:element>
    <xsl:apply-templates select="following-sibling::CELL[1]">
      <xsl:with-param name="occupiedcols" select="$occupiedcols"/>
      <xsl:with-param name="col" select="$thiscol + 1" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="CELL" mode="getoccupied">
    <xsl:param name="occupiedcols" />
    <xsl:param name="col" select="1" />
    <xsl:variable name="thiscol" select="$col + string-length(substring-before(substring($occupiedcols,$col,255),'0'))" />
    <xsl:choose>
      <xsl:when test="contains(substring($occupiedcols,$col,255),'0')">
        <xsl:value-of select="translate(substring-before(substring($occupiedcols,$col,255),'0'),'0123456789','-012345678')" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="translate(substring($occupiedcols,$col,255),'123456789','012345678')" />
      </xsl:otherwise>
    </xsl:choose>
    <xsl:value-of select="@ROWSPAN - 1" />
    <xsl:if test="not(following-sibling::CELL)">
      <xsl:value-of select="translate(substring($occupiedcols,$thiscol + 1, 255),'0123456789','0012345678')" />
    </xsl:if>
    <xsl:apply-templates select="following-sibling::CELL[1]" mode="getoccupied">
      <xsl:with-param name="occupiedcols" select="$occupiedcols"/>
      <xsl:with-param name="col" select="$thiscol + 1" />
    </xsl:apply-templates>
  </xsl:template>
</xsl:stylesheet>

它有一个已知问题:如果一个单元格跨越 9 行以上,它将中断。如果这是一个问题,实际上很容易适应。

此外,它不支持任何使用 COLSPAN

它的工作原理是传递一串数字,详细说明每列仍有一个单元格的行数,因此在您的示例中,第二行将通过“21020”,并根据 0 的位置计算 colname 属性。第二次通过每行将数字减少一个,但用 0 代替每个单元格的 ROWSPAN

此解决方案还假设所有单元格都具有 ROWSPAN 属性,即使它们仅跨越一个。如果不是这种情况,我可以添加一种支持默认 1 的方法。

关于xml - 如何正确指定表的 colname?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8846540/

相关文章:

json - XML 到 JSON Liquid 在逻辑 APP 中因特殊字符而失败

xml - 在 xslt 期间保留字符实体

xml - 使用 "less than"字符的 exec 上的 Phing 语法错误

java - 编写以 xml 格式返回表数据的 servlet 的简单方法

c# - 在 C# 中,如何将 XmlNode 转换为带有缩进的字符串? (没有循环)

python - 瘦身一个xml

xml - 如何在 xsl :when in XSLT(IBM Watson Explorer)? 中使用 "or condition"

java - XPATH 不起作用

python - 使用lxml html从嵌套元素中提取特定元素

javascript - CasperJS 无法使用 CSS 选择器或 xPath 找到元素