xsl - 把孩子变成父母和孩子

时间:2016-07-18 21:31:03

标签: xml xslt

我是.xsl / xslt(1.0)的新手,并且有一个我认为我正试图解决错误方法的泡菜。我需要.xsl在使用的实际值方面尽可能灵活,但能够评估数据以创建我需要的报告。

我需要创建一个.xsl文件来驯服一个.xml输出的野兽。它从属性字符串开始:

<Journal>
   <StartTest timestamp="12:00:00" pass="1" group="A" device="a" test="stretch" />
   <EndTest timestamp="12:00:00" pass="1" group="A" device="a" test="stretch" result="Failed" />
</Journal>

我可以很容易地将这些变成元素,但它是向后组织的,我的第二代最年轻的一代是它的祖先。 现在我需要让这个beastie代表一个数据点(开始和结束时间的测试通过/失败),同时将我的所有数据汇集到一个有组织的链中。(即,多个设备上的许多测试,每个测试分组)通过更广泛的类型,然后进行哪次迭代测试)

<Log>
   <Pass>1
      <Group>A
         <Device>a
            <Test>Stretch
               <StartTest>
                  <timestamp>12:00:00</timestamp>
               </StartTest>
               <EndTest>
                  <timestamp>12:00:00</timestamp>
               </EndTest>
               <Result>Fail</Result>
            </Test>
         </Device>
      </Group>
   </Pass>
</Log>

我即将结束我的智慧,我需要自动化这个输出,因为它是来自100个测试(目前有200个数据点)的数据,需要进行传播和编目。正如我所说,我可能会使事情变得复杂,但我需要输出对于那些想要尽可能少冗余的外行人来说是可以理解的。

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

只是为了挑战,我将采取疯狂的猜测并假设您首先按pass进行分组。然后,对于每个不同的pass,您希望在其中group进行分组。然后,在不同的passgroup内,您希望按device进行分组。

在XSLT 1.0中,分组通常最好通过一种名为Muenchian Grouping.的技术来实现。由于您有三个级别的分组,您需要三个键:

    <xsl:key name="pass" match="StartTest" use="@pass" />
    <xsl:key name="passGroup" match="StartTest" use="concat(@pass, '-', @group)" />
    <xsl:key name="passGroupDevice" match="StartTest" use="concat(@pass, '-', @group, '-', @device)" />

作为示例,您将获得不同的传递值,如下所示:

 <xsl:apply-templates select="StartTest[generate-id() = generate-id(key('pass', @pass)[1])]" mode="pass" />

我将假设Pass,Group和Device的给定组合,您不能有多个具有相同名称的测试。我还假设每个StartTest都会有一个相应的EndTest跟随它。

通过所有这些假设,这给出了以下XSLT

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

    <xsl:key name="pass" match="StartTest" use="@pass" />
    <xsl:key name="passGroup" match="StartTest" use="concat(@pass, '-', @group)" />
    <xsl:key name="passGroupDevice" match="StartTest" use="concat(@pass, '-', @group, '-', @device)" />

    <xsl:template match="Journal">
        <Log>
            <xsl:apply-templates select="StartTest[generate-id() = generate-id(key('pass', @pass)[1])]" mode="pass" />
        </Log>
    </xsl:template>

    <xsl:template match="StartTest" mode="pass">
        <Pass name="{@pass}">
            <xsl:apply-templates select="key('pass', @pass)[generate-id() = generate-id(key('passGroup', concat(@pass, '-', @group))[1])]" mode="passGroup" />
        </Pass>
    </xsl:template>

    <xsl:template match="StartTest" mode="passGroup">
        <Group name="{@group}">
            <xsl:apply-templates select="key('passGroup', concat(@pass, '-', @group))[generate-id() = generate-id(key('passGroupDevice', concat(@pass, '-', @group, '-', @device))[1])]" mode="passGroupDevice" />
        </Group>
    </xsl:template>

    <xsl:template match="StartTest" mode="passGroupDevice">
        <Device name="{@device}">
            <xsl:apply-templates select="key('passGroupDevice', concat(@pass, '-', @group, '-', @device))"/>
        </Device>
    </xsl:template>

     <xsl:template match="StartTest">
        <Test name="{@test}">
            <StartTest>
                <timestamp><xsl:value-of select="@timestamp" /></timestamp>
            </StartTest>
            <xsl:apply-templates select="following-sibling::EndTest[1]" />
        </Test>
     </xsl:template>

     <xsl:template match="EndTest">
        <EndTest>
            <timestamp><xsl:value-of select="@timestamp" /></timestamp>
        </EndTest>
        <Result>
            <xsl:value-of select="@result" />
        </Result>
     </xsl:template>
</xsl:stylesheet>

注意,我已经使用属性来记录各种传递,组和设备名称,而不是文本节点,只是为了避免缩进的麻烦(要获得绝对期望的结果,您必须添加新的行和空格XSLT中的输出,而不是像上面的XSLT一样使用自动缩进。)