EXSLT func: возвращать проблемы в xsl: for-each "loop" и func: function - PullRequest
1 голос
/ 03 декабря 2009

Моя проблема:
У меня есть множество атомных файлов RSS-каналов, в которых есть много разных записей атомов и несколько перекрывающихся записей между файлами. Мне нужно найти и вернуть запись на основе URL-адреса любого из RSS-каналов.

Технология:
Этот код выполняется через расширение XLSTProcessor PHP 5.2.10, которое использует 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 «loop» (вы можете назначить возвращаемую переменную для функции, но функция продолжается; и for-each's фактически не являются циклами, но похоже на функциональные карты), это было бы идеально, но я еще не нашел пути.

Я рассмотрел объединение всех каналов в одну переменную и полное удаление цикла for-each, но у меня были проблемы с тем, чтобы это с самого начала работало.

Любые другие возможные решения, идеи или указатели очень ценятся! Взаимосвязь файлов и XML довольно трудно изменить, поэтому решения, предлагающие такое изменение, не идеальны.

Заранее спасибо,
Тристан Истберн

Ответы [ 2 ]

0 голосов
/ 08 декабря 2009

Общий ответ (как и в ответе Джима) заключается в том, что вы не должны помещать внутри . Мое более конкретное решение для этого случая не требует, чтобы вы использовали или даже . Вы можете использовать только XPath:

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

Это работает, потому что document () может принимать набор узлов. Когда это происходит, он идет и получает документ, на который ссылается каждый узел в аргументе. Несколько входов / несколько выходов.

Тем не менее, разумное использование объяснения переменных было бы полезно для удобства чтения. Тем не менее, вам не нужно использовать .

0 голосов
/ 04 декабря 2009

Поскольку вы не можете принудительно выйти из цикла, вы должны построить полный список, а затем вернуть только первый элемент:

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

Обработка условия пустого списка оставлена ​​в качестве упражнения: -)

...