Простой XPath 2.0 :
empty(
(for $parentA-Dubled in /*/*[a = following-sibling::*/a]
return
empty($parentA-Dubled/following-sibling::*
[$parentA-Dubled/a eq a and $parentA-Dubled/b ne b])
)
[not(.)]
)
XSLT 2.0 - проверка на основе:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select=
"empty(
(for $parentA-Dubled in /*/*[a = following-sibling::*/a]
return
empty($parentA-Dubled/following-sibling::*
[$parentA-Dubled/a eq a and $parentA-Dubled/b ne b])
)
[not(.)]
)
"/>
</xsl:template>
</xsl:stylesheet>
Когдаэто преобразование применяется к любому XML-документу, оно оценивает выражение XPath и выводит результат этой оценки .
При применении к первому предоставленному XML-документу получается требуемый, правильный результат:
true
При применении ко второму предоставленному XML-документу снова получается нужный, правильный результат:
false
Объяснение :
Это подвыражение:
(for $parentA-Dubled in /*/*[a = following-sibling::*/a]
return
empty($parentA-Dubled/following-sibling::*
[$parentA-Dubled/a eq a and $parentA-Dubled/b ne b])
вычисляет последовательность логических значений: true()
/ false()
true()
возвращается, когда это правда:
empty($parentA-Dubled/following-sibling::*
[$parentA-Dubled/a eq a and $parentA-Dubled/b ne b])
Это означает, что true()
возвращается для каждого случая, когда существует $parentA-Dubled/a
, у которого нет другого a
(потомок следующего брата $parentA-Dubled
с тем же значением, что и $parentA-Dubled/a
, нозначение его b
родного брата отличается от значения $parentA-Dubled/b
.
Подводя итог : true()
возвращается, когда для всех a
элементов с одинаковым значением их b
братьев и сестер также имеют (все b
с) одинаковое значение
Тогдакогда происходит возврат false()
?
Возвращение false()
означает, что empty()
вернул false()
- то есть существует хотя бы один случай из двух a
элементов, которые имеютто же значение, но у их b
родных элементов есть разные значения.
Таким образом, вышеприведенное подвыражение возвращает последовательность, такую как:
true(), true(), true(), ..., true()
- все значения true()
или
true(), true(), true(), ..., false), ..., true()
- по крайней мере одно из значений равно false()
Первоначальная проблема требует, чтобы мы вернули true()
в первом случае и вернулиfalse()
во втором случае.
Это легко выразить как:
empty($booleanSequence[. eq false()])
- и это эквивалентно более короткому:
empty($booleanSequence[not(.)])
Теперь нам просто нужно заменить в вышеприведенном выражении $booleanSequence
первое подвыражение, которое мы проанализировали выше:
(for $parentA-Dubled in /*/*[a = following-sibling::*/a]
return
empty($parentA-Dubled/following-sibling::*
[$parentA-Dubled/a eq a and $parentA-Dubled/b ne b])
Таким образом, мыполучить полное выражение XPath, которое решает исходную проблему:
empty(
(for $parentA-Dubled in /*/*[a = following-sibling::*/a]
return
empty($parentA-Dubled/following-sibling::*
[$parentA-Dubled/a eq a and $parentA-Dubled/b ne b])
)
[not(.)]
)