Я пытаюсь понять разницу (или ее отсутствие) между использованием конкатенации последовательностей или объединения последовательностей в этом случае, например:
Входной XML:
<?xml version = "1.0" encoding = "utf-8" ?>
<document>
<someElement a = "1" b = "2" c = "3" d = "4"/>
</document>
XSLT:
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
version = "3.0">
<xsl:mode on-no-match = "shallow-copy"/>
<xsl:output method = "xml" indent = "yes"/>
<xsl:template match = "someElement">
<xsl:copy>
<xsl:copy-of select = "@* except (@c, @d)"/>
</xsl:copy>
<xsl:copy>
<xsl:copy-of select = "@* except (@c | @d)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Выход:
<?xml version = "1.0" encoding = "UTF-8"?>
<document>
<someElement a = "1" b = "2"/>
<someElement a = "1" b = "2"/>
</document>
Поэтому я использовал xsl:copy с оператором exclude, как описано на стр. 261 или XSLT и XPath доктора Кея, 4-е изд. книга. Там запятая используется для построения последовательности.
Я также пробовал с оператором унинон и получил тот же результат.
На странице 537 операторы определены как:
, : Конкатенация последовательности
| union : Объединение двух последовательностей, рассматриваемых как наборы узлов.
Итак, при использовании любого из них есть разница?
Когда вы создаете последовательность с помощью оператора запятая, операнды объединяются в том порядке, в котором вы их перечисляете, и последовательность может содержать повторяющиеся элементы.
OTOH, когда вы используете оператор объединения, элементы перечислены в порядке документа, а повторяющиеся узлы удаляются.
Вот более наглядный пример:
XML
<root>
<alpha/>
<bravo/>
<charlie/>
</root>
XSLT 2.0
<xsl:stylesheet version = "2.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "xml" version = "1.0" encoding = "UTF-8" indent = "yes"/>
<xsl:template match = "/root">
<xsl:copy>
<comma>
<xsl:copy-of select = "bravo, alpha, charlie, bravo"/>
</comma>
<union>
<xsl:copy-of select = "bravo | alpha | charlie | bravo"/>
</union>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Результат
<?xml version = "1.0" encoding = "UTF-8"?>
<root>
<comma>
<bravo/>
<alpha/>
<charlie/>
<bravo/>
</comma>
<union>
<alpha/>
<bravo/>
<charlie/>
</union>
</root>
Добавлен:
В своем ответе выше я решил проигнорировать часть об операторе исключения и сосредоточиться на различиях между операторами запятой и объединения при построении последовательности.
Как указывалось в других ответах, когда к конструктивному выражению добавляется оператор исключения, эти различия эффективно стираются.
Чтобы продемонстрировать это довольно экстремальным образом, инструкция:
<except>
<xsl:copy-of select = "(bravo, alpha, charlie, bravo) except()"/>
</except>
при использовании в приведенном выше примере будет производиться:
<except>
<alpha/>
<bravo/>
<charlie/>
</except>
Для оператора except
, который является оператором «набора», например union
, |
и intersect
, это не имеет значения, поскольку https://www.w3.org/TR/xpath-31/#combining_seq гласит: « Все эти операторы удаляют повторяющиеся узлы из своих результирующих последовательностей на основе идентификатора узла. Результирующая последовательность возвращается в порядке документа».
Выражение X except Y
выбирает каждый узел, который находится в X и не находится в Y.
Выражения (P|Q)
и (P,Q)
доставляют одни и те же узлы, хотя результаты могут быть в другом порядке, а вторая форма может содержать дубликаты. Но поскольку обе формы включают в себя одни и те же узлы, они взаимозаменяемы при использовании в правой части слова «кроме».
Эффективность полностью зависит от реализации, а также от размеров соответствующих наборов узлов. В общем, оценка (P|Q)
требует больше работы, чем оценка (P,Q)
, но тот факт, что результат находится в порядке документа, может сэкономить работу на последующих этапах. Оптимизатор вполне разумно может переписать как X except (P,Q)
, так и X except (P|Q)
как X except P except Q
, и в этом случае, конечно, они оба будут работать одинаково.
Хм. Я подумал, что поскольку (P|Q)
содержит меньше информации, чем (P,Q)
(порядок, кратность), было бы эффективнее использовать его там, где конечный результат все равно одинаков. Но я думаю, я не знаю, как все работает под капотом.
Дьявол кроется в деталях. Если P и Q являются выражениями, использующими дочернюю ось или ось атрибута, вы можете просмотреть ось и проверить каждый узел, чтобы увидеть, совпадают ли они. Если это более сложные выражения, например, вызовы функций, вам придется сортировать результаты в порядке документов и устранять дубликаты в случае «|», работа, которая не требуется в случае «,».
Хорошо. Но я по-прежнему предпочитаю использовать (P|Q)
, когда меня не волнует порядок, и оставляю использование (P,Q)
в тех случаях, когда мне это нужно. Я считаю, что это делает цель кода более ясной.
Это похоже на то, что люди продолжают писать author/@name
вместо author!@name
. Существует естественная тенденция предпочитать конструкции, которые были в языке с самого начала, они кажутся более естественными, несмотря на то, что новые конструкции на самом деле проще и потенциально быстрее.
Я не понимаю, чем причина похожа на тенденцию.
Разве (P|Q) не более эффективен, чем (P,Q)?