(XSLT) 如何递归循环访问列表中每个项目的同一列表?



我是一个相当强大的OOP程序员,所以我在弄清楚XSLT如何"思考"为函数式语言时遇到了一点麻烦。

我正在使用的实际数据是敏感的,所以让我们假设我有一个包含<artist><songs>的 XML<albums>列表,每首歌曲可能有也可能没有<guest_artist>

大致是这样的:

<album>
<album_name>First One</album_name>
<artist_name>SomeGuy</artist_name>
<song>
<song_name>Somebody</song_name>
<guest_artist>SomebodyElse</guest_artist>
</song>
...
</album>

我的目标是制作一个CSV文本文件,其中包含所有<guest_artist>,这些也是其他<album>的主要艺术家,以及他们作为嘉宾出现的专辑。

输出应如下所示:

Guest Artist Name,Album on which they were a Guest
SombodyElse,First One

我最初的方法是在每个/album/guest_artist<for-each>。首先,存储客座艺术家的名字,然后在该循环中,再次<for-each>每个../album/artist_name,看看存储的变量是否与任何艺术家姓名匹配。在内部循环中,如果有匹配项,我会写出一行。

大致是这样的:

<xsl:variable name="linefeed" select="'&#xA;'"/>
<xsl:template match="/">
<!-- Header Row Begins -->
<xsl:textGuest Artist Name,Album on which they were a Guest</xsl:text>
<xsl:value-of select="$linefeed"/>
<!-- Data Row Begins -->
<xsl:for-each select="/album/song/guest_artist">
<xsl:variable name="guest_name" select="guest_artist"/>
<xsl:variable name="this_album_name" select="../album_name"/>
<xsl:for-each select="../../album">
<xsl:if test="$guest_name=artist_name">
<xsl:value-of select="album/song/guest_artist"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="$this_album_name"/>
<xsl:value-of select="$linefeed"/>
</xsl:if>
</xsl:for-each>
<!-- Data Row End -->
</xsl:template>

(我还不担心重复。如果我能弄清楚基础知识,那么我就可以自己解决这个问题。

这会产生奇怪的结果。它似乎首先列出了所有客座艺术家,然后是逗号,然后是所有专辑名称,然后是换行符。

我不是在要求代码(也许是伪代码)。相反,我只是不了解我需要研究的 XSLT 功能,以便实现这一目标。似乎每个循环的行为方式都不符合我的预期。目前还不清楚如何处理范围。我怀疑<templates>会很有用,但我很难弄清楚他们做什么以及如何做。

我已经完成了 W3 学校课程和其他一些关于 XSL 的教程,但它们似乎没有涵盖这些细节。

有什么建议吗?

事实证明,答案比我预期的要简单得多。主要问题是每个循环的"上下文"。第一个<for-each>正在评估一个节点,但第二个嵌套<for-each>开始评估另一个节点。因此,我必须能够告诉内部<for-each>外部<for-each>正在评估哪个节点。这就像将其保存在变量中一样简单。(是的,在其他地方,这被称为"范围",但我不确定"范围"在这种情况下是正确的术语)。

结果大致是这样的:

<xsl:variable name="linefeed" select="'&#xA;'"/>
<xsl:template match="/">
<!-- Header Row Begins -->
<xsl:textGuest Artist Name,Album on which they were a Guest</xsl:text>
<xsl:value-of select="$linefeed"/>
<!-- Data Row Begins -->
<xsl:for-each select="/album/guest_artist">
--->    <xsl:variable name="current_node" select="current()"/>
<xsl:variable name="guest_name" select="guest_artist"/>
<xsl:variable name="this_album_name" select="../album_name"/>
<xsl:for-each select="../../album">
<xsl:if test="$guest_name=artist_name">
--->            <xsl:value-of select="$current_node/guest_artist"/>
<xsl:text>,</xsl:text>
--->            <xsl:value-of select="$current_node/../../album_name"/>
<xsl:value-of select="$linefeed"/>
</xsl:if>
</xsl:for-each>
<!-- Data Row End -->
</xsl:template>

对于此示例,我的路径可能已关闭。从真实数据到示例场景的转换不是 100%,尤其是当我还是 XSL 新手时。但是,生产版本有效;-)

最新更新