EXSLT func:在xsl:for-each“loop”和func:function中返回问题

时间:2009-12-03 20:01:12

标签: xslt function return foreach exslt

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

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

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

RSS馈送-names.xml:

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

stylesheet.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>
...

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

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

我已经考虑将所有Feed合并到一个变量中并完全删除for-each循环,但是从一开始就让它工作有问题。

非常感谢任何其他可能的解决方案,想法或指示!这里的文件关系和XML很难改变,所以提出这种改变的解决方案并不理想。

提前致谢,
特里斯坦·伊斯特本

2 个答案:

答案 0 :(得分: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>

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

答案 1 :(得分:0)

一般答案(与Jim的回答一样)是你不应该把&lt; func:result&gt;在&lt; xsl:for-each&gt;内针对此案例的我更具体的解决方案不要求您使用&lt; xsl:for-each&gt;甚至&lt; xsl:variable&gt;。您可以单独使用XPath:

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

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

那就是说,明智地使用解释变量会有助于提高可读性。不过,您不需要使用&lt; xsl:for-each&gt;。