XSLT 1.0: Iteration over a sequence

G

Giacomo

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

Joe Kesselman

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

Joe Kesselman

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)" />
 
G

Giacomo

Joe said:
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.
 
G

Giacomo

Joe said:
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.
 
J

Joe Kesselman

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

Giacomo

Joe said:
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.
 
D

Dimitre Novatchev

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top