XSLT associative arrays

Discussion in 'XML' started by Eric Anderson, Oct 8, 2004.

  1. Got a quick question trying to figure out the XSLT way of implementing
    the functionality of associative arrays. Basically want I want to do is
    the following:

    <xsl:template name="foo">
    <xsl:param name="bar"/>
    <xsl:choose>
    <xsl:when test="$bar = 'a'">b</xsl:when>
    <xsl:when test="$bar = 'c'">d</xsl:when>
    <xsl:when test="$bar = 'e'">f</xsl:when>
    ....
    ...
    ..
    ..
    <xsl:choose>
    <xsl:template>

    Now imagine bar is could be one of a hundred values. Also imagine that
    we are not just printing out a simple value. Imagine we have some
    complex code that just uses that simple value. We don't want to
    continually repeat that complex code all down the page. So what I would
    really like is something like:

    <xsl:variable name="a" select="'b'"/>
    <xsl:variable name="c" select="'d'"/>
    <xsl:variable name="e" select="'f'"/>
    <xsl:variable name="g" select="'h'"/>
    .....
    ....
    ...


    <xsl:template name="foo">
    <xsl:param name="bar">
    <xsl:value-of select="${$bar}"/>
    </xsl:template>

    What I am trying to indicate here is that $bar is resolved to 'a', 'c',
    'e', 'g' or any other sort of value. Then that value is used as a
    variable to resolve to 'b', 'd', 'f', 'h' or any other sort of
    associated variable. Now obviously my made up syntax doesn't work. My
    question is what is the proper way to do this in XSLT? Basically how do
    you create and use an associative array in XSLT? This would all be
    equivalent to the following in Perl.

    baz{a} = 'b';
    baz{c} = 'd';
    baz{e} = 'f';
    baz{g} = 'h';
    .....
    ....
    ...

    sub foo {
    my ( $bar ) = @_;
    print $baz{$bar};
    }

    Any suggestions?

    Eric
    Eric Anderson, Oct 8, 2004
    #1
    1. Advertising

  2. Eric Anderson wrote:
    > Got a quick question trying to figure out the XSLT way of implementing
    > the functionality of associative arrays. Basically want I want to do is
    > the following:
    >
    > <xsl:template name="foo">
    > <xsl:param name="bar"/>
    > <xsl:choose>
    > <xsl:when test="$bar = 'a'">b</xsl:when>
    > <xsl:when test="$bar = 'c'">d</xsl:when>
    > <xsl:when test="$bar = 'e'">f</xsl:when>
    > ....
    > ...
    > ..
    > ..
    > <xsl:choose>
    > <xsl:template>
    >
    > Now imagine bar is could be one of a hundred values. Also imagine that
    > we are not just printing out a simple value. Imagine we have some
    > complex code that just uses that simple value. We don't want to
    > continually repeat that complex code all down the page. So what I would
    > really like is something like:
    >
    > <xsl:variable name="a" select="'b'"/>
    > <xsl:variable name="c" select="'d'"/>
    > <xsl:variable name="e" select="'f'"/>
    > <xsl:variable name="g" select="'h'"/>
    > ....
    > ...
    > ..
    >
    >
    > <xsl:template name="foo">
    > <xsl:param name="bar">
    > <xsl:value-of select="${$bar}"/>
    > </xsl:template>
    >
    > What I am trying to indicate here is that $bar is resolved to 'a', 'c',
    > 'e', 'g' or any other sort of value. Then that value is used as a
    > variable to resolve to 'b', 'd', 'f', 'h' or any other sort of
    > associated variable. Now obviously my made up syntax doesn't work. My
    > question is what is the proper way to do this in XSLT? Basically how do
    > you create and use an associative array in XSLT? This would all be
    > equivalent to the following in Perl.
    >
    > baz{a} = 'b';
    > baz{c} = 'd';
    > baz{e} = 'f';
    > baz{g} = 'h';
    > ....
    > ...
    > ..
    >
    > sub foo {
    > my ( $bar ) = @_;
    > print $baz{$bar};
    > }
    >
    > Any suggestions?
    >
    > Eric
    >


    hi,

    hereafter is a sample code that should help you ; in this case, the key
    is the position (an integer), but you can also easily match the
    structure with something else, a string in your case

    document('') is used to load the stylesheet itself

    you MUST involve a prefix when you define your own structure

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="*** Processing dates ***">

    <date:month-names>
    <date:month short="jan">january</date:month>
    <date:month short="feb">february</date:month>
    <date:month short="mar">march</date:month>
    <date:month short="apr">april</date:month>
    <date:month short="may">may</date:month>
    <date:month short="jun">june</date:month>
    <date:month short="jul">jully</date:month>
    <date:month short="aug">august</date:month>
    <date:month short="sep">september</date:month>
    <date:month short="oct">october</date:month>
    <date:month short="nov">november</date:month>
    <date:month short="dec">december</date:month>
    </date:month-names>

    <xsl:template name="date:month-name">
    <!--returns the name of the month from its number-->
    <xsl:param name="month" select="0"/>
    <xsl:value-of
    select="document('')/*/date:month-names/date:month[$month]"/>
    </xsl:template>
    </xsl:stylesheet>

    --
    Cordialement,

    ///
    (. .)
    -----ooO--(_)--Ooo-----
    | Philippe Poulard |
    -----------------------
    Philippe Poulard, Oct 8, 2004
    #2
    1. Advertising

  3. Eric Anderson

    Joris Gillis Guest

    On Fri, 08 Oct 2004 11:59:44 -0400, Eric Anderson <> wrote:

    > Got a quick question trying to figure out the XSLT way of implementing
    > the functionality of associative arrays. Basically want I want to do is
    > the following:
    >
    > <xsl:variable name="a" select="'b'"/>
    > <xsl:variable name="c" select="'d'"/>
    > <xsl:variable name="e" select="'f'"/>
    > <xsl:variable name="g" select="'h'"/>
    > ....
    > ...
    > ..
    >
    >
    > <xsl:template name="foo">
    > <xsl:param name="bar">
    > <xsl:value-of select="${$bar}"/>
    > </xsl:template>



    Hi,

    I'd suggest you use xml nodes to store the 'array'.

    The following tree could represent the array:

    <xsl:variable name="array">
    <i ref="a">b</i>
    <i ref="c">d</i>
    <i ref="e">f</i>
    <i ref="g">h</i>
    </xsl:variable>

    The code to access it would be something like:

    <xsl:template name="foo">
    <xsl:param name="bar">
    <xsl:value-of select="$array[@ref=$bar]"/>
    </xsl:template>

    In stead of using node-tree variables you could also store this array in a
    seperate xml file
    suppose the file's name is 'array.xml', template foo would be like:

    <xsl:template name="foo">
    <xsl:param name="bar">
    <xsl:value-of select="document('array.xml')//i[@ref=$bar]"/>
    </xsl:template>



    regards,

    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    Ceterum censeo XML omnibus esse utendum
    Joris Gillis, Oct 8, 2004
    #3
  4. Joris Gillis wrote:
    > I'd suggest you use xml nodes to store the 'array'.


    What you suggested is exactly what I was looking for. You are an immense
    help. Thank you so much.

    Eric
    Eric Anderson, Oct 8, 2004
    #4
  5. Philippe Poulard wrote:
    > hereafter is a sample code that should help you


    What you and Joris Gills sent is exactly what I was looking for. I knew
    there had to be a good way to do what I wanted. It is funny your example
    deals with calendars. That is actually what this is all related to. Once
    again thanks for your help.

    Eric
    Eric Anderson, Oct 8, 2004
    #5
  6. I guess you want an XML document rather than an array.
    Given
    a file.xml with
    <x>
    <foo x="a">b</foo>
    <foo x="c">d</foo>
    ....

    then your

    <xsl:param name="bar">
    <xsl:value-of select="${$bar}"/>


    is, I believe,

    select="document('file.xml')/x/foo[@x=$bar]"

    David
    David Carlisle, Oct 8, 2004
    #6
  7. Joris Gillis wrote:
    > <xsl:template name="foo">
    > <xsl:param name="bar">
    > <xsl:value-of select="$array[@ref=$bar]"/>
    > </xsl:template>


    I am trying a variation on what both you and Philippe Poulard suggested.
    Basically what I am trying to do is store some calendar information as
    a variable that I can use in some of my XSLT templates. I have created
    the following variable:

    <xsl:variable name="calendar_info">
    <cal:month name="January">
    <cal:abbrev>Jan</cal:abbrev>
    <cal:prev>December</cal:prev>
    <cal:next>Feburary</cal:next>
    </cal:month>
    <cal:month name="Feburary">
    <cal:abbrev>Feb</cal:abbrev>
    <cal:prev>January</cal:prev>
    <cal:next>March</cal:next>
    </cal:month>
    <cal:month name="March">
    <cal:abbrev>Mar</cal:abbrev>
    <cal:prev>Feburary</cal:prev>
    <cal:next>April</cal:next>
    </cal:month>
    <cal:month name="April">
    <cal:abbrev>Apr</cal:abbrev>
    <cal:prev>March</cal:prev>
    <cal:next>May</cal:next>
    </cal:month>
    <cal:month name="May">
    <cal:abbrev>May</cal:abbrev>
    <cal:prev>April</cal:prev>
    <cal:next>June</cal:next>
    </cal:month>
    <cal:month name="June">
    <cal:abbrev>Jun</cal:abbrev>
    <cal:prev>May</cal:prev>
    <cal:next>July</cal:next>
    </cal:month>
    <cal:month name="July">
    <cal:abbrev>Jul</cal:abbrev>
    <cal:prev>June</cal:prev>
    <cal:next>August</cal:next>
    </cal:month>
    <cal:month name="August">
    <cal:abbrev>Aug</cal:abbrev>
    <cal:prev>July</cal:prev>
    <cal:next>September</cal:next>
    </cal:month>
    <cal:month name="September">
    <cal:abbrev>Sep</cal:abbrev>
    <cal:prev>August</cal:prev>
    <cal:next>October</cal:next>
    </cal:month>
    <cal:month name="October">
    <cal:abbrev>Oct</cal:abbrev>
    <cal:prev>September</cal:prev>
    <cal:next>November</cal:next>
    </cal:month>
    <cal:month name="November">
    <cal:abbrev>Nov</cal:abbrev>
    <cal:prev>October</cal:prev>
    <cal:next>December</cal:next>
    </cal:month>
    <cal:month name="December">
    <cal:abbrev>Dec</cal:abbrev>
    <cal:prev>November</cal:prev>
    <cal:next>January</cal:next>
    </cal:month>
    </xsl:variable>

    My main goal right now is to find out the next month so that I can
    iterate through a list of months. I figured while I was at it I would
    put other information in the structure which might be useful for the
    future. This variable is defined in a separate xsl file so that many xsl
    templates can use the information. I now am trying to use the
    information. So if I do

    <xsl:value-of select="$calendar_info/cal:month[@name='January']/cal:abbrev/>

    I get an error. I want this to return the abbreviated version of January
    ('Jan'). If I do

    <xsl:value-of select="$calendar_info"/>

    then I get all the content of the variable but how do I select the nodes
    in the variable. Any help is greatly appreciated.

    Thanks,

    Eric
    Eric Anderson, Oct 9, 2004
    #7
  8. Eric Anderson

    Joris Gillis Guest

    > So if I do
    >
    > <xsl:value-of
    > select="$calendar_info/cal:month[@name='January']/cal:abbrev/>
    >
    > I get an error. I want this to return the abbreviated version of January
    > ('Jan').


    Hi,

    To deal with the error:
    First, look if the typo in your mail appears in your xsl.
    (the select attribute should have an ending quote)
    Secondly, make sure you defined the 'cal' namespace in both xsl files.
    Finally, make sure you're using xsl 1.1 and a processor that supports it.
    (
    If your processor does not support version 1.1, you could still use:
    <xsl:value-of
    select="document('templates.xsl')//cal:month[@name='January']/cal:abbrev"/>
    )

    <xsl:value-of
    select="$calendar_info/cal:month[@name='January']/cal:abbrev"/>
    returns 'Jan'. Tested with saxon.


    regards,

    --
    Joris Gillis (http://www.ticalc.org/cgi-bin/acct-view.cgi?userid=38041)
    Ceterum censeo XML omnibus esse utendum
    Joris Gillis, Oct 9, 2004
    #8
  9. Eric Anderson <> writes:

    > Philippe Poulard wrote:
    > > hereafter is a sample code that should help you

    >
    > What you and Joris Gills sent is exactly what I was looking for. I
    > knew there had to be a good way to do what I wanted. It is funny your
    > example deals with calendars. That is actually what this is all
    > related to. Once again thanks for your help.


    Just a follow-up to the previous excellent suggestions. Experience
    has shown me that combining this with the the xsl:key and key()
    functionality is an order-of-magnitude faster on my applications. The
    simple XPath lookup is neater but no faster than a sequence of if
    statements (sequential search). I believe most, if not all, processors
    use hashes to implement the key() stuff.

    So if performance matters to you have a look into it.

    Here's a snippet from a (non calendar-related) example where I use it.

    ----
    <arr:books>
    <arr:book n="01" name="Genesis" osisID="Gen"/>
    <arr:book n="02" name="Exodus" osisID="Exod"/>
    <arr:book n="03" name="Leviticus" osisID="Lev"/>
    <!-- snip -->
    <arr:book n="66" name="Revelation" osisID="Rev"/>
    </arr:books>

    <!-- Using keys is an efficient way to access the book data -->
    <xsl:key name="num2osis" match="arr:book" use="@n"/>
    <xsl:key name="esv2osis" match="arr:book" use="@name"/>

    <!-- snip -->

    <!-- Example of accessing the "array" -->
    <xsl:variable name="book-name">
    <xsl:for-each select="document('')"> <!-- changes the context node -->
    <xsl:value-of select="key('num2osis',substring($esv-id,1,2))/@osisID"/>
    </xsl:for-each>
    </xsl:variable>

    ----

    --
    Ben Edgington
    Mail to the address above is discarded.
    Mail to ben at that address might be read.
    http://www.edginet.org/
    Ben Edgington, Oct 11, 2004
    #9
  10. Joris Gillis wrote:
    > Finally, make sure you're using xsl 1.1 and a processor that supports it.


    Ah! This was the problem. I am having the xslt processor in Mozilla
    process it instead of processing server-side. Evidently mozilla only
    supports 1.0 since 1.1 seems to be just a working draft and seems to
    have been dropped in favor of the upcoming 2.0.

    > (
    > If your processor does not support version 1.1, you could still use:
    > <xsl:value-of
    > select="document('templates.xsl')//cal:month[@name='January']/cal:abbrev"/>
    > )


    I ended up doing the document() method and have it working great now.
    Thanks for your help.

    Eric
    Eric Anderson, Oct 12, 2004
    #10
    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. Replies:
    4
    Views:
    7,404
    Mark Bole
    Mar 4, 2005
  2. Audun Røe

    XSLT "associative" arrays

    Audun Røe, Apr 14, 2004, in forum: XML
    Replies:
    10
    Views:
    1,113
    Mike Conmackie
    Apr 26, 2004
  3. lordy
    Replies:
    4
    Views:
    11,474
    Piotr Kobzda
    Jul 20, 2006
  4. desktop
    Replies:
    5
    Views:
    383
    James Kanze
    Jun 26, 2007
  5. shashi
    Replies:
    17
    Views:
    412
    Guest
    Apr 13, 2006
Loading...

Share This Page