我正在使用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文件,但它基本上使用给定的name
和module
来查找根module
1}}(refModule
)其中name
已定义
答案 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(' #include "agent/gen/',
lower-case(translate(., '-', '_')),
'.h"')"/>
</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(' #include "agent/gen/',
lower-case(translate(., '-', '_')),
'.h"')"/>
</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(' #include "agent/gen/',
lower-case(translate(., '-', '_')),
'.h"')"/>
</xsl:for-each>