RE: [xsl] Assigning unique id to new node using generate-id()

Subject: RE: [xsl] Assigning unique id to new node using generate-id()
From: "Michael Kay" <mhk@xxxxxxxxx>
Date: Thu, 14 Aug 2003 09:18:33 +0100
If your code works, then it's working by luck.

If you define a key

  <xsl:key name="k" match="credential" use="@id"/>

then it's very easy to add a test

  <xsl:if test="not(key('k', generate-id())">

to check that the id you are generating is not the same as the id of an
element that you are copying. You can then try other IDs until you find
one that is indeed unique:

<xsl:template name="make-id">
  <xsl:param name="try"/>
  <xsl:choose>
    <xsl:when test="not(key('k', $try))">
      <xsl:value-of select="$try"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="make-id">
        <xsl:with-param name="try" select="concat($try, 'ï')"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The letter ï ('i' with two dots, in case the email service loses it) is
chosen here as a character that can appear in an ID attribute but that
cannot appear in the result of generate-id() (which is always ASCII). In
your initial call of this template, supply generate-id() as the first
try. If this is "G123", then this value will be used unless there is an
@id with value "G123"; if this happens the next try will be "G123ï", and
so on.

Michael Kay
      

> -----Original Message-----
> From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx 
> [mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx] On Behalf Of 
> kyle.himmerick@xxxxxxxxxxxxxx
> Sent: 13 August 2003 19:41
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: Re: [xsl] Assigning unique id to new node using generate-id()
> 
> 
> Thank you for you reply.
> 
> I would like to keep the existing ID's the same.  As they are 
> referenced from other nodes (a credential is referenced from 
> 0 or more services).
> 
> My current workaround seems to be working although I'm not 
> 100% convinced that it will always create a unique id.
> 
> After new node is created without an id, I transform the 
> document again with. 
> This is run against the result of the first transform which 
> adds the new credential without and id.
> 
> <xsl:for-each select="credential">
> 	<xsl:choose>
> 		<xsl:when test="@id">
> 			<xsl:copy-of select="."/>		
> 		
> 		</xsl:when>
> 		<xsl:otherwise>
> 			<credential>
> 				<xsl:attribute name="id">
> 					<xsl:value-of 
> select="generate-id()"/>
> 				</xsl:attribute>
> 				<xsl:copy-of select="username"/>
> 				<xsl:copy-of select="password"/>
> 				<xsl:copy-of select="description"/>
> 				<xsl:copy-of select="lastModified"/>
> 			</credential>
> 		</xsl:otherwise>
> 	</xsl:choose>
> </xsl:for-each>
> 
> As I said, this seems to work.
> 
> What other methods would you recommend for generating a 
> unique id?  It is possible, albeit unlikely, that the a 
> profile may contain identical credential nodes (where 
> username, password, description and lastModified are identical).
> 
> Thanks,
> Kyle
> 
> 
> On Wed, 13 Aug 2003 13:10 , Wendell Piez 
> <wapiez@xxxxxxxxxxxxxxxx> sent:
> 
> >Hi Kyle,
> >
> >At 12:11 PM 8/13/2003, you wrote:
> >>I'd like this stylesheet to copy all existing credential nodes and 
> >>create
> >>a new
> >>node assigning a unique id
> >
> >It's a reasonable requirement.
> >
> >>  with generate-id().
> >
> >Why? as opposed to by some other means?
> >
> >>   It appears as if the generate-id
> >>call doesn't observe existing id's in the current/copied credential
> >>nodes.  So I
> >>end up with duplicate (illegal) id's.  I've tried passing 
> several context 
> >>nodes
> >>to the generate-id() function, but with no luck.
> >>
> >>Sample XSL:
> >>         
> >>                 
> >>                         
> >>                                 
> >>                         
> >>                         
> >>                                 
> >>                                         
> >> select="generate-id()"/>
> >>                                 
> >>                                 
> >> select="$username"/>
> >>                                 
> >> select="$password"/>
> >>                                 
> >> select="$description"/>
> >>                                 
> >>select="java:getCurrentDateTimeGMT($dateHelper)"/>
> >>                         
> >>                 
> >>         
> >>
> >>My current workaround is to transform twice.  The first 
> transformation 
> >>appends the new credential node.  The second transformation 
> assigns an 
> >>id (using
> >>generate-id()) to any credential nodes without an id 
> (probably only newly
> >>created).  Seems like I should be able to do it all in one 
> transform.
> >
> >The root of your problem is in thinking that generate-id() assigns 
> >(unique)
> >IDs to new nodes, when it doesn't; it merely assigns (or 
> retrieves) an ID 
> >for a node in the source. The generated value has nothing to 
> do with any 
> >value in the source, even if on an attribute called "id". It 
> needs only to 
> >be unique to the node provided as argument to the function, 
> or to the 
> >context node (in your case, "/profile") if none is given.
> >
> >Given the code you have provided, in which you create only one
> >and assign it an ID unique to the  you have matched, there is a 
> >good chance that the observed duplication is actually 
> faithful to the 
> >input, in which IDs are not unique (check to verify whether 
> this is not the 
> >case). To guarantee uniqueness, reassign an ID to every 
> credential. Since 
> >you are also creating new credentials, a second pass (your current 
> >workaround) is an appropriate place to do this. If you have 
> a requirement 
> >to preserve IDs where they exist, this is a more complex problem and 
> >generate-id() is probably not part of the solution at all.
> >
> >Cheers,
> >Wendell
> >
> >
> >
> >=============================================================
> =========
> >Wendell Piez                           
> wapiez@xxxxxxxxxxxxxxxx','','','')">wapiez@xxxxxxxxxxxxxxxx
> >Mulberry Technologies, Inc.                
> http://www.mulberrytech.com
> >17 West Jefferson Street         
>            Direct Phone: 301/315-9635
> >Suite 207                                          Phone: 
> 301/315-9631
> >Rockville, MD  20850                                 Fax: 
> 301/315-8285
> >-------------------------------------------------------------
> ---------
> >   Mulberry Technologies: A Consultancy Specializing in SGML and XML 
> >=============================================================
> =========
> >
> >
> > XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> >
> >
> 
> 
> 
> 
> 
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> 


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread