Сортировка в XSLT v1.0 для получения наибольшего значения, новый вопрос - PullRequest
2 голосов
/ 28 ноября 2008

У меня есть XML-документ с несколькими элементами <person>, каждый из которых содержит <name> человека и несколько элементов <preferred-number> внутри элемента группировки <preferred-numbers>.

Я уже обнаружил, что для получения наибольшего <preferred-number> мне нужно сделать <xsl:apply-template> с <xsl:sort> внутри него и затем взять первый элемент, так как XSLT v1.0 не имеет fn:max().

Но я предполагаю, что это дало бы мне наибольшую ценность из всех. Итак, как я могу организовать таблицу стилей для извлечения <name> каждого человека с их наибольшим <preferred-number>?

Ответы [ 2 ]

2 голосов
/ 29 ноября 2008

Можно использовать «максимальный» шаблон, как указано в FXSL - Библиотека функционального программирования для XSLT . FXSL полностью написан на самом XSLT.

Вот пример использования шаблона «максимум»:

При этом преобразование:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:maximum-own-compare="maximum-own-compare"
xmlns:Mycompare="Mycompare"
exclude-result-prefixes="xsl f Mycompare"
>
   <xsl:import href="maximum.xsl"/>

   <xsl:output method="text"/>

   <!-- This transformation must be applied to:
        numList.xml 
    -->

     <Mycompare:Mycompare/>

    <xsl:template match="/">
      <xsl:variable name="vCMPFun" 
           select="document('')/*/Mycompare:*[1]"/>

      <xsl:call-template name="maximum">
        <xsl:with-param name="pList" select="/*/*"/>
        <xsl:with-param name="pCMPFun" select="$vCMPFun"/> 

      </xsl:call-template>
    </xsl:template>

    <xsl:template name="MyIsGreater" mode="f:FXSL"
      match="Mycompare:*">
         <xsl:param name="arg1"/>
         <xsl:param name="arg2"/>

         <xsl:choose>
          <xsl:when test="$arg1 > $arg2">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
         </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

применяется к этому документу XML:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

желаемый результат получен.

10

Обратите внимание, что я могу передать любую необходимую операцию "сравнения" в качестве параметра! Например, если моя операция сравнения возвращает 1 всякий раз, когда $ arg1 <$ arg2, то приведенное выше преобразование выдаст «01» - минимум всех значений. </p>

Теперь я покажу два решения исходной задачи.

Solution1 (используя «максимальный» шаблон FXSL):

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:Mycompare="Mycompare"
exclude-result-prefixes="xsl f Mycompare"
>
   <xsl:import href="maximum.xsl"/>

   <xsl:output omit-xml-declaration="yes" indent="yes"/>

     <Mycompare:Mycompare/>

      <xsl:variable name="vCMPFun"
           select="document('')/*/Mycompare:*[1]"/>

    <xsl:template match="/">
      <persons>
       <xsl:apply-templates select="*/*"/>
      </persons>
    </xsl:template>
    <xsl:template match="person">
     <person>
      <xsl:call-template name="maximum">
        <xsl:with-param name="pList" select="*/*"/>
        <xsl:with-param name="pCMPFun" select="$vCMPFun"/> 

      </xsl:call-template>
     </person>
    </xsl:template>

    <xsl:template name="MyIsGreater" mode="f:FXSL"
      match="Mycompare:*">
         <xsl:param name="arg1"/>
         <xsl:param name="arg2"/>

         <xsl:choose>
          <xsl:when test="$arg1 > $arg2">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
         </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

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

<t>
    <person>
        <preferred-number>
            <preferred-number>8</preferred-number>
            <preferred-number>10</preferred-number>
            <preferred-number>4</preferred-number>
            <preferred-number>12</preferred-number></preferred-number>
    </person>
    <person>
        <preferred-number>
            <preferred-number>2</preferred-number>
            <preferred-number>11</preferred-number>
            <preferred-number>15</preferred-number>
            <preferred-number>6</preferred-number></preferred-number>
    </person>
    <person>
        <preferred-number>
            <preferred-number>10</preferred-number>
            <preferred-number>44</preferred-number>
            <preferred-number>9</preferred-number></preferred-number>
    </person>
</t>

желаемый результат выдается:

<persons>
   <person>
      <preferred-number>12</preferred-number>
   </person>
   <person>
      <preferred-number>15</preferred-number>
   </person>
   <person>
      <preferred-number>44</preferred-number>
   </person>
</persons>

Solution2 (используя шаблон, написанный от руки):

При этом преобразование:

<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="/">
     <persons>
       <xsl:apply-templates select="*/*"/>
     </persons>
    </xsl:template>

    <xsl:template match="person">
     <person>
      <xsl:call-template name="maximum">
        <xsl:with-param name="pList" select="*/*"/>
      </xsl:call-template>
     </person>
    </xsl:template>

    <xsl:template name="maximum">
      <xsl:param name="pList"/>

      <xsl:choose>
       <xsl:when test="not($pList)">
        -99999999999999999999
       </xsl:when>
       <xsl:otherwise>
         <xsl:variable name="vLen" select="count($pList)"/>

         <xsl:choose>
          <xsl:when test="$vLen = 1">
           <xsl:value-of select="$pList[1]"/>
          </xsl:when>
          <xsl:otherwise>
           <xsl:variable name="vHalf"
             select="floor($vLen div 2)"/>

           <xsl:variable name="vMax1">
             <xsl:call-template name="maximum">
              <xsl:with-param name="pList"
                select="$pList[not(position() > $vHalf)]"/>
             </xsl:call-template>
           </xsl:variable>

           <xsl:variable name="vMax2">
             <xsl:call-template name="maximum">
              <xsl:with-param name="pList"
                select="$pList[position() > $vHalf]"/>
             </xsl:call-template>
           </xsl:variable>

           <xsl:value-of
            select="$vMax1*($vMax1 > $vMax2)
                   +
                    $vMax2*($vMax2 >= $vMax1)
            "/>
          </xsl:otherwise>
         </xsl:choose>
       </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

применяется к тому же XML-документу, снова получается правильный результат:

<persons>
   <person>12</person>
   <person>15</person>
   <person>44</person>
</persons>
0 голосов
/ 28 ноября 2008

Когда дело доходит до сортировки вещей в XSLT 1.0, я должен использовать слегка окольный подход, насколько я помню. Если вы еще этого не сделали, вам нужно заглянуть в мюнхенскую группу , чтобы дать вам несколько идей для начала.

Я нашел этот сайт , чтобы быть очень полезным ресурсом.

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