我正在处理一个简化的 XML 文件,看起来像这样:
<resources>
<resource id="a">
<dependency idref="b"/>
<!-- some other stuff -->
</resource>
<resource id="b">
<!-- some other stuff -->
</resource>
</resources>
XSLT 样式表必须处理我们感兴趣的特定资源,我将其称为根资源,以及所有递归依赖项。id
依赖项是其他资源,由它们的属性唯一标识。
一个资源是否被处理两次并不重要,尽管最好只处理每个所需资源一次。处理资源的顺序也无关紧要。
重要的是只处理根资源及其递归依赖项。我们不能只处理所有资源并完成它。
一个简单的实现如下:
<xsl:key name="resource-id" match="resource" use="@id"/>
<xsl:template match="resource">
<!-- do whatever is required to process the resource. -->
<!-- then handle any dependencies -->
<xsl:apply-templates select="key('resource-id', dependency/@idref)"/>
</xsl:template>
此实现适用于上述示例以及许多实际案例。它确实有一个缺点,即它经常多次处理相同的资源,但如上所述,这并不是非常重要。
问题是有时资源具有循环依赖关系:
<resources>
<resource id="a">
<dependency idref="b"/>
<dependency idref="d"/>
</resource>
<resource id="b">
<dependency idref="c"/>
</resource>
<resource id="c">
<dependency idref="a"/>
</resource>
<resource id="d"/>
</resources>
如果您使用朴素的实现来处理此示例,并且从处理a、b或c开始,您将获得无限递归。
不幸的是,我无法控制输入数据,并且在任何情况下循环依赖都是完全有效的,并且相关规范允许。
我提出了各种部分解决方案,但没有任何一种方法适用于所有情况。
理想的解决方案是防止节点被多次处理的通用方法,但我认为这是不可能的。事实上,我怀疑这整个问题是不可能解决的。
如果有帮助,我可以使用大部分 EXSLT(包括功能)。如有必要,我还可以使用任意数量的其他 XSLT 脚本对输入进行预处理,但最好不要对不会出现在输出中的资源进行过多的预处理。
我不能做的是切换到用另一种语言处理这个(至少不是没有大量的重新设计)。我也不能使用 XSLT 2.0。
有任何想法吗?