Вы можете воспользоваться неявной экзистенциальной квантификацией XPath для оператора =
:
<xsl:for-each select="//vertex[not(@name = //vertex/directed-edge-to/@vertex)]">
Когда вы используете любой из шести операторов сравнения (=
, !=
, <
, <=
, >
и >=
) для сравнения набора узлов, выражение вернет true если какой-либо узел в наборе узлов удовлетворяет условию. При сравнении одного набора узлов с другим, выражение возвращает истину, если какой-либо узел в первом наборе узлов удовлетворяет условию по сравнению с любым узлом во втором наборе узлов. В XPath 2.0 введено шесть новых операторов, которые не выполняют эту экзистенциальную количественную оценку (eq
, ne
, lt
, le
, gt
и ge
). Но в вашем случае вы захотите использовать «=
», чтобы получить это экзистенциальное количественное определение.
Обратите внимание, что вы все равно захотите использовать функцию not()
, как и раньше. В большинстве случаев лучше избегать оператора !=
. Если вы использовали его здесь вместо not()
, то он вернул бы true, если есть какие-либо атрибуты @vertex
, которые не равны значению @name
, что не является вашим намерением. (И если любой набор узлов пуст, тогда он вернет false, поскольку сравнения с пустыми наборами узлов всегда возвращают false.)
Если вы хотите вместо этого использовать eq
, вам нужно будет сделать что-то, как вы: отделить условное от итерации, чтобы вы могли связать current()
. Но в XPath 2.0 вы можете сделать это в выражении:
<xsl:for-each select="for $v in //vertex
return $v[not(//directed-edge-to[@vertex eq $v/@name])]">
Это полезно, когда ваше условие не является простым сравнением на равенство (и, следовательно, не может быть количественно количественно определено с помощью "=
"). Например: starts-with(@vertex, $v/@name)
.
XPath 2.0 также имеет явный способ выполнения экзистенциального количественного определения. Вместо приведенного выше выражения for
мы могли бы написать следующее:
<xsl:for-each select="//vertex[not(some $e in //directed-edge-to
satisfies @name eq $e/@vertex)]">
В дополнение к синтаксису some
XPath 2.0 также предоставляет соответствующий синтаксис every
для выполнения универсального количественного определения.
Вместо использования for-each
вы также можете использовать шаблонные правила, которые являются более модульными (и мощными):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<minimal-vertices>
<xsl:apply-templates/>
</minimal-vertices>
</xsl:template>
<!-- Copy vertex elements that have no arrows pointing to them -->
<xsl:template match="vertex[not(@name = //directed-edge-to/@vertex)]">
<minimal-vertex name="{@name}"/>
</xsl:template>
</xsl:stylesheet>
Опять же, в этом случае мы полагаемся на экзистенциальную количественную оценку =
.
XSLT 1.0 запрещает использование функции current()
в шаблонах, т. Е. В атрибуте match
, но XSLT 2.0 допускает это. В этом случае current()
относится к узлу, который в настоящее время сопоставляется. Таким образом, в XSLT 2.0 мы могли бы также написать это (без использования выражения for
):
<xsl:template match="vertex[not(//directed-edge-to[@vertex eq current()/@name])]">
Обратите внимание, что этот шаблон по сути совпадает с выражением, которое вы пытались использовать в for-each
, но, хотя он и не делает то, что вы хотите в for-each
, он делает , что вы хотите в шаблоне (потому что то, к чему current()
привязывается, отличается).
Наконец, я добавлю еще один вариант, который в некоторой степени упрощает логику (удаление not()
). Это также восходит к использованию XSLT 1.0:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<minimal-vertices>
<xsl:apply-templates/>
</minimal-vertices>
</xsl:template>
<!-- By default, copy vertex elements -->
<xsl:template match="vertex">
<minimal-vertex name="{@name}"/>
</xsl:template>
<!-- But strip out vertices with incoming arrows -->
<xsl:template match="vertex[@name = //directed-edge-to/@vertex]"/>
</xsl:stylesheet>
Если вам не нравится выводимые пробелы, добавьте пустое правило для текстовых узлов, чтобы они были удалены (переопределяя правило по умолчанию для текстовых узлов, то есть копировать их):
<xsl:template match="text()"/>
Или вы можете быть более избирательными в том, к каким узлам вы применяете шаблоны:
<xsl:apply-templates select="/dag/vertex"/>
Какой подход вы выберете, частично зависит от вкуса, частично зависит от более широкого контекста вашей таблицы стилей и ожидаемых данных (насколько может изменяться структура ввода и т. Д.).
Я знаю, что я вышел далеко за рамки того, о чем вы просили, но я надеюсь, что вы хотя бы нашли это интересным : -)