2011-11-14 41 views
9

¿Cómo puedo generar un UUID con XSLT pura? Básicamente buscando una forma de crear secuencias únicas con XSLT. La secuencia puede ser de cualquier longitud.XSLT generar UUID

estoy usando XSLT 2.0.

+0

posible duplicado de [Generar GUID en XSLT] (http://stackoverflow.com/questions/5494175/generate-guid-in-xslt) –

Respuesta

1

Desde XSLT es un lenguaje funcional, la generación de números aleatorios no es parte de la lengua. Dicho esto, hay paquetes de extensión (EXSLT) y algunos procesadores (sajones) que admiten la generación de números aleatorios. Si no puede usar extensiones o Saxon, entonces creo que no tiene suerte.

+2

¿Cómo apoya Saxon la generación de números aleatorios? – Ayyoudy

+0

Saxon viene con el módulo aleatorio EXSLT incorporado. Ver http://saxonica.com/documentation/extensions/intro.xml –

+0

Gracias. Lástima que los módulos integrados EXSLT no están disponibles para Saxon HE (Home Edition). – Ayyoudy

10

Aquí hay una good example. Básicamente se configura una extensión que apunta a la clase UUID java, y luego hacer referencia a ella en el XSL:

<xsl:stylesheet version="2.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:uuid="java:java.util.UUID"> 
<xsl:template match="/"> 
    <xsl:variable name="uid" select="uuid:randomUUID()"/> 
    <xsl:value-of select="$uid"/> 
</xsl:template> 
+0

Lo sentimos, por no aclarar. Vi ese ejemplo antes, pero tiene que hacerse en XSLT puro. Sin Java – Ayyoudy

+1

'xsl: value-of' no puede ser hijo de' xsl: stylesheet' ... – Abel

+0

He votado como esto funcionó para mí. Sin embargo, vale la pena señalar que las llamadas reflexivas de java como esta tampoco están disponibles para las licencias de Saxon HE (aunque, como otros han señalado, es más o menos un problema resuelto escribir sus propias funciones para hacerlo). –

2

para generar números aleatorios en XSLT, consulte Casting the Dice with FXSL: Random Number Generation Functions in XSLT. La única función de extensión que utiliza es node-set(), que ya no es necesaria en XSLT 2.0.

Además, si el requisito es sólo que los identificadores sean únicos (no necesariamente al azar), echar un vistazo a how to generate unique string. Por ejemplo, si está generando un UUID para cada elemento de un documento XML de entrada, puede usar una combinación de la URL del documento de entrada y <xsl:number> para generar una cadena única para cada elemento.

4

Puede utilizar fragmento de XSLT para esto (fuente: http://code.google.com/p/public-contracts-ontology/source/browse/transformers/GB-notices/uuid.xslt?r=66e1d39a1c140079a86d219df5b3e031007cc957):

<xsl:stylesheet xmlns:uuid="http://www.uuid.org" xmlns:math="http://exslt.org/math" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

     <xsl:template match="/"> 
       <xsl:value-of select=" 
concat('First random ID:', uuid:get-id()), 
concat('Base timestamp: ', uuid:generate-timestamp()), 
concat('Clock id: ' ,uuid:generate-clock-id()), 
concat('Network node: ' ,uuid:get-network-node()), 
concat('UUID Version: ' ,uuid:get-uuid-version()), 
concat('Generated UUID: ' ,uuid:get-uuid()), 
concat('Generated UUID: ' ,uuid:get-uuid()), 
concat('Generated UUID: ' ,uuid:get-uuid()), 
concat('Generated UUID: ' ,uuid:get-uuid()) 
" separator="&#10;"/> 
     </xsl:template> 

    <!-- 
Functions in the uuid: namespace are used to calculate a UUID 
The method used is a derived timestamp method, which is explained 
here: http://www.famkruithof.net/guid-uuid-timebased.html 
and here: http://www.ietf.org/rfc/rfc4122.txt 
--> 
    <!-- 
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 doesn't 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> 
</xsl:stylesheet>:choose> 
    </xsl:template> 
</xsl:stylesheet> 
+0

upvoted ... gracias usted :) – Ayyoudy

+0

Gracias por compartir. La fuente (contratos públicos-ontología) es un enlace inactivo :( –

+0

Es posible obtener 4 UUID diferentes con este código "": 23CD00A6-8952-11E6-2114-09173F13E4C5 23CD00A5-8952-11E6-2114-09173F13E4C5 23CD00A3-8952-11E6-2114-09173F13E4C5 23CD00A4-8952-11E6-2114-09173F13E4C5 –

0

Si se utiliza .Net 's XslCompiledTransform para transformar su XSL, puede establecer la propiedad EnableScripts a true, a continuación, utilizar el código tal como por debajo :

<msxsl:script language="C#" implements-prefix="csharp"> 
    <![CDATA[ 
    public static string NewGuid() 
    { 
     return Guid.NewGuid().ToString(); 
    } 
    ]]> 
</msxsl:script> 

NB: me he dado esta funcionalidad personalizada el nombre/prefijo csharp en el anterior; pero puedes llamarlo como quieras

Para más información sobre las secuencias de comandos que permite, ver https://stackoverflow.com/a/1873265/361842.

archivo XSLT completa más abajo para darle un poco de contexto adicional:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:csharp="urn:JohnLBevan/NewGuid" 
    exclude-result-prefixes="xsl msxsl csharp" 
> 

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

    <xsl:template match="//*/text()"> 
     <!-- replaces all text nodes from input document with GUIDs --> 
     <xsl:value-of select="csharp:NewGuid()"/> 
    </xsl:template> 

    <msxsl:script language="C#" implements-prefix="csharp"> 
     <![CDATA[ 
     public static string NewGuid() 
     { 
      return Guid.NewGuid().ToString(); 
     } 
     ]]> 
    </msxsl:script> 

</xsl:stylesheet>