gpt4 book ai didi

xslt - 使用 XSLT 处理循环依赖

转载 作者:行者123 更新时间:2023-11-30 23:59:51 25 4
gpt4 key购买 nike

我正在处理一个 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>

如果你使用简单的实现来处理这个例子,并且你从处理 开始 , b c ,你得到无限递归。

不幸的是,我无法控制输入数据,并且在任何情况下循环依赖都是完全有效的,并且是相关规范所允许的。

我想出了各种部分解决方案,但没有任何方法适用于所有情况。

理想的解决方案是防止节点被多次处理的通用方法,但我认为这是不可能的。事实上,我怀疑这整个问题是不可能解决的。

如果有帮助,我可以使用大部分 EXSLT(包括函数)。如有必要,我还可以使用任意数量的其他 XSLT 脚本对输入进行预处理,尽管最好不要对不会出现在输出中的资源进行过多的预处理。

我不能做的是切换到用另一种语言来处理它(至少在没有大量重新设计的情况下不能)。我也不能使用 XSLT 2.0。

有任何想法吗?

最佳答案

这是一个简单的解决方案 :

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

<xsl:param name="pRootResourceId" select="'a'"/>

<xsl:key name="kResById" match="resource" use="@id"/>

<xsl:template match="/">
<resourceProcessing root="{$pRootResourceId}">
<xsl:apply-templates select=
"key('kResById', $pRootResourceId)"/>
</resourceProcessing>
</xsl:template>

<xsl:template match="resource">
<xsl:param name="pVisited" select="'|'"/>

<xsl:copy>
<xsl:copy-of select="@*"/>

<xsl:apply-templates select=
"key('kResById',
dependency/@idref
[not(contains($pVisited, concat('|', ., '|')))])">
<xsl:with-param name="pVisited"
select="concat($pVisited, @id, '|')"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时 :
<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>

产生了想要的、正确的结果 :
<resourceProcessing root="a">
<resource id="a">
<resource id="b">
<resource id="c"/>
</resource>
<resource id="d"/>
</resource>
</resourceProcessing>

主要思想很简单 :维护已访问资源的 id 列表,并且仅当新资源的 id 不在列表中时才允许处理新资源。 “处理”用于演示目的,并输出包装它所依赖的所有其他请求(递归)的请求。

另请注意 request只处理一次。

几年前,我为图遍历问题提供了一个类似的解决方案——它可以在 xml-dev 组文件中找到—— here . :)

关于xslt - 使用 XSLT 处理循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3401488/

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