XSL newbie here - please help!

Discussion in 'XML' started by gwoodhouse, Nov 12, 2007.

  1. gwoodhouse

    gwoodhouse Guest

    Hello everyone,

    Im brand new to XSL, im a java programmer by trade.

    Problem:
    What i need to do is put a variable in a for loop and extract an array
    or set of variables from it.

    Example:
    I have a variable coming to the xsl in the format "hum|bla|lit"

    I need to print this out as "Humanities, Black Studies, Literature"
    but i dont know how to recursivly get what i need.

    Current Code:
    So far i can get the first part of the variable understood and
    translated.

    <xsl:param name="subject"><xsl:value-of select="substring-
    before(.,'|')"/></xsl:param>
    <xsl:choose>
    <xsl:when test="$subject = 'wom'">
    <subfield code="a">Women's Studies</subfield>
    </xsl:when>
    etc etc etc

    Is there a function to split a variable so i can use a <xsl:for-each
    select="splittingfunction(.,"|")"> type line?

    Hope someone can help!

    Graeme
     
    gwoodhouse, Nov 12, 2007
    #1
    1. Advertisements

  2. gwoodhouse

    gwoodhouse Guest

    update of the code:

    <xsl:param name="subject"></xsl:param>
    <xsl:for-each select="tokenize(.,'|')">
    <xsl:choose>
    <xsl:when test="$subject = 'wom'">
    <xsl:param name="subject"><xsl:value-of
    select="$subject"/> | Women's Studies</xsl:param>
    </xsl:when>
    </xsl:choose>
    </xsl:for-each>
    <subfield code="a"><xsl:value-of select="$subject"/></
    subfield>

    This doesnt work but hopefully you'll understand what i mean.

    Thanks again for anyone who will help!

    Graeme
     
    gwoodhouse, Nov 12, 2007
    #2
    1. Advertisements

  3. Here is an XSLT 2.0 stylesheet that can be run with Saxon from
    <http://saxon.sourceforge.net/>:

    <xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:mp="http://example.com/data"
    version="2.0">

    <xsl:param name="topics" select="'hum|bla|lit'"/>

    <map xmlns="http://example.com/data">
    <item key="hum" value="Humanity"/>
    <item key="bla" value="Black Studies"/>
    <item key="lit" value="Literature"/>
    </map>

    <xsl:template name="main">
    <xsl:value-of select="for $t in tokenize($topics, '\|') return
    document('')/*/mp:map/mp:item[@key = $t]/@value"
    separator=", "/>
    </xsl:template>

    </xsl:stylesheet>
     
    Martin Honnen, Nov 12, 2007
    #3
  4. gwoodhouse

    Pavel Lepin Guest

    There are no 'for loops' in XSLT. xsl:for-each is not a
    loop, it's inline template application to a nodeset.

    To emulate stateful loops in XSLT you would usually employ
    recursive templates, using Divide & Conquer or tail
    recursion approaches where possible.
    A crude implementation would be:

    <c:cats xmlns:c="http://example.org/categories/">
    <c:cat cat="bla">
    <subfield code="a">Black Studies</subfield>
    </c:cat>
    <c:cat cat="hum">
    <subfield code="b">Humanities</subfield>
    </c:cat>
    <c:cat cat="lit">
    <subfield code="c">Literature</subfield>
    </c:cat>
    <c:cat cat="wom">
    <subfield code="d">Women's Studies</subfield>
    </c:cat>
    </c:cats>
    <xsl:template name="cats"
    xmlns:c="http://example.org/categories/">
    <xsl:param name="cats"/>
    <xsl:variable name="car"
    select="substring-before($cats,'|')"/>
    <xsl:variable name="cdr"
    select="substring-after($cats,'|')"/>
    <xsl:apply-templates
    select=
    "
    document('')/
    */c:cats/c:cat[@cat=$car or @cat=$cats]/node()
    "/>
    <xsl:if test="$cdr">
    <xsl:call-template name="cats">
    <xsl:with-param name="cats" select="$cdr"/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>
    <xsl:template match="@*|node()">
    <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>

    Don't use in production environments, it will choke on long
    category lists.
    In XSLT1, xsl:for-each can only be invoked on nodesets.
    XSLT2+XPath2 are a whole different story, but since you
    failed to mention the processor you're using, I will not
    elaborate any further.
     
    Pavel Lepin, Nov 12, 2007
    #4
  5. gwoodhouse

    gwoodhouse Guest

    Hi, thanks for your response =)

    I was wondering if you could explain these lines to me:
    <map xmlns="http://example.com/data"> (I tried google xsl, xml &
    map and all i get is references to cocoon 1 and cocoon2)
    <xsl:value-of select="for $t in tokenize($topics, '\|') return
    document('')/*/mp:map/mp:item[@key = $t]/@value" separator=", "/>

    What should the xmlns="" line read instead of example.com
    How does the second line here know which "map" to use (for example).

    Thanks again for your help martin, i can probably integrate this
    without any real understanding but, i would prefer to not have to
    bother you guys again :)

    Again i appologise if all this that im asking is ridiculously simple
    and im being dense.

    Graeme
     
    gwoodhouse, Nov 12, 2007
    #5
  6. gwoodhouse

    gwoodhouse Guest

    Thanks Pavel,

    I understood even less of your post than the last reply =)

    Do you have any advice for what subjects i should be researching in
    order to understand lines like
    Which to me looks scarily complicated.

    Also Pavel, nice quote :)

    Graeme
     
    gwoodhouse, Nov 12, 2007
    #6
  7. An XSLT stylesheet allows top-level elements that are not in the XSLT
    namespace, for instance to store some data. My suggestion makes use of
    that as that way you can easily "map" the short topic descriptions (e.g.
    hum or lit) to the complete descriptions (e.g Humanity or Literature).
    So the choosen elements names are arbitrary, you can choose any element
    name you want, I chose "map" and "item".
    The stylesheet can then access that data using
    document('')/*/mp:map/mp:item as it does below:
    You can choose any namespace URI you want or are allowed to use, you
    just need to put those elements in a different namespace than the XSLT
    namespace.
    document('') refers to the stylesheet document itself, document('')/* is
    the root element of the stylesheet, document('')/*/mp:map selects the
    map element(s) in the namespace mp is bound to (e.g.
    http://example.com/data).


    See <URL:http://www.w3.org/TR/xslt20/#user-defined-top-level>
     
    Martin Honnen, Nov 12, 2007
    #7
  8. gwoodhouse

    Pavel Lepin Guest

    It's an XPath1 expression (part of it, to be precise). Good
    working knowledge of XPath is required for efficient
    development of XSLT transformations. This is even more true
    in case of XSLT2+XPath2.

    Unfortunately, I'm unaware of any good, comprehensive
    introductory materials on the subject of XSLT and XPath.
    The resources I normally recommend to neophytes are XSLT
    FAQ, IBM's developerWorks section on XML and XSLT, Mozilla
    Developer Center's XSLT and XPath references, and W3C's
    corresponding recommendations, but none of those are
    precisely beginner-level.

    The best way to learn XSLT right now seems to be solving
    problems. Taking courses might work as well, but get expert
    opinion beforehand - a poorly designed course is likely to
    do more harm than good.

    Basically, it'll take a good bit of effort on your part to
    acquire firm understanding of XSLT basics, not in the least
    because XSLT is quite different from bread-and-butter
    general-purpose imperative languages. Familiarity with SQL
    helps a little. So does familiarity with
    Haskell/Scheme/Lisp/your-functional-language-of-choice or
    Prolog (in fact, this helps much more that familiarity with
    SQL).

    Note that both of solutions posted, Martin's and mine, use
    the same approach to generate the resulting tree. XSLT
    processors ignore children of xsl:stylesheet element in the
    namespaces they don't recognise (map element in Martin's
    stylesheet and c:cats element in my snippet). Furthermore,
    transformations can select nodesets from themselves, using
    the document('') function. This is to avoid writing an
    xsl:choose or anything along these lines.
     
    Pavel Lepin, Nov 12, 2007
    #8
  9. in xslt2 you'd do

    <xsl:variable name="names">
    <subject id="hum">Humanities</subject>
    <subject id="bla">Black Studies</subject>
    <subject id="lit">Literature</subject>
    </xsl:variable>

    <xsl:key name="names" match="subject" use="@id"/>

    <xsl:template match="zzz">
    <xsl:value-of
    select="tokenize(.,'|')/key('names',.,$names)"
    separator=", ">
    </xsl:template>

    In XSLT1 you'd write a recursive template splitting off one subject at a
    time using substring-before.

    David
     
    David Carlisle, Nov 12, 2007
    #9
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.