RE: [xsl] Generating ID key values

Subject: RE: [xsl] Generating ID key values
From: "Trevor Nicholls" <trevor@xxxxxxxxxxxxxxxxxx>
Date: Thu, 11 Dec 2008 22:59:24 +1300
Thank you for your reply, Vasu, and I will try the technique you suggested
instead of using keys.

> I see some issues in your stylesheet.
> 
> First: Your complex use of translate function
> 
> >  <xsl:variable name="id"
> > select="translate(normalize-space(translate(.,translate(.,'
> > abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-',''),'
> > ')),' ','_')" />
> 
 ..
> so You see, your first translate is not doing anything interesting. It
> is translateing your current text to blank space.
> your second translate is again not doing anything. It is translating
> space into space in your current. text

The translate(n-s(translate(.,translate(.,),),) construction actually
replaces any non NCName characters with spaces and then replaces any
sequence of spaces with a single underscore. It turns any arbitrary string
value into a valid NCName. Or it would if it had some way of adjusting the
result when the first character isn't an upper or lowercase letter, which is
a modification I can't see how to do in XSL 1. Maybe it is impossible after
all.

> Next: Your use of Keys and the for each:
> 
> Looking at what you really want, i think you are thinking in the
> direction of over engineering ..

You could well be right!

> I think what you want is below.. try it out and let me know if this is
> not what you want.

	<xsl:template name="copy-elem-giving-id">
		<xsl:variable name="id"
select="translate(normalize-space(.),' ','_')" />
		<xsl:copy>
			<xsl:attribute name="id">
				<xsl:value-of select="$id" />
				<xsl:variable name = "current-node-name"
select="name(.)"/>
				<xsl:variable name = "current-node-val"
select="$id"/>
				<xsl:variable name = "prefix"
select="count(preceding-sibling::*[not(@id)][(name() =
$current-node-name ) and  translate(normalize-space(.),' ','_') =
$current-node-val])+1"/>
				<xsl:if test = "string($prefix)">
					<xsl:text>-</xsl:text>
				</xsl:if>
				<xsl:value-of select = "$prefix"/>
			</xsl:attribute>
			<xsl:apply-templates select="@*" />
			<xsl:apply-templates />
		</xsl:copy>
	</xsl:template>

After restoring the nested translate expression in all its glory, this is
almost what I want, except that it assumes that the input document is
basically id-free. That is not correct: in the typical case Framemaker will
run the stylesheet every time a user saves a document and will fill in ids
for any new titles etc. that hadn't already been given them.

Cheers
Trevor

Current Thread