XSLT генерация uuid дублирует идентификатор для братьев и сестер - PullRequest
0 голосов
/ 06 июня 2018

Я использую xslt с Saxon HE, и я использовал метод, указанный здесь для генерации UUID, но я получаю одинаковый идентификатор для всех узлов одного уровня.

Что ясейчас:

<aaa uid="6EE63184-6950-11E8-9859-09173F13E4C5">
      <discount uid="6EE63183-6950-11E8-9859-09173F13E4C5">
         <li id="#d2e17">Dark Coffee<a href="#d2e20">USD 1.8</a>
         </li>
      </discount>
   </aaa>
   <aaa uid="6EE63184-6950-11E8-9859-09173F13E4C5">
      <discount uid="6EE63183-6950-11E8-9859-09173F13E4C5">
         <li id="#d2e32">Milk Shake<a href="#d2e35">USD 2.6</a>
         </li>
      </discount>
   </aaa>
   <aaa uid="6EE63184-6950-11E8-9859-09173F13E4C5">
      <discount uid="6EE63183-6950-11E8-9859-09173F13E4C5">
         <li id="#d2e47">Iced Coffee<a href="#d2e50">USD 1.5</a>
         </li>
      </discount>
   </aaa>
   <aaa uid="6EE63184-6950-11E8-9859-09173F13E4C5">
      <discount uid="6EE63183-6950-11E8-9859-09173F13E4C5">
         <li id="#d2e62">Bottled Water<a href="#d2e65">USD 2.5</a>
         </li>
      </discount>
   </aaa>

Я хочу, чтобы идентификаторы каждого тега aaa и тега discount были уникальными.какое изменение я должен сделать, чтобы добиться этого.

Ниже приведен xslt, который я использовал.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:m0="http://services.samples" xmlns:math="http://exslt.org/math" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:uuid="http://www.uuid.org" version="2.0" exclude-result-prefixes="m0 fn">
  <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
  <xsl:param name="drink_name"/>
  <xsl:template match="/">
     <Payment xmlns="http://ws.apache.org/ns/synapse">
        <xsl:for-each select="//Order/lunch">
           <xsl:element name="aaa">
              <xsl:attribute name="uid" select="uuid:get-uuid()"/>
              <discount>
                 <xsl:attribute name="uid" select="uuid:get-uuid()"/>
                 <li id="#{generate-id(drinkName)}">
                    <xsl:value-of select="drinkName"/>
                    <a href="#{generate-id(drinkPrice)}">
                       <xsl:value-of select="drinkPrice"/>
                    </a>
                 </li>
              </discount>
           </xsl:element>
        </xsl:for-each>
     </Payment>
  </xsl:template>
  <!-- Returns the UUID --><xsl:function name="uuid:get-uuid" as="xs:string*">
     <xsl:variable name="ts" select="uuid:ts-to-hex(uuid:generate-timestamp())"/>
     <xsl:value-of separator="-" select="             substring($ts, 8, 8),             substring($ts, 4, 4),             string-join((uuid:get-uuid-version(), substring($ts, 1, 3)), ''),             uuid:generate-clock-id(),             uuid:get-network-node()"/>
  </xsl:function>
  <!-- internal aux. fu with saxon, this creates a more-unique result with
generate-id then when just using a variable containing a node
--><xsl:function name="uuid:_get-node">
     <xsl:comment/>
  </xsl:function>
  <!-- generates some kind of unique id --><xsl:function name="uuid:get-id" as="xs:string">
     <xsl:sequence select="generate-id(uuid:_get-node())"/>
  </xsl:function>
  <!-- should return the next nr in sequence, but this can't be done
in xslt. Instead, it returns a guaranteed unique number
--><xsl:function name="uuid:next-nr" as="xs:integer">
     <xsl:variable name="node">
        <xsl:comment/>
     </xsl:variable>
     <xsl:sequence select="             xs:integer(replace(             generate-id($node), '\D', ''))"/>
  </xsl:function>
  <!-- internal fu for returning hex digits only --><xsl:function name="uuid:_hex-only" as="xs:string">
     <xsl:param name="string"/>
     <xsl:param name="count"/>
     <xsl:sequence select="             substring(replace(             $string, '[^0-9a-fA-F]', '')             , 1, $count)"/>
  </xsl:function>
  <!-- may as well be defined as returning the same seq each time --><xsl:variable name="_clock" select="uuid:get-id()"/>
  <xsl:function name="uuid:generate-clock-id" as="xs:string">
     <xsl:sequence select="uuid:_hex-only($_clock, 4)"/>
  </xsl:function>
  <!-- returns the network node, this one is 'random', but must
