XSLT generate UUID
6 réponses
puisque XSLT est un langage fonctionnel, générer des nombres aléatoires ne fait pas partie du langage. Cela dit, il existe des paquets d'extension (EXSLT) et certains processeurs (Saxon) qui prennent en charge la génération de nombres aléatoires. Si vous ne pouvez pas utiliser les extensions ou Saxon, alors je crois que vous n'avez pas de chance.
Voici un bon exemple. En gros, vous configurez une extension qui pointe vers la classe java UUID, puis vous la référencez dans le 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>
Vous pouvez utiliser XSLT snippet pour cela (source: 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=" "/>
</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 < 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>
jetez un coup d'oeil à une autre question Generate GUID in XSLT.
Probablement l'article vous aidera - il défini des fonctions XSLT pour générer GUID
Pour la génération de nombres aléatoires en XSLT, voir lancer les dés avec FXSL: fonctions de génération de nombres aléatoires en XSLT. La seule fonction d'extension utilisée est node-set (), qui n'est plus nécessaire dans XSLT 2.0.
aussi, si l'exigence est seulement que les ID soient uniques (pas nécessairement aléatoires), jetez un coup d'oeil à comment générer une chaîne unique. Par exemple, si vous générez un UUID pour chaque élément D'un document XML d'entrée, vous pouvez utiliser un combinaison de L'URL du document d'entrée, et <xsl:number>
pour générer une chaîne unique pour chaque élément.
Si vous utilisez .Net
XslCompiledTransform
pour transformer votre XSL, vous pouvez définir le EnableScripts
propriété true
, puis utilisez le code suivant:
<msxsl:script language="C#" implements-prefix="csharp">
<![CDATA[
public static string NewGuid()
{
return Guid.NewGuid().ToString();
}
]]>
</msxsl:script>
NB: J'ai donné à cette fonctionnalité personnalisée le nom / préfixe csharp
dans ce qui précède; mais vous pouvez l'appeler ce que vous voulez.
pour en savoir plus sur l'activation des scripts, voir https://stackoverflow.com/a/1873265/361842.
Plein de fichier XSLT ci-dessous à donner un peu de contexte:
<?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>