使用 XLST 1.0 扁平化 XML 到唯一嵌套 XML

Flat XML to Unique Nested XML using XLST 1.0

我正在尝试将 filemaker 数据库的输出导出到 Web 应用程序可用的表单中。我试图编写一个 XLST (1.0) 来进行转换。 Filemaker 输出本质上是一个电子表格(行 x 列),我想根据关系转换它。基本上对于每个坦克 "Col[1]" 我希望在与此 "Col[3]".

相关联的特定日期 "Col[2]" 收集数据

使用 XSLT,我已经能够获得唯一日期或唯一坦克,但不是每个坦克的多个日期。

我已经包含了我的 XLST,以及输入 XML 的 "simplified" 版本,以及我希望得到的结果。

非常感谢您的任何建议!

XLST 到目前为止

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fmp="http://www.filemaker.com/fmpxmlresult" version="1.0" exclude-result-prefixes="fmp">
<xsl:output method="xml" version="1.0" encoding="windows-1251" indent="yes"/>

<xsl:key name="fishdate" match="fmp:ROW" use="fmp:COL[3]"/>
<xsl:key name="tanknumber" match="fmp:ROW" use="fmp:COL[9]"/>

<xsl:template match="/">
    <fishroom>
        <xsl:for-each select="fmp:FMPXMLRESULT/fmp:RESULTSET/fmp:ROW[generate-id()=generate-id(key('tanknumber',fmp:COL[9]))]">

                <!-- <xsl:for-each select="fmp:FMPXMLRESULT/fmp:RESULTSET/fmp:ROW[generate-id()=generate-id(key('fishdate',fmp:COL[3]))]"> -->
                        <date> <xsl:value-of select="fmp:COL[3]/fmp:DATA"/>
                            <tank> 
                                <temp><xsl:value-of select="fmp:COL[10]/fmp:DATA"/></temp>
                            </tank>
                        </date>
                 <!-- </xsl:for-each> -->
        </xsl:for-each>

    </fishroom>
</xsl:template>
</xsl:stylesheet>

输入XML:

<row>
    <col>1/1/14</col>
    <col>tank1</col>
    <col>data1</col
</row>
<row>
    <col>1/1/14</col>
    <col>tank2</col>
    <col>data3</col>
</row>
<row>
    <col>1/2/14</col>
    <col>tank1</col>
    <col>data2</col>
</row>

期望输出:

<tank1>
    <date>1/1/14
         <somedata>data2</somedata>
    </date>
    <date>1/2/14
         <somedata>data1</somedata>
   </date>
</tank1>
<tank2>
     <date>1/2/14
         <somedata>data3</somedata>
      </date>
</tank2>

您的尝试有几个问题,最严重的是:

  1. 'fishdate' 键必须使用 tankdate 的串联。 否则,您将在每个 all 记录下进行子分组 tank;
  2. tank分组后,您必须继续对记录进行子分组 在当前组。这些可以通过您用来确定不同坦克的相同密钥访问。
  3. 您遗漏了第三步,您实际上列出了每个中的数据 子组。

给定以下示例输入:

XML

<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
    <!-- omitted -->
    <RESULTSET FOUND="4">
        <ROW MODID="1" RECORDID="1">
            <COL><DATA>tank1</DATA></COL>
            <COL><DATA>1/1/2014</DATA></COL>
            <COL><DATA>data1</DATA></COL>
        </ROW>
        <ROW MODID="1" RECORDID="2">
            <COL><DATA>tank2</DATA></COL>
            <COL><DATA>1/1/2014</DATA></COL>
            <COL><DATA>data3</DATA></COL>
        </ROW>
        <ROW MODID="1" RECORDID="3">
            <COL><DATA>tank1</DATA></COL>
            <COL><DATA>1/2/2014</DATA></COL>
            <COL><DATA>data2</DATA></COL>
        </ROW>
        <ROW MODID="1" RECORDID="4">
            <COL><DATA>tank1</DATA></COL>
            <COL><DATA>1/1/2014</DATA></COL>
            <COL><DATA>data4</DATA></COL>
        </ROW>
    </RESULTSET>
</FMPXMLRESULT>

以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
exclude-result-prefixes="fmp">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="tanknumber" match="fmp:ROW" use="fmp:COL[1]"/>
<xsl:key name="fishdate" match="fmp:ROW" use="concat(fmp:COL[1], '|', fmp:COL[2])"/>

<xsl:template match="/">
    <fishroom>
        <!-- create a group for each distinct tank -->
        <xsl:for-each select="fmp:FMPXMLRESULT/fmp:RESULTSET/fmp:ROW[generate-id()=generate-id(key('tanknumber',fmp:COL[1]))]">
            <xsl:element name="{fmp:COL[1]/fmp:DATA}">
               <!-- create a subgroup for each distinct date within a tank -->
               <xsl:for-each select="key('tanknumber', fmp:COL[1])[generate-id()=generate-id(key('fishdate',concat(fmp:COL[1], '|', fmp:COL[2])))]"> 
                    <date>
                        <xsl:value-of select="fmp:COL[2]/fmp:DATA"/>
                        <!-- enumerate the values in the current subgroup -->
                         <xsl:for-each select="key('fishdate',concat(fmp:COL[1], '|', fmp:COL[2]))">
                             <value>
                                <xsl:value-of select="fmp:COL[3]/fmp:DATA"/>
                            </value>
                        </xsl:for-each>
                    </date>
                </xsl:for-each>
            </xsl:element>
        </xsl:for-each>
    </fishroom>
</xsl:template>

</xsl:stylesheet>

将return这个结果

<?xml version="1.0" encoding="UTF-8"?>
<fishroom>
   <tank1>
      <date>1/1/2014<value>data1</value>
         <value>data4</value>
      </date>
      <date>1/2/2014<value>data2</value>
      </date>
   </tank1>
   <tank2>
      <date>1/1/2014<value>data3</value>
      </date>
   </tank2>
</fishroom>

注:
我不知道您的目标应用程序的要求是什么。上面输出的 XML 格式有两个通常要避免的弱点:

  1. 兄弟元素名称的顺序编号;
  2. 混合内容。