be the same within calls. The least-significant bit must be '1'
when it is not a real MAC address (in this case it is set to '1')
--><xsl:function name="uuid:get-network-node" as="xs:string">
     <xsl:sequence select="uuid:_hex-only('09-17-3F-13-E4-C5', 12)"/>
  </xsl:function>
  <!-- returns version, for timestamp uuids, this is "1" --><xsl:function name="uuid:get-uuid-version" as="xs:string">
     <xsl:sequence select="'1'"/>
  </xsl:function>
  <!-- Generates a timestamp of the amount of 100 nanosecond
intervals from 15 October 1582, in UTC time.
--><xsl:function name="uuid:generate-timestamp"><!-- date calculation automatically goes
    correct when you add the timezone information, in this
    case that is UTC.
    --><xsl:variable name="duration-from-1582" as="xs:dayTimeDuration">
        <xsl:sequence select="                 current-dateTime() -                 xs:dateTime('1582-10-15T00:00:00.000Z')"/>
     </xsl:variable>
     <xsl:variable name="random-offset" as="xs:integer">
        <xsl:sequence select="uuid:next-nr() mod 10000"/>
     </xsl:variable>
     <!-- do the math to get the 100 nano second intervals --><xsl:sequence select="             (days-from-duration($duration-from-1582) * 24 * 60 * 60 +             hours-from-duration($duration-from-1582) * 60 * 60 +             minutes-from-duration($duration-from-1582) * 60 +             seconds-from-duration($duration-from-1582)) * 1000             * 10000 + $random-offset"/>
  </xsl:function>
  <!-- simple non-generalized function to convert from timestamp to hex --><xsl:function name="uuid:ts-to-hex">
     <xsl:param name="dec-val"/>
     <xsl:value-of separator="" select="             for $i in 1 to 15             return (0 to 9, tokenize('A B C D E F', ' '))             [             $dec-val idiv             xs:integer(math:power(16, 15 - $i))             mod 16 + 1             ]"/>
  </xsl:function>
  <xsl:function name="math:power">
     <xsl:param name="base"/>
     <xsl:param name="power"/>
     <xsl:choose>
        <xsl:when test="$power lt 0 or contains(string($power), '.')">
           <xsl:message terminate="yes">

                The XSLT template math:power doesnt support negative or

                fractional arguments.

            </xsl:message>
           <xsl:text>NaN</xsl:text>
        </xsl:when>
        <xsl:otherwise>
           <xsl:call-template name="math:_power">
              <xsl:with-param name="base" select="$base"/>
              <xsl:with-param name="power" select="$power"/>
              <xsl:with-param name="result" select="1"/>
           </xsl:call-template>
        </xsl:otherwise>
     </xsl:choose>
  </xsl:function>
  <xsl:template name="math:_power">
     <xsl:param name="base"/>
     <xsl:param name="power"/>
     <xsl:param name="result"/>
     <xsl:choose>
        <xsl:when test="$power = 0">
           <xsl:value-of select="$result"/>
        </xsl:when>
        <xsl:otherwise>
           <xsl:call-template name="math:_power">
              <xsl:with-param name="base" select="$base"/>
              <xsl:with-param name="power" select="$power - 1"/>
              <xsl:with-param name="result" select="$result * $base"/>
           </xsl:call-template>
        </xsl:otherwise>
     </xsl:choose>
  </xsl:template>

1 Ответ

0 голосов
/ 06 июня 2018

(Предварительный неполный ответ, я вернусь к этому позже)

Вся эта таблица стилей очень сильно зависит от того, что когда функция создает новые узлы, она будет создавать разные узлы каждый раз, когда она вызываетсяи разные узлы будут иметь разные результаты для generate-id ().То есть, он опирается на тот факт, что вызов функции имеет незначительный побочный эффект, в результате чего можно вызывать одну и ту же функцию дважды и получать разные результаты.Это, конечно, отклонение от нормальных правил функционального программирования, и оно имеет неприятные последствия для оптимизации, потому что это означает, что вызовы функций не могут быть извлечены из циклов (если вы вызываете f (3) внутри цикла, вы можетене извлекайте этот вызов из цикла и делайте это только один раз).

Это подробно обсуждается в https://www.w3.org/TR/xslt-30/#function-determinism

XSLT 3.0 позволяет объявлять ожидания функции, используя атрибут new-Каждое время = «да».Предполагается, что это значение по умолчанию, но поскольку Saxon имеет историю попыток оптимизации при отсутствии строгих правил в этой области, он, вероятно, пытается самостоятельно оценить необходимость нескольких вызовов.

ИспользованиеОпция -explain при запуске таблицы стилей дает вам отзыв о том, какие оптимизации применяет Saxon.Вы также можете отключить выбранные оптимизации, например, -opt: -fl отключает подъем цикла и наложение функций.

Гораздо лучшим подходом ко всей проблеме будет использование нового fn: random-number-функция генератора ().К сожалению, здесь используются функции более высокого порядка, поэтому он недоступен в Saxon-HE.

...