|
Subject: RE: [xsl] generating ID strings that are both readable and unique From: "Michael Kay" <mike@xxxxxxxxxxxx> Date: Tue, 14 Oct 2008 10:44:03 +0100 |
Quite hard to do in "pure" XSLT 1.0 without a node-set() extension, because
I think any solution that is moderately efficient is going to involve some
temporary data.
I would create a temporary document containing all distinct ids/titles like
this
<xsl:variable name="allids">
<xsl:for-each-group select="//section" group-by="(@original-id,
@title)[1]">
<id id="{current-grouping-key()}" count="count(current-group())"/>
</xsl:for-each-group>
</xsl:variable>
Here's a function to get a unique ID derived from a string s and a sequence
number, that is guaranteed unique:
<xsl:function name="f:unique" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="gid" as="xs:string"/>
<xsl:choose>
<xsl:when test="exists($allids/id[@id=$input]">
<xsl:sequence select="f:unique(concat($input, '_', $gid))"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$input"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
And then when processing an individual section,
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:when test="$allids/id[@id=current()/@title]/@count eq 1">
<xsl:value-of select="@title"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="f:unique(@title, generate-id())"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
Instead of using generate-id() for disambiguation, you could use the result
of xsl:number level="any". This would mean that if there are two sections
titled "Introduction", one gets the id "Introduction_1", the other
"Introduction_2". In the rare event that "Introduction_1" is already in use,
you would get "Introduction_1_1" etc.
Michael Kay
http://www.saxonica.com/
> -----Original Message-----
> From: Trevor Nicholls [mailto:trevor@xxxxxxxxxxxxxxxxxx]
> Sent: 14 October 2008 07:26
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] generating ID strings that are both readable and unique
>
> Hi
>
> In this particular application we have a set of XML documents
> which are divided into nested sections; each section may
> (down the track) give rise to a url. Currently that url is
> generated by <xsl:number level="multiple"> but this produces
> urls that change frequently. Some sections have been given an
> ID attribute by the process which originally created the
> documents, but most have not.
> Additionally, all sections must have exactly one title child,
> along with their other content.
>
> The requirement is to process an XML file and generate an ID
> attribute for sections which lack them - deriving the ID
> value from the title so that the url is comprehensible.
> Providing we ignore the problem cases, this is a trivial exercise:
>
> ----
>
> <xsl:variable name="upchars"
> select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> <xsl:variable
> name="lochars" select="'abcdefghijklmnopqrstuvwxyz'" />
>
> <!-- catchall -->
> <xsl:template match="*">
> <xsl:copy>
> <xsl:apply-templates select="@*" />
> <xsl:apply-templates />
> </xsl:copy>
> </xsl:template>
>
> <xsl:template match="@*">
> <xsl:copy-of select="." />
> </xsl:template>
>
> <xsl:template match="section[@id]">
> <xsl:copy>
> <xsl:apply-templates select="@*" />
> <xsl:apply-templates />
> </xsl:copy>
> </xsl:template>
>
> <xsl:template match="section">
> <xsl:copy>
> <xsl:attribute name="id">
> <xsl:apply-templates select="title" mode="id" />
> </xsl:attribute>
> <xsl:apply-templates select="@*" />
> <xsl:apply-templates />
> </xsl:copy>
> </xsl:template>
>
> <xsl:template match="title" mode="id">
> <xsl:value-of select="translate(translate(.,'
> ','_'),$upchars,$lochars)"
> />
> </xsl:template>
>
> ----
>
> The problem cases are
> (a) duplicate titles (after the translations) which would
> lead to duplicate IDs, and
> (b) existing IDs which might also duplicate a title.
>
> If there were no IDs in the document to begin with, I think I
> could have solved the first problem by using a key. But the
> second problem complicates it, and I haven't got enough
> experience with keys to figure out how to adjust the "id"
> mode title template to take both issues into account.
>
> Can anyone offer some helpful advice here?
> XSL 1.0 is preferred, although I would be interested to see
> how XSL2 might handle this problem too.
>
> Thanks
> Trevor
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [xsl] generating ID strings tha, David Carlisle | Thread | [xsl] EXSLT and XSLT 2.0, Jesper Tverskov |
| Re: [xsl] generating ID strings tha, David Carlisle | Date | Re: [xsl] using position() inside M, G. Ken Holman |
| Month |