Как объединить два набора узлов так, чтобы порядок соблюдался? - PullRequest
4 голосов
/ 06 января 2011

Насколько я понимаю, несмотря на то, что "наборы узлов" в XSLT называются "наборами", на самом деле они представляют собой упорядоченные списки узлов (именно поэтому каждый узел связан с индексом). Поэтому я пытался использовать "|" оператор для объединения наборов узлов, так что порядок узлов соблюдается.

Я пытаюсь выполнить что-то вроде следующего кода JavaScript:

[o1,o2,o3].concat([o4,o5,o6])

Что дает:

[o1,o2,o3,o4,o5,o6]

Но рассмотрим следующий сокращенный пример:

testFlatten.xsl

<?xml version="1.0"?>
<xsl:stylesheet 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 version="1.0">
 <xsl:output method="xml"/>

 <xsl:template match="/">

  <xsl:variable name="parentTransition" select="//*[@id='parentTransition']"/>
  <xsl:variable name="childTransition" select="//*[@id='childTransition']"/>
  <xsl:variable name="parentThenChildTransitions" select="$parentTransition | $childTransition"/>
  <xsl:variable name="childThenParentTransitions" select="$childTransition | $parentTransition"/>

  <return>
   <parentThenChildTransitions>
    <xsl:copy-of select="$parentThenChildTransitions"/>
   </parentThenChildTransitions>
   <childThenParentTransitions>
    <xsl:copy-of select="$childThenParentTransitions"/>
   </childThenParentTransitions>
  </return>

 </xsl:template>

</xsl:stylesheet>

С учетом следующего ввода:

<?xml version="1.0"?>
<root>
        <element id="parentTransition"/>

 <element id="childTransition"/>
</root>

Что дает (с xsltproc):

<?xml version="1.0"?>
<return>
    <parentThenChildTransitions>
        <element id="parentTransition"/><element id="childTransition"/>
    </parentThenChildTransitions>
    <childThenParentTransitions>
        <element id="parentTransition"/><element id="childTransition"/>
    </childThenParentTransitions>
</return>

Так что "|" оператор на самом деле не уважает порядок операндов набора узлов. Есть ли способ, которым я могу объединить наборы узлов так, чтобы порядок соблюдался?

Ответы [ 3 ]

8 голосов
/ 06 января 2011

На самом деле это не XSLT, а вопрос XPath.

В XPath 1.0 нет ничего похожего на тип данных "список".Набор узлов - это набор, и у него нет порядка.

В XPath 2.0 существует тип данных sequence .Любые элементы в последовательности упорядочены.Это не имеет ничего общего с порядком документов.Кроме того, один и тот же элемент (или узел) может появляться в последовательности более одного раза.

Таким образом, в XSLT 2.0 просто используется оператор конкатенации последовательности XPath 2.0 ,:

//*[@id='parentTransition'] , //*[@id='childTransition']

, и это оценивает последовательность всех элементов в документе с атрибутом id 'parentTransition', за которым следуют все элементы в документе с атрибутом id 'childTransition'

В XSLT все еще возможно получить доступ и обрабатывать узлы не в порядке документа : например, с помощью инструкции <xsl:sort> - однако набор узлов, которые обрабатываются в результате <xsl:apply-templates> или <xsl:for-each>, являетсяnode-list - не набор узлов.

Другим примером оценки узлов не в порядке документа является функция position() в <xsl:apply-templates> или <xsl:for-each>, которые имеют <xsl:sort> дочерний или в предикате шага местоположения (выражения XPath), в котором используется обратная ось (например, ancesstor:: или preceeding::)

3 голосов
/ 06 января 2011

В XSLT 1.0 вы можете обрабатывать узлы в выбранном порядке (например, с помощью xsl: sort), но вы не можете хранить список узлов в переменной.Единственное, что вы можете хранить в переменной (или передать в шаблон и т. Д.) - это набор узлов;Наборы узлов не имеют собственного порядка, но когда вы их обрабатываете, они всегда обрабатываются в порядке документов, если вы не используете xsl: sort для запроса другого порядка обработки.

Возможно, вы сможете решить свою проблему, скопировавузлы:

<xsl:variable name="temp">
  <xsl:copy-of select="$ns0"/>
  <xsl:copy-of select="$ns1"/>
</xsl:variable>
...
<xsl:apply-templates select="exslt:node-set($temp/*)"/>

, но это зависит от вашего варианта использования.

Переключитесь на XSLT 2.0, если можете!

1 голос
/ 06 января 2011

"|"Оператор сохранит узлы в порядке документа.В XSLT 1.0 вам понадобятся последовательные операции copy или for-each.

<xsl:copy-of select="$parentTransition"/>
<xsl:copy-of select="$childTransition"/>
...