2011-11-14 102 views
9

如何使用純XSLT生成UUID?基本上尋找一種使用XSLT創建獨特序列的方法。序列可以是任何長度。XSLT生成UUID

我正在使用XSLT 2.0。

+0

可能重複[生成XSLT GUID(http://stackoverflow.com/questions/5494175/generate-guid-in-xslt) –

回答

1

由於XSLT是一種功能性的語言,生成隨機數不是語言的一部分。也就是說,有擴展包(EXSLT)和一些支持生成隨機數的處理器(Saxon)。如果你不能使用擴展或撒克遜,那麼我相信你運氣不好。

+2

撒克遜如何支持生成隨機數? – Ayyoudy

+0

撒克遜隨附內置的EXSLT隨機模塊。請參閱http://saxonica.com/documentation/extensions/intro.xml –

+0

謝謝。太糟糕了,內置的EXSLT模塊不適用於Saxon HE(家庭版)。 – Ayyoudy

10

這是good example。基本上你設置指向的java UUID類的擴展,然後引用它在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

對不起,不明確。我之前看過這個例子,但它需要在純XSLT中完成。沒有Java。 – Ayyoudy

+1

'xsl:value-of'不能是'xsl:stylesheet'的子... – Abel

+0

我已經upvoted,因爲這對我有效。然而,值得注意的是,像這樣的自反java調用也不適用於Saxon HE許可證(儘管其他人已經指出,編寫自己的函數來解決這個問題或多或少是個問題)。 –

2

對於XSLT生成隨機數,見Casting the Dice with FXSL: Random Number Generation Functions in XSLT。它使用的唯一擴展函數是node-set(),這在XSLT 2.0中不再需要。

此外,如果要求只是ID是唯一的(不一定是隨機的),請看how to generate unique string。例如,如果要爲輸入XML文檔的每個元素生成一個UUID,則可以使用輸入文檔的URL和每個元素的唯一字符串的組合來生成輸入文檔的URL。

4

您可以使用XSLT片段爲這個(來源: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 ... thank你:) – Ayyoudy

+0

感謝分享。源代碼(public-contracts-ontology)是一個無效的鏈接:( –

+0

)這個代碼可以得到4個不同的UUID「」: 23CD00A6-8952-11E6-2114-09173F13E4C5 23CD00A5-8952-11E6-2114-09173F13E4C5 23CD00A3-8952-11E6-2114-09173F13E4C5 23CD00A4-8952-11E6-2114-09173F13E4C5 –

0

如果使用.NetXslCompiledTransform改變你的XSL,可以將EnableScripts屬性設置爲true,然後使用如下代碼如下:

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

注意:我在上面給出了這個自定義功能的名稱/前綴csharp;但你可以隨心所欲地調用它。請參閱https://stackoverflow.com/a/1873265/361842。下面

完全XSLT文件提供一些額外的背景:

<?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>