gpt4 book ai didi

xslt 跳过已经 "visited"节点

转载 作者:行者123 更新时间:2023-12-02 11:42:16 26 4
gpt4 key购买 nike

不确定这是否可能,而不必经过几次传递,但我无论如何都会问(我的 XSL 有点生锈)

我有一个 XML 文档,其中包含如下节点:

<structures>
<structure id="STRUCT_A">
<field idref="STRUCT_B" name="b"/>
<field idref="STRUCT_C" name="c"/>
<field idref="FIELD_D" name="d"/>
</structure>

<structure id="STRUCT_B">
<field idref="STRUCT_C" name="c"/>
<field idref="FIELD_E" name="e"/>
</structure>

<structure id="STRUCT_C">
<field idref="FIELD_E" name="e"/>
<field idref="FIELD_F" name="f"/>
<field idref="FIELD_G" name="g"/>
</structure>
</structures>

(真实文件包含大量相互依赖的结构标签,没有一个是循环的!)

我想要做的是生成一些文本(在本例中为 C++ struct s),明显的要求是 struct 的顺序。 s,所以我的理想输出是

struct STRUCT_C
{
FIELD_E e;
FIELD_F f;
FIELD_G g;
};

struct STRUCT_B
{
STRUCT_C c;
FIELD_E e;
};

struct STRUCT_A
{
STRUCT_B b;
STRUCT_C c;
FIELD_D d;
};

我知道我可以使用前向声明,这意味着顺序并不重要,但问题是结构中会有内联的“处理”代码,并且它们需要存在真正的定义。

到目前为止,我可以检测是否有 structure有任何依赖关系,具有以下 xsl 位:

<xsl:for-each select="descendant::*/@idref">
<xsl:variable name="name" select="."/>
<xsl:apply-templates select="//structure[@id = $name]" mode="struct.dep"/>
</xsl:for-each>

(这发生在 <xsl:template match="structure"> 内)

现在,理论上,我可以遵循这个依赖“链”并生成 struct首先为每个条目,然后是我当前所在的条目,但是正如你可以想象的,这会生成大量相同结构的副本 - 这是一个痛苦..

有什么办法可以避免复制吗?基本上,一旦访问了一个结构,如果我们再次访问,就不必费心输出它的代码...我不需要完整的 xslt 来执行此操作(除非它很微不足道!),但只是关于方法的任何想法...

如果没有,理论上我可以包装 struct#ifdef/#define/#endif保护,以便编译器只使用第一个定义,但这真的很讨厌! :(

(注:Linux 上的 xslt 1.0、xsltproc:使用 libxml 20623、libxslt 10115 和 libexslt 812)

最佳答案

这种转变:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:variable name="vLeafs" select="/*/structure[not(field/@idref = /*/structure/@id)]"/>

<xsl:template match="/*">
<xsl:apply-templates select="$vLeafs[1]">
<xsl:with-param name="pVisited" select="'|'"/>
</xsl:apply-templates>

</xsl:template>

<xsl:template match="structure">
<xsl:param name="pVisited"/>

struct <xsl:value-of select="@id"/>
{<xsl:text/>
<xsl:apply-templates/>
};
<xsl:variable name="vnewVisited"
select="concat($pVisited, @id, '|')"/>
<xsl:apply-templates select=
"../structure[not(contains($vnewVisited, concat('|', @id, '|')))
and
not(field/@idref
[not(contains($vnewVisited, concat('|', ., '|')) )
and
. = ../../../structure/@id
]
)
] [1]
">
<xsl:with-param name="pVisited" select="$vnewVisited"/>
</xsl:apply-templates>
</xsl:template>

<xsl:template match="field">
<xsl:value-of select="concat('&#xA; ', @idref, ' ', @name, ';')"/>
</xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<structures>
<structure id="STRUCT_A">
<field idref="STRUCT_B" name="b"/>
<field idref="STRUCT_C" name="c"/>
<field idref="FIELD_D" name="d"/>
</structure>

<structure id="STRUCT_B">
<field idref="STRUCT_C" name="c"/>
<field idref="FIELD_E" name="e"/>
</structure>

<structure id="STRUCT_C">
<field idref="FIELD_E" name="e"/>
<field idref="FIELD_F" name="f"/>
<field idref="FIELD_G" name="g"/>
</structure>
</structures>

产生想要的正确结果:

struct STRUCT_C
{
FIELD_E e;
FIELD_F f;
FIELD_G g;
};


struct STRUCT_B
{
STRUCT_C c;
FIELD_E e;
};


struct STRUCT_A
{
STRUCT_B b;
STRUCT_C c;
FIELD_D d;
};

说明:struct 元素被严格地一一处理。我们随时处理第一个 struct 元素,其 id 尚未在 pVisited 参数中注册,并且没有 field/pVisited 参数中尚未存在的 @idref 值,该值引用现有的 struct 元素。

关于xslt 跳过已经 "visited"节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4205865/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com