XSLT для нескольких условий - PullRequest
       0

XSLT для нескольких условий

0 голосов
/ 25 августа 2018

У меня есть вопрос по XSLT. В основном я ищу ... Уникальный метод доставки (Mail, Home и т. Д.) Из последней транзакции для книг, имеющих статус «В наличии» из приведенного ниже xml. Например, в приведенном ниже примере «Mail» и «Store Pickup» будут результатом. Может ли кто-нибудь помочь мне с XSLT? Заранее спасибо.

<BookCollection>
    <Book>
        <status>In Stock</status>
        <name>The Hunt for Red October</name>
        <OrderHistory>
           <Order>
              <transactionid>sssss</transactionid>
               <date>2018-03-24</date>
               <Delivery>Home</Delivery>
           </Order>
           <Order>
              <transactionid>sssss</transactionid>
              <date>2018-04-23</date>
              <Delivery>Mail</Delivery>
           </Order>
        </Orderhistory>
    </Book>
    <Book>
        <name>A case of need</name>
        <status>Pending Stock</status>
        <OrderHistory>
           <Order>
              <transactionid>sssss</transactionid>
               <date>2018-08-24</date>
               <Delivery>Home</Delivery>
           </Order>
           <Order>
              <transactionid>sssss</transactionid>
              <date>2018-02-23</date>
              <Delivery>Store Pickup</Delivery>
           </Order>
        </Orderhistory>
    </Book>
    <Book>
        <name>Sharp Objects</name>
        <status>In Stock</status>
        <OrderHistory>
           <Order>
              <transactionid>sssss</transactionid>
               <date>2018-01-24</date>
               <Delivery>Home</Delivery>
           </Order>
           <Order>
              <transactionid>sssss</transactionid>
              <date>2018-05-23</date>
              <Delivery>Store Pickup</Delivery>
           </Order>
        </Orderhistory>
    </Book>
    <Book>
        <name>Happy Doomsday</name>
        <status>In Stock</status>
        <OrderHistory>
           <Order>
              <transactionid>aaa</transactionid>
               <date>2018-01-24</date>
               <Delivery>Mail</Delivery>
           </Order>
           <Order>
              <transactionid>bb</transactionid>
              <date>2018-03-23</date>
              <Delivery>Store Pickup</Delivery>
           </Order>
        </Orderhistory>
    </Book>
        .......
        .........
    </Book>
</BookCollection>

Ответы [ 2 ]

0 голосов
/ 26 августа 2018

Обычно, если вы хотите найти отдельные элементы, вы можете рассматривать это как проблему группировки, но вам нужно вывести только одно значение из каждой группы. В XSLT 1.0 вы будете использовать технику под названием Muenchian Grouping , что будет означать определение ключа следующим образом:

<xsl:key name="orders" match="Order" use="Delivery" />

Однако у вас есть дополнительная сложность получения последнего заказа по дате. Вероятно, самый простой вариант - создать переменную, содержащую только последние Order элементов для каждого OrderHistory

  <xsl:variable name="Orders">
    <xsl:for-each select="//Book[status = 'In Stock']/OrderHistory">
      <xsl:for-each select="Order">
        <xsl:sort select="date" order="descending" />
        <xsl:if test="position() = 1">
          <xsl:copy-of select="." />    
        </xsl:if>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:variable>

Однако вам нужно использовать функцию расширения, чтобы преобразовать этот «Фрагмент дерева результатов» в набор узлов, который затем вы можете использовать технику группирования Мюнцзяня. Больше всего похоже, что ваш процесс поддерживает EXSLT, что означает добавление этого пространства имен

xmlns:exsl="http://exslt.org/common"

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

<xsl:for-each select="exsl:node-set($Orders)/Order[generate-id() = generate-id(key('orders', Delivery)[1])]">

Попробуйте это XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                version="1.0">

  <xsl:output method="text" />

  <xsl:key name="orders" match="Order" use="Delivery" />

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

  <xsl:variable name="Orders">
    <xsl:for-each select="//Book[status = 'In Stock']/OrderHistory">
      <xsl:for-each select="Order">
        <xsl:sort select="date" order="descending" />
        <xsl:if test="position() = 1">
          <xsl:copy-of select="." />    
        </xsl:if>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:for-each select="exsl:node-set($Orders)/Order[generate-id() = generate-id(key('orders', Delivery)[1])]">
      <xsl:if test="position() > 1">, </xsl:if>
      <xsl:value-of select="Delivery" />     
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

См. Это в действии на http://xsltfiddle.liberty -development.net / 3NzcBtu / 2 (который использует Microsoft XSLTCompiledTransform, то есть XSLT 1.0).

В идеале, вам стоит подумать об обновлении до XSLT 3.0, чтобы не скучать с Мартином Хонненом ...

0 голосов
/ 25 августа 2018

Это можно сделать в чистом XPath 3, если поддерживается более высокая версия функции sort https://www.w3.org/TR/xpath-functions/#func-sort:

distinct-values( 
    BookCollection/Book[status = 'In Stock'] 
    ! 
    sort(
      OrderHistory/Order, 
      (), 
      function($order) { xs:date($order/date) }
    )[last()]/Delivery
)

Полная таблица стилей XSLT 3, которая будет работать сSaxon 9.8 EE или PE или любой другой процессор XSLT 3, поддерживающий функцию высшего порядка, будет иметь вид

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:template match="/">
        <xsl:value-of 
            select="distinct-values( 
                        BookCollection/Book[status = 'In Stock'] ! sort(OrderHistory/Order, (), function($order) { xs:date($order/date) })[last()]/Delivery
                    )"
            separator=", "/>
    </xsl:template>

</xsl:stylesheet>

В процессорах XSLT 3, таких как Saxon 9.8 HE, где не поддерживается вариант старшего порядка sortвам нужно делегировать сортировку вашей собственной функции:

<xsl:template match="/">
    <xsl:value-of 
        select="distinct-values( 
                    BookCollection/Book[status = 'In Stock'] ! mf:sort(OrderHistory/Order)[last()]/Delivery
                )"
        separator=", "/>
</xsl:template>

<xsl:function name="mf:sort" as="element(Order)*">
    <xsl:param name="orders" as="element(Order)*"/>
    <xsl:perform-sort select="$orders">
        <xsl:sort select="xs:date(date)"/>
    </xsl:perform-sort>
</xsl:function>

Пример на https://xsltfiddle.liberty -development.net / bdxtqs .

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