首页 > 解决方案 > XSLT 和递归生成表

问题描述

我是 XSLT 的新手,在尝试格式化具有递归节点的 XML 文档时遇到了一些问题。

树节点有两种样式,即组和数据。

问题是当节点混合了组和数据样式时,我当前的 XSLT 模板无法生成内容。

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes"/>
  <xsl:template match="Nodes[TreeNode]">
      <xsl:apply-templates select="TreeNode" />
  </xsl:template>

  <xsl:template match="Nodes[not(TreeNode)]" />

  <xsl:template match="TreeNode[Style='Data']">
      <!--<table>
        <thead>
          <tr>
            <th scope="col">Value</th>
         </tr>
        </thead>
        <tbody>-->
          <tr>
            <td>
              <xsl:value-of select="Value"/>
            </td>
          </tr>
        <!--</tbody>
      </table>-->
  </xsl:template>

   <xsl:template match="TreeNode[Style='Group']">
    <group>
      <p>
        <xsl:value-of select="Label"/>
      </p> 
         <xsl:apply-templates select="Nodes" />
    </group>
   </xsl:template>
</xsl:stylesheet>

XML

<?xml version="1.0" encoding="utf-8"?>
<TreeNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Label>Root</Label>
  <Style>Group</Style>
  <Nodes>
    <TreeNode>
      <Label>A</Label>
      <Style>Group</Style>
      <Nodes>
        <TreeNode>
          <Label>B</Label>
          <Style>Group</Style>
          <Nodes>
            <TreeNode>
              <Label />
              <Value>AAA</Value>
              <Style>Data</Style>
              <Nodes />
            </TreeNode>
            <TreeNode>
              <Label />
              <Value>BBB</Value>
              <Style>Data</Style>
              <Nodes />
            </TreeNode>
          </Nodes>
        </TreeNode>
        <TreeNode>
          <Label>C</Label>
          <Style>Group</Style>
          <Nodes>
            <TreeNode>
              <Label />
              <Value>CCC</Value>
              <Style>Data</Style>
              <Nodes />
            </TreeNode>
            <TreeNode>
              <Label />
              <Value>DDD</Value>
              <Style>Data</Style>
              <Nodes />
            </TreeNode>
          </Nodes>
        </TreeNode>
        <TreeNode>
          <Label>D</Label>
          <Style>Group</Style>
          <Nodes>
            <TreeNode>
              <Label />
              <Value>EEE</Value>
              <Style>Data</Style>
              <Nodes />
            </TreeNode>
          </Nodes>
        </TreeNode>
      </Nodes>
    </TreeNode>
  </Nodes>
</TreeNode>

预期结果:

在此处输入图像描述

标签: c#xmlxslt

解决方案


您的 XSLT 开头有两个模板

<xsl:template match="Nodes[TreeNode]">
  <xsl:apply-templates select="TreeNode" />
</xsl:template>

<xsl:template match="Nodes[not(TreeNode)]" />

这些实际上可以合并为一个;像这样:

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

原因是如果Nodes它下面没有a TreeNode,那么<xsl:apply-templates select="TreeNode" />无论如何都不会选择任何东西,所以效果是一样的。(事实上​​,如果Nodes只能TreeNode在它下面有这个模板,你可以完全放弃它,因为 XSLT 的内置模板会做同样的事情)。

但是,为了回答您的问题,我认为您需要的是另一个模板,您需要另一个模板,在“数据”Nodes有一个子项的情况下匹配TreeNode

<xsl:template match="Nodes[TreeNode/Style='Data']">
  <table>
    <xsl:apply-templates select="TreeNode" />
  </table>
</xsl:template>

试试这个 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes"/>
 <xsl:strip-space elements="*" />

  <xsl:template match="Nodes[TreeNode/Style='Data']">
      <table>
        <xsl:apply-templates select="TreeNode" />
      </table>
  </xsl:template>

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

  <xsl:template match="TreeNode[Style='Data']">
    <tr>
      <td>
        <xsl:value-of select="Value"/>
      </td>
    </tr>
  </xsl:template>

   <xsl:template match="TreeNode[Style='Group']">
    <group>
      <p>
        <xsl:value-of select="Label"/>
      </p> 
      <xsl:apply-templates select="Nodes" />
    </group>
   </xsl:template>
</xsl:stylesheet>

推荐阅读