XML - XSL - выбрать только первый элемент, соответствующий условию - PullRequest
0 голосов
/ 19 февраля 2019

Давайте предположим, что у меня есть массив MyObject элементов, который имеет некоторое свойство, скажем, IsFinalResult , на основе которого я хотел бы условно выбрать элемент.Я хочу, чтобы логика принимала только первый элемент из массива, который соответствует данному условию IsFinalResult == true (даже если несколько элементов соответствуют условию).

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
      <xsl:for-each select="ArrayOfMyObject/MyObject">
         <xsl:choose>
            <xsl:when test="// Here how to check?">
               // this will match only once
            </xsl:when>
            <xsl:otherwise>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

Я могу сделать это только с XPath 1.0.

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Рассмотрите возможность использования шаблонного подхода ...

<xsl:template match="/">
  <xsl:apply-templates select="ArrayOfMyObject/MyObject" />
</xsl:template>

Затем, чтобы представить ваш xsl:when тест, соответствующий первому из элементов "IsFinalResult = 'true'", совпадение шаблона будетthis ...

<xsl:template match="MyObject[@IsFinalResult='true'][1]">

(заметьте, я предполагаю, что IsFinalResult является здесь атрибутом. Если нет, просто удалите префикс @)

И для представления xsl:otherwise, иметь шаблон (с более низким приоритетом), который подберет все остальные MyObject элементы

<xsl:template match="MyObject">

Итак, учитывая следующий XML:

<ArrayOfMyObject>
    <MyObject IsFinalResult="false">1</MyObject>
    <MyObject IsFinalResult="false">2</MyObject>
    <MyObject IsFinalResult="true">3</MyObject>
    <MyObject IsFinalResult="false">4</MyObject>
    <MyObject IsFinalResult="true">5</MyObject>
    <MyObject IsFinalResult="true">6</MyObject>
</ArrayOfMyObject>

Если вы применяетеэто XSLT

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

  <xsl:template match="/">
    <xsl:apply-templates select="ArrayOfMyObject/MyObject" />
  </xsl:template>

  <xsl:template match="MyObject[@IsFinalResult='true'][1]">
    <When>
      <xsl:value-of select="." />
    </When>
  </xsl:template>

  <xsl:template match="MyObject">
    <Otherwise>
      <xsl:value-of select="." />
    </Otherwise>
  </xsl:template>
</xsl:stylesheet>

Вывод такой ...

<Otherwise>1</Otherwise>
<Otherwise>2</Otherwise>
<When>3</When>
<Otherwise>4</Otherwise>
<Otherwise>5</Otherwise>
<Otherwise>6</Otherwise>

(Измените соответствие шаблона на <xsl:template match="MyObject[@IsFinalResult='true' and position() = 1]">, если вы хотите учитывать @IsFinalResult='true', если это оченьпервый дочерний элемент).

Обратите внимание, что если вы хотите, чтобы ваш xsl:otherwise обрабатывал элементы, где IsFinalResult="true" (после первого), вам просто нужно добавить третий шаблон, чтобы игнорировать другие элементы

<xsl:template match="MyObject[not(@IsFinalResult='true')]" />
0 голосов
/ 19 февраля 2019

Вы можете сделать это с помощью функции position()

<xsl:when test="position() = 1 and IsFinalResult='true'">
   // this will match only once
</xsl:when>

Но есть и другие способы справиться с этой ситуацией.
Одним из них является использование сопоставления шаблонов с предикатами:

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true' and position() = 1]">
  <!-- For the first MyObject element -->
  ...

и

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true' and position() > 1]">
  <!-- For all the other MyObject elements -->
  ...

Вдохновленный комментарием ниже, есть другой способ прочитать ваш вопрос (который я имел в одной из предыдущих версий этого ответа),Этот способ может быть реализован с помощью двух отдельных условий:

<xsl:for-each select="ArrayOfMyObject/MyObject[IsFinalResult='true']">
  <xsl:choose>
    <xsl:when test="position() = 1">
      // this will match only once
    </xsl:when>
  ...

Второй способ изменяется следующим образом:

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true'][1]">
  <!-- Matches the first element of the list of elements that satisfy the first predicate -->
  ...

Здесь [1] не требуется - рассмотрите его как способПодчеркните удобочитаемость.
А

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true'][position() > 1]">
  <!-- Matches all the other elements of the list of elements that satisfy the first predicate -->
  ...
...