Как я могу изменить порядок xsl для каждого? - PullRequest
4 голосов
/ 04 августа 2010

Мне нужно изменить порядок, в котором выполняется мой for-each, только если выполнены некоторые условия.

Вот как выглядит мой XML:

<OptionList>
    <Option name="My First Option" />
    <Option name="My Second Option" />
</OptionList>

Однако в некоторых случаях мой XML может выглядеть так:

<OptionList>
    <Option />
    <Option name="My Second Option" />
</OptionList>

В моем XSL я делаю для каждого, как это:

<xsl:for-each select="//OptionList/Option">
    {...}
</xsl:for-each>

Я знаю, что могу изменить порядок узлов Option, используя эту строку в моем для каждого:

<xsl:sort select="position()" data-type="number" order="descending" />

Проблема в том, что я хочу, чтобы мой ордер был убывающим только тогда, когда мой первый узел Option пуст и не имеет атрибута name. В противном случае я хочу сохранить возрастающий порядок по умолчанию.

Есть какие-нибудь сведения о том, как я могу это достичь? Пока что все, что я пробовал, заканчивалось «Переменная вне области» или неправильным использованием функций xpath.

Ответы [ 3 ]

5 голосов
/ 04 августа 2010

Вы можете использовать хак для изменения порядка сортировки на основе условия:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <result>
    <xsl:for-each select="//OptionList/Option">
      <xsl:sort data-type="number" order="ascending"
        select="position()*(-2*number(not(//OptionList/Option[1]/@name))+1)"/>

      <option>
        <xsl:value-of select="@name"/>
      </option>
    </xsl:for-each>
    </result>

  </xsl:template>
</xsl:stylesheet>

Хак состоит в том, что number((true()) возвращает 1 и number(false()) возвращает 0. Как следствие, выражение

-2 * number(not(//OptionList/Option[1]/@name)) + 1

оценивается как 1, если первый элемент option имеет атрибут name, и -1 в противном случае.Это используется как фактор, чтобы изменить порядок сортировки.

1 голос
/ 05 августа 2010

Порядок получения требуемого результата может быть легко определен с помощью <xsl:sort>:

Это естественно и просто и практически не требует взломов.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vOrder" select=
   "2*boolean(/*/Option[1]/@name)-1"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
   <xsl:copy>
     <xsl:for-each select="Option">
       <xsl:sort data-type="number" select="$vOrder* position()"/>

       <xsl:apply-templates select="."/>
     </xsl:for-each>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование выполняется для этого XML-документа :

<OptionList>
    <Option name="My First Option" />
    <Option name="My Second Option" />
    <Option name="My Third Option" />
</OptionList>

, будет получен требуемый, правильный результат :

<OptionList>
   <Option name="My First Option"/>
   <Option name="My Second Option"/>
   <Option name="My Third Option"/>
</OptionList>

Когда то же самое преобразование теперь выполняется для этого XML-документа :

<OptionList>
    <Option />
    <Option name="My Second Option" />
    <Option name="My Third Option" />
</OptionList>

требуемый, правильный результат получается снова :

<OptionList>
   <Option name="My Third Option"/>
   <Option name="My Second Option"/>
   <Option/>
</OptionList>

Объяснение : переменная $vOrder определена таким образом, что она равна -1, если первый элемент Option не имеет атрибута name и равен +1, если первый *Элемент 1036 * имеет атрибут name.Здесь мы используем тот факт, что false() автоматически преобразуется в 0 и true() в 1.

Мы также используем тот факт, что когда знак каждого числа в последовательности возрастающих положительных чисел (позиции), порядок новой последовательности уменьшается.

0 голосов
/ 04 августа 2010

Проверьте, имеет ли первая опция имя узла или нет

<xsl:if test="Option/[position()=1]/@name">sort here</xsl:test>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...