【问题标题】:XSLT to flatten XML hierarchy to HTML tableXSLT 将 XML 层次结构展平为 HTML 表
【发布时间】:2009-06-04 10:45:30
【问题描述】:

我有一些像这样的分层 XML:

<node text="a" value="1">
  <node text="gga" value="5">  
    <node text="dh" value="9">
      <node text="tyfg" value="4">  
      </node>  
    </node>  
  </node>  
  <node text="dfhgf" value="7">  
    <node text="fdsg" value="2">  
    </node>  
  </node>  
</node>

元素的名称一直是相同的(“节点”),并且事先不知道层次结构的深度 - 在上面的示例中,最深的叶子是四个向下,但它可以是任何深度。

我需要做的是获取此 XML 并将其展平为 HTML 表格。表中的列数应该等于最深元素的深度,加上每个元素的 value 属性列。 “值”应该出现在表格的最右边一列,因此输出行不能有参差不齐的边缘。每个节点都应该有一行,无论它处于什么级别。上面的例子应该转化为:

<table>
  <tr>
    <td>a</td>
    <td></td>
    <td></td>
    <td></td>
    <td>1</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td></td>
    <td></td>
    <td>5</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td></td>
    <td>9</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td>tyfg</td>
    <td>4</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td></td>
    <td></td>
    <td>7</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td>fdsg</td>
    <td></td>
    <td>2</td>
  </tr>
</table>

有人有一些聪明的 XSLT 可以实现这一点吗?

【问题讨论】:

  • 看起来您正在尝试可视化结构,在每一行上重复父元素链。你真的需要它成为一张桌子吗?结果在我看来不像是实际的表格数据。
  • 是的,目标是可视化结构。一张桌子对我来说似乎是最好的选择,但我对其他建议持开放态度。正如你所说,我真正需要的是每一行的元素链。

标签: html xml xslt


【解决方案1】:

这不是你所需要的(因为它会留下一个锯齿状的表格)但它仍然可以在 html 中工作

<xsl:template match="/">
    <html>
        <head>
        </head>
        <body>
            <table>
                <xsl:apply-templates select="//node" mode="row" />
            </table>
        </body>
    </html>
</xsl:template>

<xsl:template match="node" mode="row">
    <tr>
        <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/>   
        <xsl:apply-templates select="node[1]" mode="emptycell"/>
    </tr>
</xsl:template>

<xsl:template match="node" mode="popcell">
    <td><xsl:value-of select="@text"/></td>
</xsl:template>

<xsl:template match="node" mode="emptycell">
    <td></td>
    <xsl:apply-templates select="node[1]" mode="emptycell"/>
</xsl:template>

版本 2:好吧,我对它的自我满足感要低得多:P,但以下内容消除了锯齿状:

<xsl:variable name="depth">
    <xsl:for-each select="//node">
        <xsl:sort select="count(ancestor::node)" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
            <xsl:value-of select="count(ancestor::node)+1"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

<xsl:template match="/">
    <html>
        <head>
        </head>
        <body>
            <table>
                <xsl:apply-templates select="//node" mode="row" />
            </table>
        </body>
    </html>
</xsl:template>

<xsl:template match="node" mode="row">
    <tr>
        <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/>
        <xsl:call-template name="emptycells">
            <xsl:with-param name="n" select="($depth)-count(ancestor-or-self::node)"/>
        </xsl:call-template>
        <td><xsl:value-of select="@value"/></td>
    </tr>
</xsl:template>

<xsl:template match="node" mode="popcell">
    <td><xsl:value-of select="@text"/></td>
</xsl:template>

<xsl:template name="emptycells">
    <xsl:param name="n" />
    <xsl:if test="$n &gt; 0">
        <td></td>   
        <xsl:call-template name="emptycells">
            <xsl:with-param name="n" select="($n)-1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

【讨论】:

  • 谢谢 :) 有时 XSLT 的优雅确实令人惊叹。
  • 嗨,annakata,谢谢!它接近我需要的东西,不幸的是锯齿状的桌子​​是个问题。在我的问题初稿中,我简化了我的问题。我现在已经修改了它,所以我不能有锯齿状边缘的原因应该很清楚。
  • 呸,你毁了我漂亮的 XSL。
  • Annakata,很抱歉毁了你漂亮的 XSL,但你的第二个版本正是我需要的 - 非常感谢!
【解决方案2】:

这个 XSLT 1.0 解决方案可以做到。

  • 生成格式良好的 HTML 表格
  • 没有使用递归

XSLT 代码:

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

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

  <!-- some preparation -->
  <xsl:variable name="vAllNodes" select="//node" />

  <!-- find out the deepest nested node -->
  <xsl:variable name="vMaxDepth">
    <xsl:for-each select="$vAllNodes">
      <xsl:sort 
        select="count(ancestor::node)" 
        data-type="number" 
        order="descending" 
      />
      <xsl:if test="position() = 1">
        <xsl:value-of select="count(ancestor-or-self::node)" />
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <!-- select a list of nodes, merely to iterate over them -->
  <xsl:variable name="vIteratorList" select="
    $vAllNodes[position() &lt;= $vMaxDepth]
  " />

  <!-- build the table -->
  <xsl:template match="/">
    <table>
      <!-- the rows will be in document order -->
      <xsl:apply-templates select="$vAllNodes" />
    </table>
  </xsl:template>

  <!-- build the rows -->
  <xsl:template match="node">
    <xsl:variable name="self" select="." />
    <tr>
      <!-- iteration instead of recursion -->
      <xsl:for-each select="$vIteratorList">
        <xsl:variable name="vPos" select="position()" />
        <td>
          <!-- the ancestor axis is indexed the other way around -->
          <xsl:value-of select="
            $self/ancestor-or-self::node[last() - $vPos + 1]/@text
          " />
        </td>
      </xsl:for-each>
      <td>
        <xsl:value-of select="@value" />
      </td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

输出:

<table>
  <tr>
    <td>a</td>
    <td></td>
    <td></td>
    <td></td>
    <td>1</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td></td>
    <td></td>
    <td>5</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td></td>
    <td>9</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td>tyfg</td>
    <td>4</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td></td>
    <td></td>
    <td>7</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td>fdsg</td>
    <td></td>
    <td>2</td>
  </tr>
</table>

【讨论】:

  • 感谢 Tomalak,它运行良好。我做了一个微小的改变来获得我想要的输出 - 更改为: 否则行中的文本单元格是倒序的(即叶节点文本在最左列)
  • 实际上,这不应该发生。 $vNodes 由祖先轴组成,这意味着 $vNodes[1] 应该是叶子。您使用的是什么 XSLT 处理器?
  • 嗯。我已经对其进行了更改,使其直接使用“祖先或自我”轴而不是变量。你能再试一次吗?
  • 我尝试了更改,现在我看到输出表中的每一行都包含相同的文本单元格。这些单元格中的文本对应于树中最长路径的文本。希望我已经解释清楚了!
  • 哎呀,我的错。此问题已修复,请重试。
猜你喜欢
  • 2018-08-25
  • 1970-01-01
  • 2018-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多