使用XSLT将XML转换为HTML表格

7

我需要能够将扁平的XML数据集转换为HTML表格,但是我很难找到适合我的需求的语法示例。我想使用一种样式表,可以将外观类似的数据集转换为具有可变列的HTML表格。这意味着它不能使用任何硬编码的元素名称,除了"rows"和"row"。

我需要的样式表能够将以下内容转换为HTML表格:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
  <row>
    <AccountId>BlPUAA0</AccountId>
    <AccountName>Initech</AccountName>
    <AcocuntStatus>Client</AcocuntStatus>
  </row>
  <row>
    <AccountId>CJxIAAW</AccountId>
    <AccountName>Intertrode</AccountName>
    <AcocuntStatus>Prospect</AcocuntStatus>
  </row>
</rows>

into:

<table>
  <tr>
    <th>AccountId</th>
    <th>AccountName</th>
    <th>AcocuntStatus</th>
  </tr>
  <tr>
    <td>BlPUAA0</td>
    <td>Initech</td>
    <td>Client</td>
  </tr>
  <tr>
    <td>CJxIAAW</td>
    <td>Intertrode</td>
    <td>Client</td>
  </tr>
</table>

并且这个:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
  <row>
    <AccountId>BlPUAA0</AccountId>
    <AccountName>Initech</AccountName>
  </row>
  <row>
    <AccountId>CJxIAAW</AccountId>
    <AccountName>Intertrode</AccountName>
  </row>
</rows>

将其转换为:

<table>
  <tr>
    <th>AccountId</th>
    <th>AccountName</th>
  </tr>
  <tr>
    <td>BlPUAA0</td>
    <td>Initech</td>
  </tr>
  <tr>
    <td>CJxIAAW</td>
    <td>Intertrode</td>
  </tr>
</table>
4个回答

8

一种简单明了的解决方案:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match="row[1]">
  <tr><xsl:apply-templates select="*" mode="header"/></tr>
  <xsl:call-template name="standardRow"/>
 </xsl:template>

 <xsl:template match="row" name="standardRow">
  <tr><xsl:apply-templates select="*"/></tr>
 </xsl:template>

 <xsl:template match="row/*">
  <td><xsl:apply-templates select="node()"/></td>
 </xsl:template>

 <xsl:template match="row/*" mode="header">
  <th><xsl:value-of select="name()"/></th>
 </xsl:template>
</xsl:stylesheet>

当应用于第一个提供的XML文档时:

<rows>
    <row>
        <AccountId>BlPUAA0</AccountId>
        <AccountName>Initech</AccountName>
        <AcocuntStatus>Client</AcocuntStatus>
    </row>
    <row>
        <AccountId>CJxIAAW</AccountId>
        <AccountName>Intertrode</AccountName>
        <AcocuntStatus>Prospect</AcocuntStatus>
    </row>
</rows>

正确的结果已经生成:

<table>
   <tr>
      <th>AccountId</th>
      <th>AccountName</th>
      <th>AcocuntStatus</th>
   </tr>
   <tr>
      <td>BlPUAA0</td>
      <td>Initech</td>
      <td>Client</td>
   </tr>
   <tr>
      <td>CJxIAAW</td>
      <td>Intertrode</td>
      <td>Prospect</td>
   </tr>
</table>

当应用于第二个提供的 XML 文档时:

<rows>
    <row>
        <AccountId>BlPUAA0</AccountId>
        <AccountName>Initech</AccountName>
    </row>
    <row>
        <AccountId>CJxIAAW</AccountId>
        <AccountName>Intertrode</AccountName>
    </row>
</rows>

再次生成所需的正确结果:

<table>
   <tr>
      <th>AccountId</th>
      <th>AccountName</th>
   </tr>
   <tr>
      <td>BlPUAA0</td>
      <td>Initech</td>
   </tr>
   <tr>
      <td>CJxIAAW</td>
      <td>Intertrode</td>
   </tr>
</table>

+1 对于规范化表的好回答。如果没有那些不必要的 select,拉取式的方法会更清晰。 - user357812

5

在发布问题后不久,我有解决它的冲动,下面是我的方法。我猜在你自己回答问题前需要等待24小时。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:template match="/">
    <table>
      <tr>
        <xsl:for-each select="rows/row[1]/*">
          <th>
            <xsl:value-of select ="local-name()"/>
          </th>
        </xsl:for-each>
      </tr>
      <xsl:for-each select="rows/row">
        <tr>
          <xsl:for-each select="*">
            <td>
              <xsl:value-of select="."/>
            </td>
          </xsl:for-each>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

一定要学习借鉴他人的答案。这种“模板代码”并没有太大用处。 - user357812

2

