xslt перебирает весь список или до совпадения
Мне нужно перебрать список объектов и сравнить их в xslt. Если совпадение найдено, мне нужно прекратить обработку документа. Если я попадаю в конец списка и совпадение не найдено, мне нужно обработать документ. Проблема в том, что переменные xslt не могут быть изменены после их объявления. Это был бы простой цикл For с переменной true/false в других распространенных языках.
<!--I need to iterate through this list-->
<xsl:variable name="exclude">
<exclude block="999" />
<exclude block="111" />
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<!-- Here I iterate through the docs, but I don't iterate though the objects in the list.The main problem is I don't know how to search the list and make a decision at the end or when I encounter a match. This code only works on the first object "999" -->
<xsl:template match="/">
<xsl:if test="not(contains($url, exsl:node-set($exclude)/exclude/@block))">
<xsl:copy-of select="." />
</xsl:if>
</xsl:template>
3 ответа
Вы не показали входной документ, ни то, как вы настраивали переменную, и что именно вы хотите проверить, но я не думаю, что вам нужна какая-либо итерация, если вы хотите проверить, что ни один из block
Значения атрибута содержатся в вашей переменной, то
<xsl:if test="not(exsl:node-set($exclude)/exclude/@block[contains($url, .)])">
достаточно сделать это.
Я поставил три образца в
- http://xsltfiddle.liberty-development.net/3Nqn5Y9
- http://xsltfiddle.liberty-development.net/3Nqn5Y9/1
- http://xsltfiddle.liberty-development.net/3Nqn5Y9/2
первые два совпадения (параметр url
является <xsl:param name="url">file://111</xsl:param>
соответственно <xsl:param name="url">file://999</xsl:param>
) и ничего не создается, последний не совпадает (<xsl:param name="url">file://888</xsl:param>
) и вывод создан.
Таким образом, по крайней мере, в контексте обычной настройки XSLT 1 с переменной или параметром, как показано, подход работает.
Если вы используете XSLT 2.0, вы можете использовать хвостовую рекурсию в шаблоне или функции, в идеале с первичной конструкцией выбора, когда иным (операторы when, обеспечивающие механизм завершения, и в противном случае подготовка следующего цикла и сам вызов).
Если вы используете 3.0, попробуйте xsl: iterate.
Здесь довольно много возможных стратегий.
Часто можно написать выражение пути, которое выбирает элементы, которые вы хотите обработать, и использовать это в атрибуте select xsl:for-each.
Случай, когда это не работает, - это когда обработка одного элемента (или решение прекратить) зависит от информации, вычисленной для предыдущих элементов (и когда повторение вычисления слишком дорого каждый раз).
Классическим решением в этом случае является использование рекурсии head-tail: напишите шаблон или функцию, которая принимает список элементов в качестве параметра. Шаблон / функция должны (а) решить, продолжать ли обработку (обычно она завершается, когда список ввода пуст, но возможны другие условия завершения), (б) обрабатывает первый ("головной") элемент и (в) вызывать сам рекурсивно обрабатывать остальную часть списка ("хвост").
В XSLT 3.0 есть удобная инструкция под названием xsl:iterate, которую многие люди находят проще в использовании этой рекурсии, потому что она больше похожа на обычное процедурное программирование. Это похоже на xsl: for-each, за исключением того, что выполнение строго последовательное, и после обработки одного элемента вы устанавливаете параметры, которые доступны при обработке следующего элемента; и есть инструкция xsl:break для досрочного выхода.
Наконец, в версии 3.0 вы можете использовать функциональный подход к программированию функции сложения влево или вправо. Если вы не пришли в XSLT с других языков функционального программирования, это, вероятно, не будет вашим первым выбором. Кроме того, он всегда обрабатывает всю последовательность ввода: нет возможности для досрочного выхода.