XSLT 1.0 - условное назначение узлов - PullRequest
5 голосов
/ 15 ноября 2011

с использованием чистого XSLT 1.0, как я могу условно назначить узел. Я пытаюсь что-то вроде этого, но это не работает.

<xsl:variable name="topcall" select="//topcall"/>
<xsl:variable name="focusedcall" select="//focusedcall" />

<xsl:variable name="firstcall" select="$topcall | $focusedcall"/>

Для переменной firstcall я делаю выбор условного узла. если есть topcall, тогда присвойте его firstcall, другим присвойте firstcall focusedcall.

Ответы [ 3 ]

5 голосов
/ 15 ноября 2011

Это должно работать:

<xsl:variable name="firstcall" select="$topcall[$topcall] |
                                       $focusedcall[not($topcall)]" />

Другими словами, выберите $topcall, если $topcall nodeset не пуст; $focusedcall, если $topcall набор узлов пуст.

Повторное обновление относительно "это может быть 5-6 узлов":

Учитывая, что может быть 5-6 альтернатив, то есть еще 3-4, кроме $ topcall и $ focuscall ...

Самое простое решение - использовать <xsl:choose>:

<xsl:variable name="firstcall">
  <xsl:choose>
    <xsl:when test="$topcall">    <xsl:copy-of select="$topcall" /></xsl:when>
    <xsl:when test="$focusedcall"><xsl:copy-of select="$focusedcall" /></xsl:when>
    <xsl:when test="$thiscall">   <xsl:copy-of select="$thiscall" /></xsl:when>
    <xsl:otherwise>               <xsl:copy-of select="$thatcall" /></xsl:otherwise>
  </xsl:choose>
</xsl:variable>

Однако в XSLT 1.0 это преобразует вывод выбранного результата во фрагмент дерева результатов (RTF: в основном, замороженное поддерево XML). После этого вы не сможете использовать какие-либо существенные XPath-выражения в $firstcall для выбора вещей из него. Если вам нужно , чтобы сделать выбор XPath на $firstcall позже, например, select="$firstcall[1]", тогда у вас есть несколько вариантов ...

  1. Поместите эти выборки в <xsl:when> или <xsl:otherwise>, чтобы они произошли до того, как данные будут преобразованы в RTF. Или,
  2. Рассмотрим расширение node-set(), которое преобразует RTF в набор узлов, поэтому вы можете делать из него обычные выборки XPath. Это расширение доступно в большинстве процессоров XSLT, но не во всех. Или,
  3. Рассмотрите возможность использования XSLT 2.0, где RTF вообще не являются проблемой. На самом деле, в XPath 2.0 вы можете поместить обычные условные выражения if / then / else внутри выражения XPath, если хотите.
  4. Реализуйте его в XPath 1.0, используя вложенные предикаты, такие как

select="$topcall[$topcall] |
        ($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])[not($topcall)]"

и продолжайте гнездиться настолько глубоко, насколько это необходимо. Другими словами, здесь я взял выражение XPath для 2 альтернатив выше и заменил $ focuscall на

($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])

На следующей итерации вы замените $ thiscall на

($thiscall[$thiscall] | $thatcall[not($thiscall)])

и т.д.

Конечно, это становится трудным для чтения и подвержено ошибкам, поэтому я бы не стал выбирать этот вариант, если другие неосуществимы.

3 голосов
/ 15 ноября 2011

<xsl:variable name="firstcall" select="($topcall | $focusedcall)[1]"/> делает то, что вы хотите?Это обычно способ взять первый узел в порядке документа различных типов узлов.

2 голосов
/ 16 ноября 2011

I.Решение XSLT 1.0 Это короткое (30 строк) простое и параметризованное преобразование работает с любым количеством типов / имен узлов:

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

 <xsl:param name="pRatedCalls">
   <call type="topcall"/>
   <call type="focusedcall"/>
   <call type="normalcall"/>
 </xsl:param>

 <xsl:variable name="vRatedCalls" select=
  "document('')/*/xsl:param[@name='pRatedCalls']/*"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:variable name="vpresentCallNames">
  <xsl:for-each select="$vRatedCalls">
   <xsl:value-of select=
   "name($vDoc//*[name()=current()/@type][1])"/>
   <xsl:text> </xsl:text>
  </xsl:for-each>
 </xsl:variable>

 <xsl:template match="/">
  <xsl:copy-of select=
   "//*[name()
       =
        substring-before(normalize-space($vpresentCallNames),' ')]"/>
 </xsl:template>
</xsl:stylesheet>

Применительно к этому документу XML (doобратите внимание, что порядок документов не совпадает с указанными приоритетами в параметре pRatedCalls):

<t>
 <normalcall/>
 <focusedcall/>
 <topcall/>
</t>

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

<topcall/>

когда то же преобразование применяется к следующему XML-документу :

<t>
 <normalcall/>
 <focusedcall/>
</t>

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

<focusedcall/>

Объяснение :

  1. Имена узлов, которые необходимо найти (столько, сколько необходимо и в порядке приоритета), задаются глобальным(обычно это внешний параметр) параметр с именем $pRatedCalls.

  2. В теле переменной $vpresentCallNames мы генерируем разделенный пробелами список имен элементов, которые оба указаны в качестве значенияатрибута type элемента callПараметр t in the $ pRatedCalls`, а также имена элементов в документе XML.

  3. Наконец, мы определяем первое такое имя в этом списке, разделенном пробелами, и выбираем все элементы вдокумент с таким названием.

II.Решение 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:param name="pRatedCalls" select=
  "'topcall', 'focusedcall', 'normalcall'"/>

 <xsl:template match="/">
  <xsl:sequence select=
   "//*
     [name()=$pRatedCalls
                [. = current()//*/name()]
                                        [1]
     ]"/>
 </xsl:template>
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...