我是一个相当强大的OOP程序员,所以我在弄清楚XSLT如何“认为”作为一种函数式语言时遇到了一些麻烦。
我正在处理的实际数据很敏感,所以我假设我有一个<albums>
的XML列表,其中包含<artist>
,<songs>
,每首歌可能会也可能不会有一个<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>
我的目标是生成所有<guest_artist>
的CSV文本文件,这些文件也是其他<album>
的主要艺术家,以及它们作为访客显示的相册。
输出应该如下所示:
Guest Artist Name,Album on which they were a Guest
SombodyElse,First One
我最初的方法是<for-each>
超过每个/album/guest_artist
。首先,存储来宾艺术家的名字,然后在该循环中再次<for-each>
在每个../album/artist_name
上,并查看存储的变量是否与任何艺术家名称相匹配。在内循环中,如果匹配,我写出一行。
大致相同:
<xsl:variable name="linefeed" select="'
'"/>
<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的教程,但它们似乎没有涵盖这些细节。
有什么建议吗?
答案 0 :(得分:0)
答案结果比我想象的要简单得多。主要问题是每个循环的“上下文”。第一个<for-each>
正在评估一个节点,但第二个嵌套<for-each>
开始评估另一个节点。因此,我必须能够告诉内部<for-each>
外部<for-each>
正在评估哪个节点。这就像将其保存在变量中一样简单。 (是的,在其他地方,这被称为“范围”,但我不确定“范围”在这种情况下是正确的术语)。
大致是这样的:
<xsl:variable name="linefeed" select="'
'"/>
<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的新手时。但是,生产版本有效; - )