我的问题:
我有大量的原子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很难改变,所以提出这种改变的解决方案并不理想。
提前致谢,
特里斯坦·伊斯特本
答案 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;。