在XML中循环遍历子节点的XSL

3
我想循环遍历一个看起来像这样的 XML 文件:
<node>
  <cd name="td1">
    <data value="cd1-0" />
    <cd name="td2">
      <data value="cd1-1" />
    </cd>
    <cd name="td3">
      <data value="cd1-2" />
    </cd>
  </cd>
  <cd name="td4">
    <data value="cd2-0" />
  </cd>
</node>

这是我想要的结果。
<html>  
  <table border="1">  
    <tr>  
      <td>cd1-0</td>  
      <td></td>  
    </tr>  
    <tr>  
      <td></td>  
      <td>cd1-1</td>  
    </tr>  
    <tr>  
      <td></td>  
      <td>cd1-2</td>  
    </tr>  
    <tr>  
      <td>cd2-0</td>  
      <td></td>  
    </tr>  
  </table>  
</html>

在这个例子中,节点cd有两个级别。但是级别可以是无限的。所以我需要一种递归循环函数。

提示:模板匹配="node/cd" - Tommy
3个回答

2

这将适用于任何层级嵌套的cd元素。

您需要进行一些修改才能生成<html>(和<head/><body>...</body>)结构,这可以在match='node'模板中完成。

它会跳过不需要呈现的空尾随<td/>

XSL

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

    <xsl:template match="node">
       <xsl:element name="table">
        <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

    <xsl:template match="cd">   
        <xsl:element name="tr">
            <xsl:for-each select="ancestor::cd">
                <xsl:element name="td"/>
            </xsl:for-each>
            <xsl:element name="td">
                <xsl:value-of select="./data/@value" />
            </xsl:element>
        </xsl:element>
        <xsl:apply-templates />
    </xsl:template>

</xsl:stylesheet>

输出

<table>
  <tr><td>cd1-0</td></tr>        <!-- Here the second <td/> is skipped -->
  <tr><td/><td>cd1-1</td></tr>
  <tr><td/><td>cd1-2</td></tr>
  <tr><td>cd2-0</td></tr>        <!-- Here the second <td/> is skipped -->
</table>

0

您发送的XML看起来不像是格式良好的XML。这个问题留给您自己解决,您可以在XSLT中使用foreach元素。

例如:

<table>
<xsl:for-each select="node/cd">
<tr>
<td>
<xsl:value-of select="data/@value"/>
</td>
</tr>
</xsl:for-each>
</table>

查看此链接以获取更多信息:http://www.w3schools.com/Xsl/xsl_for_each.asp

希望你明白了。

更新:感谢subtenante澄清了XML。 您可以使用模板来解决这个问题。

<xsl:template match="node">
 <html>
  <body>
   <table border="1">
      <xsl:apply-templates select="cd" />
   </table>
  </body>
 </html>
</xsl:template>

<xsl:template match="cd">
 <tr>
  <td>
   <xsl:value-of select="@name" />
  </td>
  <td>
   <xsl:value-of select="data/@value"/>
  </td>
 </tr> 

 <xsl:if test="cd">
  <xsl:apply-templates select="cd" />
 </xsl:if>
</xsl:template>

这将生成以下表格:

<table border="1">
<tbody>
<tr>
 <td>td1</td>
 <td>cd1-0</td>
</tr>
<tr>
 <td>td2</td>
 <td>cd1-1</td>
</tr>
<tr>
 <td>td3</td>
 <td>cd1-2</td>
</tr>
<tr>
 <td>td4</td>
 <td>cd2-0</td>
</tr>
</tbody></table>

提供的 XSLT 需要稍作修改才能完全达到您想要的效果。如果您对此没有意见,那就太好了。
来源:1 Ramjee

在最后你不需要那个 xsl:if 测试。只有当存在一个或多个子 cd 元素时,<xsl:apply-templates select="cd"/> 才会执行任何操作;先检查是否存在一个是多余的。 - Robert Rossney

0
一种方法是:
<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <!-- adapt output method and doctype to your needs -->
  <xsl:output 
    method="html" 
    doctype-system="http://www.w3.org/TR/html4/strict.dtd" 
    doctype-public="-//W3C//DTD HTML 4.01//EN" 
    indent="yes" 
  /> 

  <!-- the document root becomes html -->
  <xsl:template match="/">
    <html>
      <xsl:apply-templates select="*" />
    </html>
  </xsl:template>

  <!-- node becomes table -->
  <xsl:template match="node">
    <table border="1">
      <xsl:apply-templates select="*" />
    </table>
  </xsl:template>

  <!-- 1st level cd elements (children of node) go into first td -->
  <xsl:template match="node/cd">
    <tr>
      <td><xsl:value-of select="data/@value" /></td>
      <td />
    </tr>
  </xsl:template>

  <!-- 2nd level cd elements (children of cd) go into second td -->
  <xsl:template match="cd/cd">
    <tr>
      <td />
      <td><xsl:value-of select="data/@value" /></td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接