xsl-list
[Top] [All Lists]

Re: [xsl] Generating ID key values

2008-12-10 12:14:30
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_.-',''),'
')),' ','_')" />

If i devide this into much simpler expression, I will get :

<xsl:variable name = "tr1" select="translate(.,'
abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-','')"/>

<xsl:variable name = "tr2" select="translate(.,$tr1,'')"/>

<xsl:variable name="id" select="translate(normalize-space($tr2),' ','_')" />



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

Hmm. Nothing so far..

Your Id is translating the space into underscore. Fair enuff.

So really only the variable id seems to be doing something, and it
could be written as

<xsl:variable name="id" select="translate(normalize-space(.),' ','_')" />


NExt :

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

Can be :

<xsl:template match="node()|@*">
                <xsl:copy>
                        <xsl:apply-templates select="node()|@*" />
                        
                </xsl:copy>
        </xsl:template>
        
** Just a plain identity template

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


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


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
        <xsl:output method="xml" encoding="UTF-8" />
        <xsl:template match="node()|@*">
                <xsl:copy>
                        <xsl:apply-templates select="node()|@*"/>
                </xsl:copy>
        </xsl:template>
        <xsl:template match="document/*[not(@id)]">
                <xsl:call-template name="copy-elem-giving-id" />
        </xsl:template>
        <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>
</xsl:stylesheet>


2008/12/10 Trevor Nicholls <trevor(_at_)castingthevoid(_dot_)com>:> Hi

I have a stylesheet which is supposed to generate id attributes for any
occurrences of particular elements which do not already have one.
Unfortunately it has a couple of defects.

I am testing in XMLSpy but the stylesheet has to run with Xalan (because
it's built into a FrameMaker application). Hence we're restricted to XSL 1
solutions.

The stylesheet is here:
 =======================
 <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
 <xsl:output method="xml" encoding="UTF-8" />

 <!--
  - NOTE
  - This stylesheet generates ID attributes for certain elements that
should have them - but do not.
  -->

 <!-- set of existing ID values -->
 <xsl:key name="id" match="*[(_at_)id]" use="@id" />

 <!-- set of potential ID values -->
 <xsl:key name="noid" match="title[not(@id)]"
use="translate(normalize-space(translate(.,translate(.,'
abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-',''),'
')),' ','_')" />
 <xsl:key name="noid" match="question[not(@id)]"
use="translate(normalize-space(translate(.,translate(.,'
abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-',''),'
')),' ','_')" />
 <xsl:key name="noid" match="dt[not(@id)]"
use="translate(normalize-space(translate(.,translate(.,'
abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-',''),'
')),' ','_')" />
 <xsl:key name="noid" match="target[not(@id)]"
use="translate(normalize-space(translate(.,translate(.,'
abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-',''),'
')),' ','_')" />

 <!-- Fill in any missing IDs -->

 <xsl:template match="title | question | target | dt">
 <xsl:choose>
  <xsl:when test="@id">
   <xsl:call-template name="copy-elem" />
  </xsl:when>
  <xsl:otherwise>
   <xsl:call-template name="copy-elem-giving-id" />
  </xsl:otherwise>
 </xsl:choose>
 </xsl:template>

 <xsl:template name="copy-elem">
 <xsl:copy>
  <xsl:apply-templates select="@*" />
  <xsl:apply-templates />
 </xsl:copy>
 </xsl:template>

 <xsl:template name="copy-elem-giving-id">
 <xsl:variable name="id"
select="translate(normalize-space(translate(.,translate(.,'
abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_.-',''),'
')),' ','_')" />
 <xsl:variable name="thisnode" select="generate-id()" />
 <xsl:copy>
  <xsl:attribute name="id">
   <xsl:value-of select="$id" />
   <xsl:for-each select="key('noid',$id)">
    <xsl:if test="(key('id',$id)) or (position()!=1 and
generate-id(.)=$thisnode)">
     <xsl:text>-</xsl:text>
     <xsl:value-of select="position()" />
    </xsl:if>
   </xsl:for-each>
  </xsl:attribute>
  <xsl:apply-templates select="@*" />
  <xsl:apply-templates />
 </xsl:copy>
 </xsl:template>

 <!-- 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:stylesheet>
 =======================

Sample XML here:
 =======================
 <?xml version="1.0" encoding="UTF-8"?>
 <document>
 <title id="Intro">Intro</title>
 <title>Me</title>
 <title>Intro</title>
 <title>3 Point Turns</title>
 <title>Intro</title>
 </document>
 =======================

The output I get:
 =======================
 <?xml version="1.0" encoding="UTF-8"?>
 <document>
 <title id="Intro">Intro</title>
 <title id="Me">Me</title>
 <title id="Intro-1-2">Intro</title>
 <title id="3_Point_Turns">3 Point Turns</title>
 <title id="Intro-1-2">Intro</title>
 </document>
 =======================

The first problem is that instead of generating ID values of "Intro-1" and
"Intro-2", both titles are given the illegal duplicate ids "Intro-1-2",
which rather negates the point of using the keys in the first place. I
thought the <for-each><if /></for-each> construction would only match once,
but evidently not.

The second problem is that title beginning with a digit. While I can prefix
the id with an underscore when I create the attribute, I can't see how to do
the same modification when I construct the key. And if I don't construct the
"noid" key with the same prefix then I run the risk of failing to detect a
duplicate id when I create the attribute.

If you can see what I've done wrong I would be most grateful.

Cheers
Trevor



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--





-- 
Vasu Chakkera
Numerical Algorithms Group Ltd.
Oxford
www.vasucv.com

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>