XSLT 1.0: Iteration over a sequence

Discussion in 'XML' started by Giacomo, Aug 11, 2006.

  1. Giacomo

    Giacomo Guest

    I need to iterate over the letters of the alphabet; the only solution I
    found using only XSLT 1.0 is:

    <xsl:key name="hostnames" match="host/name" use="substring(., 1, 1)" />

    <my:alphabet xmlns:my="my.com">
    <l>a</l><l>b</l><l>c</l><l>d</l><l>e</l><l>f</l><l>g</l><l>h</l><l>i</l><l>j</l><l>k</l><l>l</l><l>m</l><l>n</l><l>o</l><l>p</l><l>q</l><l>r</l><l>s</l><l>t</l><l>u</l><l>v</l><l>w</l><l>x</l><l>y</l><l>z</l>
    </my:alphabet>

    <xsl:variable name="root" select="/"/>
    <xsl:variable name="alphabet" select="document('')/*/my:alphabet/l"/>


    <xsl:template name="summary">
    ...
    <!--this works, but I don't need it -->
    <xsl:for-each select="$root">
    <xsl:apply-templates select="key('hostnames','b')" />
    </xsl:for-each>

    <!--this doesn't work and I need it!!! -->
    <xsl:for-each select="$alphabet">
    <xsl:variable name="letter" select="." />
    <xsl:for-each select="$root">
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames','a')" />
    </xsl:for-each>
    </xsl:for-each>

    </xsl:template>


    What can I do?

    Thanks,
    Giacomo.
    Giacomo, Aug 11, 2006
    #1
    1. Advertising

  2. I get the output
    <?xml version="1.0" encoding="UTF-8"?>
    ...

    a: b: c: d: e: f: g: h: i: j: k: l: m: n: o: p: q: r: s: t: u: v: w:
    x: y: z:

    (modulo the tabs, of course.) So your iteration is working fine. Of
    course I don't have your input file (or the other parts of your
    stylesheet), so it isn't surprising the key lookup of 'b' isn't finding
    anything.

    Working copy follows.


    <xsl:stylesheet version="1.0" xmlns:my="my.com"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:key name="hostnames" match="host/name" use="substring(., 1, 1)" />
    <my:alphabet xmlns:my="my.com">
    <l>a</l><l>b</l><l>c</l><l>d</l><l>e</l><l>f</l><l>g</l><l>h</l><l>i</l><l>j</l><l>k</l><l>l</l><l>m</l><l>n</l><l>o</l><l>p</l><l>q</l><l>r</l><l>s</l><l>t</l><l>u</l><l>v</l><l>w</l><l>x</l><l>y</l><l>z</l>
    </my:alphabet>

    <xsl:variable name="root" select="/"/>
    <xsl:variable name="alphabet" select="document('')/*/my:alphabet/l"/>

    <xsl:template match="/">
    <xsl:call-template name="summary"/>
    </xsl:template>

    <xsl:template name="summary">
    ...
    <!--this works, but I don't need it -->
    <xsl:for-each select="$root">
    <xsl:apply-templates select="key('hostnames','b')" />
    </xsl:for-each>

    <!--this works just fine... -->
    <xsl:for-each select="$alphabet">
    <xsl:variable name="letter" select="." />
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames','a')" />
    </xsl:for-each>

    </xsl:template>

    </xsl:stylesheet>



    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
    Joe Kesselman, Aug 12, 2006
    #2
    1. Advertising

  3. One thought: When you wrote
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames','a')" />

    I suspect you meant something more like:
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames',$letter)" />



    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
    Joe Kesselman, Aug 12, 2006
    #3
  4. Giacomo

    Giacomo Guest

    Joe Kesselman wrote:
    > I get the output
    > <?xml version="1.0" encoding="UTF-8"?>
    > ...
    >
    > a: b: c: d: e: f: g: h: i: j: k: l: m: n: o: p: q: r: s: t: u: v:
    > w: x: y: z:
    >
    > (modulo the tabs, of course.) So your iteration is working fine. Of
    > course I don't have your input file (or the other parts of your
    > stylesheet), so it isn't surprising the key lookup of 'b' isn't finding
    > anything.


    It doesn't work even if you have an input file!

    The problem is that this works:

    <xsl:for-each select="$root">
    <xsl:apply-templates select="key('hostnames',$letter)" />
    </xsl:for-each>


    but when I put that code inside another for-each it doesn't work anymore:

    <xsl:for-each select="$alphabet">
    <xsl:variable name="letter" select="." />
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames',$letter)" />
    </xsl:for-each>


    If you want to try you can use as input:

    <hosts>
    <host>
    <name>aasd/name>
    </host>
    <host>
    <name>azsddz</name>
    </host>
    <host>
    <name>bfsds</name>
    </host>
    <host>
    <name>casd</name>
    </host>
    ....
    </hosts>


    Thanks,
    Giacomo.
    Giacomo, Aug 12, 2006
    #4
  5. Giacomo

    Giacomo Guest

    Joe Kesselman wrote:
    > I suspect you meant something more like:
    > <xsl:value-of select="$letter" />: <xsl:apply-templates
    > select="key('hostnames',$letter)" />


    Of course, I was just trying to analyze the problem without causing
    other possible problems :)

    Giacomo.
    Giacomo, Aug 12, 2006
    #5
  6. The following is producing expected output for me. I suspect your
    problem isn't the scan, but what you're doing with the values you've
    retrieved from the key. Either that, or you've got a broken XSLT
    implementation...?


    Stylesheet:

    <xsl:stylesheet version="1.0" xmlns:my="my.com"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:key name="hostnames" match="host/name" use="substring(., 1, 1)" />
    <my:alphabet xmlns:my="my.com">
    <l>a</l><l>b</l><l>c</l><l>d</l><l>e</l><l>f</l><l>g</l><l>h</l><l>i</l><l>j</l><l>k</l><l>l</l><l>m</l><l>n</l><l>o</l><l>p</l><l>q</l><l>r</l><l>s</l><l>t</l><l>u</l><l>v</l><l>w</l><l>x</l><l>y</l><l>z</l>
    </my:alphabet>

    <xsl:variable name="root" select="/"/>
    <xsl:variable name="alphabet" select="document('')/*/my:alphabet/l"/>

    <xsl:template match="/">
    <xsl:call-template name="summary"/>
    </xsl:template>


    <xsl:template name="summary">
    <SingleTest>
    <xsl:for-each select="$root">
    <xsl:apply-templates select="key('hostnames','b')" />
    </xsl:for-each>
    </SingleTest>

    <MultipleTest>
    <xsl:for-each select="$alphabet">
    <xsl:variable name="letter" select="." />
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames',$letter)" />
    </xsl:for-each>
    </MultipleTest>
    </xsl:template>

    <xsl:template match="@*|node()">
    <xsl:copy>
    <xsl:apply-templates/>
    </xsl:copy>
    <xsl:text>
    </xsl:text>
    </xsl:template>


    </xsl:stylesheet>


    Output:

    <?xml version="1.0" encoding="UTF-8"?>
    <SingleTest xmlns:my="my.com"><name>bfsds
    </name>
    </SingleTest><MultipleTest xmlns:my="my.com">a: <name>aasd
    </name>
    <name>azsddz
    </name>
    b: <name>bfsds
    </name>
    c: <name>casd
    </name>
    d: e: f: g: h: i: j: k: l: m: n: o: p: q: r: s: t: u: v: w: x: y: z:
    </MultipleTest>

    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
    Joe Kesselman, Aug 12, 2006
    #6
  7. Giacomo

    Giacomo Guest

    Joe Kesselman wrote:
    > The following is producing expected output for me. I suspect your
    > problem isn't the scan, but what you're doing with the values you've
    > retrieved from the key. Either that, or you've got a broken XSLT
    > implementation...?

    I tried exactly your code and I obtain:

    <SingleTest xmlns:my="my.com"><name>bfsds
    </name>
    </SingleTest><MultipleTest xmlns:my="my.com">a: b: c: d: e: f: g: h: i:
    j: k: l: m: n: o: p: q: r: s: t: u: v: w: x: y: z: </MultipleTest>

    so I think it's an awful and old implementation of XSLT. From phpinfo:

    XSL enabled
    libxslt Version 1.0.30
    libxslt compiled against libxml Version 2.5.7
    EXSLT enabled
    libexslt Version 1.0.30

    but unfortunately I can't change it because it's on a university server
    and laboratory technicians don't want to update it...


    Thank you very much for you patience,
    Giacomo.
    Giacomo, Aug 12, 2006
    #7
  8. > but when I put that code inside another for-each it doesn't work anymore:
    >
    > <xsl:for-each select="$alphabet">
    > <xsl:variable name="letter" select="." />
    > <xsl:value-of select="$letter" />: <xsl:apply-templates
    > select="key('hostnames',$letter)" />
    > </xsl:for-each>



    The xsl:for-each instruction changes thje current document to the one, which
    contains the node-set defined as the value of the variable $alphabet.

    So, the current document is changed to the stylesheet document. It, most
    probably, is not the input xml document and doesn't conatain any host/name
    nodes.

    This is why the key() function in the above code will be evaluated to the
    empty node-set.

    Most probably (guessing without having your source xml document), the
    following will do what you intended:

    <xsl:for-each select="$alphabet">
    <xsl:variable name="letter" select="." />
    <xsl:for-each select="$root">
    <xsl:value-of select="$letter" />: <xsl:apply-templates
    select="key('hostnames',$letter)" />
    </xsl:for-each>
    </xsl:for-each>


    Hope this helped.

    Cheers,
    Dimitre Novatchev


    "Giacomo" <> wrote in message news:ebk69v$p46$...
    > Joe Kesselman wrote:
    >> I get the output
    >> <?xml version="1.0" encoding="UTF-8"?>
    >> ...
    >>
    >> a: b: c: d: e: f: g: h: i: j: k: l: m: n: o: p: q: r: s: t: u: v:
    >> w: x: y: z:
    >>
    >> (modulo the tabs, of course.) So your iteration is working fine. Of
    >> course I don't have your input file (or the other parts of your
    >> stylesheet), so it isn't surprising the key lookup of 'b' isn't finding
    >> anything.

    >
    > It doesn't work even if you have an input file!
    >
    > The problem is that this works:
    >
    > <xsl:for-each select="$root">
    > <xsl:apply-templates select="key('hostnames',$letter)" />
    > </xsl:for-each>
    >
    >
    > but when I put that code inside another for-each it doesn't work anymore:
    >
    > <xsl:for-each select="$alphabet">
    > <xsl:variable name="letter" select="." />
    > <xsl:value-of select="$letter" />: <xsl:apply-templates
    > select="key('hostnames',$letter)" />
    > </xsl:for-each>
    >
    >
    > If you want to try you can use as input:
    >
    > <hosts>
    > <host>
    > <name>aasd/name>
    > </host>
    > <host>
    > <name>azsddz</name>
    > </host>
    > <host>
    > <name>bfsds</name>
    > </host>
    > <host>
    > <name>casd</name>
    > </host>
    > ...
    > </hosts>
    >
    >
    > Thanks,
    > Giacomo.
    Dimitre Novatchev, Aug 13, 2006
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. M.Kamermans

    XSLT - maintaining iteration count

    M.Kamermans, Jan 29, 2005, in forum: XML
    Replies:
    6
    Views:
    8,240
    Dimitre Novatchev
    Jan 30, 2005
  2. python
    Replies:
    4
    Views:
    8,509
    Serge Orlov
    May 29, 2006
  3. Replies:
    10
    Views:
    1,197
    Gabriel Genellina
    Jun 10, 2007
  4. stef mientki
    Replies:
    13
    Views:
    618
    stef mientki
    Oct 20, 2007
  5. Rudi
    Replies:
    5
    Views:
    4,970
Loading...

Share This Page