需要存储在for-each中创建的局部变量,这些变量不是XML文件的一部分

时间:2015-03-24 22:10:34

标签: xml xslt xslt-2.0

我正在使用XSLT将2个XML文件转换为C代码(XSLT 2.0)。

目标是生成.c文件所需的#include(可能很多)。

有两个不同的地方我需要查找#include名称的变量部分:一个可以直接从一个XML文件中读取,但第二个需要在找到第一个文件后搜索另一个文件(两者都是生成的XML文件,yay代表继承的代码!)。

    <xsl:for-each select="/root/eventDoc/event/parameterList/parameter">
        <xsl:variable name="name" select="@name"/>
        <xsl:variable name="module" select="@module"/>
        <xsl:variable name="refModule" select="eventgen:ref-module-lookup($name, $module)"/>

目前,我只需在包含中打印$module$refModule(通过删除我当前的工作来简化以避免重复):

    <xsl:text>
    #include "agent/gen/</xsl:text><xsl:value-of select="concat(fn:lower-case(translate($module, '-', '_')),'.h')"/><xsl:text>"</xsl:text>

这没关系,但我想摆脱不可避免的重复。 如果我只是编写C代码,我会创建一个数组并添加每个唯一的$module$refModule,然后遍历它并打印出来。

我的第一种方法让我使用preceding::parameter/@module来避免重复,问题是preceding::parameter/@refModule不存在,因为它不属于这个XML文件! preceding::parameter/$refModule也不起作用(对XSLT中的变量范围没有100%明确)。

我想我可以处理这个独特的部分,但是我的问题是如何存储这些非XML值,以便我可以在for-each之后浏览它们并打印出来?模板?也许我毕竟不需要存储?

注意:我可以提供XML输入,但我不认为这对我的问题有帮助(请告诉我)

谢谢!

编辑:虽然已经解决,但为有类似问题的任何不幸的人添加了一些额外的信息。

输入XML:

<event name="PolicyError">
<!-- list of parameters -->
  <parameterList>
      <parameter
        name="Index" module="COMPANY-TEAM-NG-MIB"
      />        
      <parameter
        name="PolicyId" module="COMPANY-TEAM-NG-MIB"
      />
  </parameterList>
</event>

期望的输出:

#include "agent/gen/company_team_ng_mib.h"

为了简单起见,我省略了eventgen:ref-module-lookup函数和第二个XML文件,但它基本上使用给定的namemodule来查找根module 1}}(refModule)其中name已定义

2 个答案:

答案 0 :(得分:2)

您还没有举例说明我可以测试一下,但如果您可以将所有可能的值合并到一个序列中,那么您可以使用distinct-values删除重复项,例如:

<xsl:variable name="moduleNames" select="distinct-values(/root/eventDoc/event
  /parameterList/parameter/(@module, eventgen:ref-module-lookup(@name, @module)))"/>

<xsl:for-each select="$moduleNames">
  <xsl:value-of select="concat('&#10;#include &quot;agent/gen/',
                               lower-case(translate(., '-', '_')),
                               '.h&quot;')"/>
</xsl:for-each>

请注意,distinct-values不提供任何排序​​保证。如果这是一个问题(即您需要#include指令以与XML中的参数相同的顺序出现),那么您可以改为使用for-each-group

<xsl:variable name="moduleNames" select="/root/eventDoc/event
  /parameterList/parameter/(@module, eventgen:ref-module-lookup(@name, @module))"/>

<xsl:for-each-group select="$moduleNames" group-by=".">
  <xsl:value-of select="concat('&#10;#include &quot;agent/gen/',
                               lower-case(translate(., '-', '_')),
                               '.h&quot;')"/>
</xsl:for-each-group>

处理各组的结果保证按照输入序列中第一次提到的组的顺序输出。

答案 1 :(得分:0)

为了完整起见,这是我最终选择的解决方案。 Ian在那里获得了99%的解决方案,我只需要按字母顺序对#includes进行排序。

  <xsl:variable name="moduleNames" select="distinct-values(/root/eventDoc/event/parameterList/parameter/(@module, eventgen:ref-module-lookup(@name, @module)))"/>
  <xsl:for-each select="$moduleNames">
    <xsl:sort select="." />
    <xsl:value-of select="concat('&#10;#include &quot;agent/gen/',
                           lower-case(translate(., '-', '_')),
                           '.h&quot;')"/>
  </xsl:for-each>