6

必须有一种通用的方法来转换一些分层的 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 的东西,所以我会及时解决它,但任何线索都会很有用。

4

5 回答 5

5

我不能 100% 确定您要做什么,但如果您的 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>
于 2008-09-18T00:19:31.657 回答
1

我需要一个类似的 XSLT,但深度未知,这就是我的做法。

首先,为生成的 HTML table/def 列表添加一个包装器,并调用模板 mode="puke" 来展平我们的 XML 树:

<xsl:element name="div">
    <xsl:attribute name="class" select="puke" />
    <xsl:apply-templates select="$notice" mode="puke" />
</xsl:element>  

在这里,我们匹配每个节点以显示其内容(例如 text())及其属性。我们递归地执行此操作。我使用 dl/dt/dd 因为我的源代码树是一个复杂的树,它不能被展平为 .

<!-- @description: 
    Display all field from the notice so the customer can tell what he want
-->
<xsl:template match="node()" mode="puke">
<xsl:message>
    puking : <xsl:value-of select="local-name( . )" />
</xsl:message>
    <xsl:element name="dl">
        <xsl:element name="dt">
            <xsl:attribute name="class">tagName</xsl:attribute> 
            <xsl:value-of select="local-name( . )" />
        </xsl:element>
        <xsl:element name="dd">
            <xsl:attribute name="class">tagText</xsl:attribute>
            <xsl:value-of select="text()" /></xsl:element> 
        <xsl:element name="dl">
            <xsl:attribute name="class">attr</xsl:attribute>
            <!-- display attribute -->
            <xsl:apply-templates select="@*" />
        </xsl:element>
    </xsl:element>
    <!-- recursive call on node() -->
    <xsl:apply-templates select="./*" mode="puke" />    
</xsl:template>

匹配给定节点的属性并显示它们。

CSS 用于格式化生成的 HTML:

<style>
.puke {
    background-color: #BDD6DE;
    clear: both;
}
.tagName, .attrName {
    float: left;
}
.tagText, .attrText {
    clear: right;
}
</style>
于 2012-08-02T15:09:58.873 回答
0

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

于 2008-09-18T00:17:37.107 回答
0

原来的问题需要澄清:

  • 原始问题中的 BValue 和 CValue 会发生什么?为什么它们不应该成为扁平结构的一部分?
  • XML 文档中的所有元素是否都有 2 个属性,或者这完全是任意的?
  • 是否只有 3 种类型的元素,它们是否总是嵌套,如示例中所示?
  • 您的 element1 可以自己重复还是这是您的文档的根元素?

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

于 2008-09-18T05:54:24.740 回答
0

我使用了以下模板的扩展版本来展平结构化 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>
于 2008-09-18T09:47:04.460 回答