Выдавать только HTML, когда переменная отличается от последней итерации в XSLT - PullRequest
1 голос
/ 26 октября 2010

Использование XSLT Я пытаюсь найти способ испускать строку таблицы HTML, только если значение отличается от последней итерации цикла for-each. По сути, я хочу, чтобы таблица отображалась сгруппированными заголовками, выписывая заголовок только после его изменения.

У меня возникли некоторые проблемы, когда я концептуально выяснил, как я мог бы это сделать, учитывая, что вы не можете изменить значение переменной после ее определения.

<xsl:for-each select="//databaseConstraint/constraint">

    <xsl:variable name="caption" select="@caption" />

    <tr>
        <th colspan="2"><xsl:value-of select="$caption" /></th>
    </tr>

    ...

</xsl:for-each >

Обновление Я пробовал ниже, но получаю ошибку: NodeTest ожидается здесь

<xsl:for-each select="//databaseConstraint/constraint">

    <xsl:variable name="caption" select="@caption" />

    <xsl:if test="not(@caption = preceding-sibling::@caption)">
    <tr>
        <th colspan="2">
            <xsl:value-of select="$caption" />
        </th>
    </tr>
    </xsl:if>

    ...

</xsl:for-each >

Ответы [ 4 ]

1 голос
/ 26 октября 2010

Я пытаюсь найти способ выдавать строку таблицы HTML, только если значение отличается от последней итерации цикла for-each

Это отвечает на вопрос буквально .Если вы хотите выполнить группировку , узнайте о мюнхенской группировке .

Это преобразование :

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

 <xsl:template match="/">
  <xsl:variable name="vConstraints"
       select="//databaseConstraint/constraint"/>
  <table>
      <xsl:for-each select="$vConstraints">
        <xsl:variable name="vCaption" select="@caption" />
        <xsl:variable name="vPos" select="position()"/>

        <xsl:if test="not($vCaption = $vConstraints[$vPos -1]/@caption)">
            <tr>
                <th colspan="2"><xsl:value-of select="$vCaption" /></th>
            </tr>
        </xsl:if>
      </xsl:for-each>
  </table>
 </xsl:template>
</xsl:stylesheet>

при применении к следующему документу XML :

<t>
 <a>
 <databaseConstraint>
   <constraint caption="Simple Constraint"/>
 </databaseConstraint>
 <databaseConstraint>
   <constraint caption="Simple Constraint"/>
 </databaseConstraint>
 </a>
 <b>
 <databaseConstraint>
   <constraint caption="Complex Constraint"/>
 </databaseConstraint>
 </b>
</t>

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

<table>
   <tr>
      <th colspan="2">Simple Constraint</th>
   </tr>
   <tr>
      <th colspan="2">Complex Constraint</th>
   </tr>
</table>

Примечание :

  1. Преобразование работает даже в том случае, если элементы <constraint> не являются братьями и сестрами или даже если некоторые из нихпредки / потомки друг друга.

  2. В этом случае необходимо собрать все <constraint> элементы в переменной и запомнить position() текущего <constraint> element , чтобы можно было сравнить его с элементом <constraint> в предыдущей позиции в наборе узлов.

1 голос
/ 26 октября 2010
<xsl:if test="not(@caption = preceding-sibling::@caption)">

Это будет проверять, равен ли заголовок атрибуту заголовка, который является родственным узлом контекстного узла, то есть родственным элементом обрабатываемого элемента ограничения. Но я подозреваю, что он «не работает» с синтаксической ошибкой, потому что шаг заголовка имеет две оси: preceding-sibling:: и attribute:: (для которого @ означает сокращение).

То, что вы, вероятно, хотите, это

<xsl:if test="not(@caption = preceding-sibling::constraint[1]/@caption)">

Это будет делать то, что вы хотите, это проще, чем Muenchian, и это, вероятно, достаточно быстро, если реализация XPath в браузере приличная, потому что ему нужно тестировать только один другой узел, а не все предыдущие узлы ограничения.

Если эта стратегия не достаточно быстра для ваших целей, например, если у вас много данных, вы можете использовать мюнхенскую группировку, как сказал @ Frédéric.

Добавление: [1] является сокращением для [position() = 1]. Здесь это означает, что в правой части = у нас есть только @caption of ограничение непосредственно , предшествующее текущему элементу. Если бы мы пропустили [1], мы сравнили бы значение @caption текущего элемента с @captions all , предшествующих элементам ограничения родственного элемента.

Важно понимать, что оператор XPath = работает с наборами узлов (когда есть шанс), а не только с отдельными значениями или узлами. Таким образом, A = B, где A и B являются наборами узлов, возвращает true, если существует любой член набора узлов A, равный любому члену набора узлов B. Это скорее похоже на соединение в SQL. Это мощная операция, но вы должны осознавать, что она делает.

Еще одна деталь ... Почему [1] дает элемент ограничения , непосредственно предшествующий текущему, вместо первого в документе? Потому что position() отражает направление текущей оси, которое в данном случае равно preceding-sibling. Как сказано в спецификации XPath ,

ось, которая только когда-либо содержит узел контекста или узлы, которые находятся до контекстный узел в порядке документа обратная ось . Таким образом, предок, предок или сам, предшествующий и предшествующий брат оси обратные оси; все остальные оси являются прямыми. ...

Близость положения члена набор узлов относительно оси определяется как позиция узла в наборе узлов, упорядоченном в документе порядок, если ось является передней осью и заказано в обратном порядке документа если ось является обратной осью. первая позиция 1.

НТН.

0 голосов
/ 26 октября 2010

Вы можете попытаться сравнить текущий узел (или один из его атрибутов) с предыдущим узлом, используя предыдущий или предшествующий брат, и отобразить таблицу, только если текущий! = Предыдущий. См. Оси XPath .

0 голосов
/ 26 октября 2010

Это нелегко сделать с помощью XSLT 1.0. Если ваша реализация поддерживает функции XSLT 2.0, используйте xsl: for-each-group . Если вы застряли с 1.0, проверьте эту мюнхенскую реализацию, используя ключи .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...