1

我的问题:
我有大量的原子 RSS 提要文件,其中有许多不同的原子条目,并且文件之间有一些重叠的条目。我需要根据来自任何一个 RSS 提要的 URL 查找并返回一个条目。

技术:
此代码通过 PHP 5.2.10 的 XLSTProcessor 扩展运行,该扩展使用 XSLT 1,支持 EXSLT 并能够运行内置的 PHP 函数。Saxan、Xalan 或其他类似的解决方案在这种特殊情况下并没有太大帮助。

下面的代码大大简化了,但代表了我的情况。

rss-feed-names.xml:

<feeds>
    <feed name="travel.xml"/>
    <feed name="holidays.xml"/>
    ...
    <feed name="summer.xml"/>
    <feed name="sports.xml"/>
</feeds>

样式表.xsl

<xsl:stylesheet ...>
...

<func:function name="cozi:findPost">
    <xsl:param name="post-url"/>  

    <xsl:variable name="blog-feeds" select="document('rss-feed-names.xml')/feeds"/>  

    <xsl:for-each select="$blog-feeds/feed">
        <xsl:variable name="feed-file" select="document(@name)/atom:feed"/>
        <xsl:variable name="feed-entry" select="$feed-file/atom:entry[atom:link[contains(@href, $post-url)]]"/>
        <xsl:if test="$feed-entry">
            <func:result select="$feed-entry"/><!-- this causes errors if more than one result is found -->
        </xsl:if>
    </xsl:for-each>
</func:function>
</xsl:stylesheet>
...

如果我们要查找的 atom 条目出现在我们查看的文件之一中,则此代码可以正常工作。它可能在该文件中出现多次,但一旦出现在两个或多个文件中,代码就会中断,因为 func:result 已经实例化并且正在被覆盖,这在 XSLT 中是禁止的。

如果有办法实际退出 EXSLT 函数或 xsl:for-each “循环”(您可以为函数分配返回变量,但函数继续;而 for-each 实际上不是循环,但更类似于函数地图),那将是理想的,但我还没有找到方法。

我曾考虑将所有提要合并到一个变量中并完全删除 for-each 循环,但从一开始就遇到了问题。

非常感谢任何其他可能的解决方案、想法或指针!这里的文件关系和 XML 很难更改,因此建议进行此类更改的解决方案并不理想。

在此先感谢,
特里斯坦伊斯特本

4

2 回答 2

0

由于您无法强制退出循环,因此您必须构建完整列表,然后仅返回第一个元素:

<func:function name="cozi:findPost">
    <xsl:param name="post-url"/>  

    <xsl:variable name="blog-feeds" select="document('rss-feed-names.xml')/feeds"/>  

     <xsl:variable name="feedList">
         <xsl:for-each select="$blog-feeds/feed">
            <xsl:variable name="feed-file" select="document(@name)/atom:feed"/>
            <xsl:variable name="feed-entry" select="$feed-file/atom:entry[atom:link[contains(@href, $post-url)]]"/>
            <xsl:if test="$feed-entry">
                <xsl:value-of select="$feed-entry"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <func:result select="$feedList[1]"/>
</func:function>

空列表条件的处理留作练习:-)

于 2009-12-04T03:37:07.540 回答
0

一般的回答(与 Jim 的回答一样)是您不应该将 <func:result> 放在 <xsl:for-each> 中。对于这种情况,我更具体的解决方案不需要您使用 <xsl:for-each> 甚至 <xsl:variable>。您可以单独使用 XPath:

<func:result select="(document
                       (document('rss-feed-names.xml')/feeds/@name)
                       /atom:feed
                       /atom:entry
                             [atom:link
                                   [contains(@href, $post-url)]]
                     )[1]"/>

这是有效的,因为 document() 可以采用节点集。当它这样做时,它会去获取参数中每个节点引用的文档。多输入/多输出。

也就是说,明智地使用解释变量将有助于提高可读性。不过,您不需要使用 <xsl:for-each>。

于 2009-12-07T22:32:31.967 回答