将XML展平为HTML表

时间:2020-03-06 14:19:27  来源:igfitidea点击:

必须有一种通用的方法来转换某些分层XML,例如:

<element1 A="AValue" B="BValue">
   <element2 C="DValue" D="CValue">
      <element3 E="EValue1" F="FValue1"/>
      <element3 E="EValue2" F="FValue2"/>
   </element2>
   ...
</element1>

放入扁平化的XML(html)中,沿途拾取选定的属性,并为成为列标题的属性提供不同的标签。

<table>
   <tr>
     <th>A_Label</th>
     <th>D_Label</th>
     <th>E_Label</th>
     <th>F_Label</th>
   </tr>
   <tr>
     <td>AValue</td>
     <td>DValue</td>
     <td>EValue1</td>
     <td>FValue1</td>
   </tr>
   <tr>
     <td>AValue</td>
     <td>DValue</td>
     <td>EValue2</td>
     <td>FValue2</td>
   </tr>
<table>

好的,由于属性重新标记,因此没有通用的解决方案,但是我们希望得到我的意思。我刚刚开始使用XSLT / XPATH的所有东西,所以我会及时解决,但是任何线索都将有用。

解决方案

我们已经有一个从Oracle数据库读取的Pro * C程序,它调用一个perl脚本,该脚本依次执行一些Java以从上述数据库中提取XML格式的数据,以调用一个批处理文件来执行一些vbscript,然后将该文件通过FTP传输到其他服务器。我真的希望在Fortran中有所收获。

我不确定我们要做什么,但是如果element1,element2和element3始终嵌套嵌套,此解决方案可能会奏效。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="element3">
        <tr>
            <td><xsl:value-of select="../../@A"/></td>
            <td><xsl:value-of select="../../@B"/></td>
            <td><xsl:value-of select="../@C"/></td>
            <td><xsl:value-of select="../@D"/></td>
            <td><xsl:value-of select="@E"/></td>
            <td><xsl:value-of select="@F"/></td>
        </tr>
        <xsl:apply-templates select="*"></xsl:apply-templates>
    </xsl:template>

</xsl:stylesheet>

原始问题需要澄清:

  • 原始问题中的BValue和CValue会发生什么?是否有理由不应该将它们包含在扁平化结构中?
  • XML文档中的所有元素是否都具有2个属性,或者这完全是任意的?
  • 仅存在3种类型的元素,并且它们始终如示例中所示嵌套吗?
  • 是否可以重复element1本身,或者这是文档的根元素?

在XSLT中,可以编写非常通用的转换器,但是在考虑任何已知限制的情况下,编写样式表来转换文档通常会容易得多。

我使用了下面模板的扩展版本来展平结构化XML。警告:原始版本中有一些特定于案例的代码(实际上将XML转换为CSV),我刚刚删除了该代码,但未测试该版本。

它的基本工作方式应该很清楚:它打印所有没有节点子节点的内容,否则以递归的方式在有子节点的node()上调用模板。我认为它现在不能正确处理属性和注释,但这应该不难解决。

<?xml version="1.0" encoding="UTF-8"?>

<!-- XSL template to flatten structured XML, before converting to CSV. -->
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <xsl:strip-space elements="*" /> 

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

    <xsl:template match="//yourElementsToFlatten">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:choose>
            <!-- If the element has multiple childs, call this template 
                on its children to flatten it-->
            <xsl:when test="count(child::*) > 0">
                <xsl:apply-templates select="@*|node()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:value-of select="text()" />
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>