这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <table>
            <xsl:apply-templates select="rows/row[1]" />
        </table>
    </xsl:template>
    <xsl:template match="row">
        <tr>
            <xsl:apply-templates mode="th" />
        </tr>
        <xsl:apply-templates select="../row" mode="td" />
    </xsl:template>
    <xsl:template match="row/*" mode="th">
        <th>
            <xsl:value-of select="local-name()" />
        </th>
    </xsl:template>
    <xsl:template match="row" mode="td">
        <tr>
            <xsl:apply-templates />
        </tr>
    </xsl:template>
    <xsl:template match="row/*">
        <td>
            <xsl:apply-templates />
        </td>
    </xsl:template>
</xsl:stylesheet>

适用于:

<rows>
    <row>
        <AccountId>BlPUAA0</AccountId>
        <AccountName>Initech</AccountName>
        <AcocuntStatus>Client</AcocuntStatus>
    </row>
    <row>
        <AccountId>CJxIAAW</AccountId>
        <AccountName>Intertrode</AccountName>
        <AcocuntStatus>Prospect</AcocuntStatus>
    </row>
</rows>

生成:

<table>
    <tr>
        <th>AccountId</th>
        <th>AccountName</th>
        <th>AcocuntStatus</th>
    </tr>
    <tr>
        <td>BlPUAA0</td>
        <td>Initech</td>
        <td>Client</td>
    </tr>
    <tr>
        <td>CJxIAAW</td>
        <td>Intertrode</td>
        <td>Prospect</td>
    </tr>
</table>

适用于:

<rows>
  <row>
    <AccountId>BlPUAA0</AccountId>
    <AccountName>Initech</AccountName>
  </row>
  <row>
    <AccountId>CJxIAAW</AccountId>
    <AccountName>Intertrode</AccountName>
  </row>
</rows>

生成:

<table>
    <tr>
        <th>AccountId</th>
        <th>AccountName</th>
    </tr>
    <tr>
        <td>BlPUAA0</td>
        <td>Initech</td>
    </tr>
    <tr>
        <td>CJxIAAW</td>
        <td>Intertrode</td>
    </tr>
</table>

或者,使用条件和一个更少的模板,这个样式表可以产生相同的输出:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <table>
            <xsl:apply-templates select="rows/row" />
        </table>
    </xsl:template>
    <xsl:template match="row">
        <xsl:if test="position()=1">
            <tr>
                <xsl:apply-templates mode="th" />
            </tr>
        </xsl:if>
        <tr>
            <xsl:apply-templates />
        </tr>
    </xsl:template>
    <xsl:template match="row/*" mode="th">
        <th>
            <xsl:value-of select="local-name()" />
        </th>
    </xsl:template>
    <xsl:template match="row/*">
        <td>
            <xsl:apply-templates />
        </td>
    </xsl:template>
</xsl:stylesheet>

1

几天前我发布了一篇文章,希望能够帮助您:http://web.swfideas.com/?p=12191

假设有以下数据:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Edited by XMLSpy -->
<table-node>
  <tbody>
    <tr>
      <td>[C1R1]</td>
      <td>[C2R1]</td>
    </tr>
    <tr>
      <td>[C1R2]</td>
      <td>[C2R2]</td>
    </tr>
    <tr>
      <td>[C1R3]</td>
      <td>[C2R3]</td>
    </tr>
  </tbody>
</table-node>

现在,核心部分是我们的XSLT模板:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Coded by SWFideas -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- table template -->
<xsl:template match="table-node">
    <table style="border:solid #000000 1px;border-spacing: 0;border-collapse: collapse;">
        <xsl:for-each select="tbody">
            <tbody>
                <xsl:for-each select="tr">
                    <tr>
                        <xsl:for-each select="td">
                            <td style="border:solid #000000 1px; padding: 5px;">
                                <xsl:value-of select="."/>
                            </td>
                        </xsl:for-each>                     
                    </tr>                 
                </xsl:for-each>
            </tbody>
        </xsl:for-each>
    <table>
</xsl:template>
</xsl:stylesheet>

在这个第一种方法中,我避免使用COLSPAN和其他真实属性(很快就会实现,我保证)。因此,如果我们应用XSLT,结果将是这样的:
<table style="border:solid #000000 1px;border-spacing: 0;border-collapse: collapse;">
    <tbody>
        <tr>
            <td style="border:solid #000000 1px; padding: 5px;">[C1R1]</td>
            <td style="border:solid #000000 1px; padding: 5px;">[C2R1]</td>
        </tr>
        <tr>
            <td style="border:solid #000000 1px; padding: 5px;">[C1R2]</td>
            <td style="border:solid #000000 1px; padding: 5px;">[C2R2]</td>
        </tr>
        <tr>
            <td style="border:solid #000000 1px; padding: 5px;">[C1R3]</td>
            <td style="border:solid #000000 1px; padding: 5px;">[C2R3]</td>
        </tr>
    </tbody>
</table>

你可以在这里尝试:http://www.xsltcake.com/slices/gNfh6i/2

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