XSL question

Discussion in 'XML' started by Rhino, Mar 9, 2012.

  1. Rhino

    Rhino Guest

    I'm pretty new to XSL. I've only played with it for a few hours very
    sporadically over the course of the last few years.

    I'm trying to write an XSL that will properly handle a repeating group in my
    data but it's not working for me.

    Basically, my data consists of 8 unique values, then a single value that can
    repeat anywhere from 0 to, say, 50 times. The XML is like this:
    <log>
    <record>
    <timestamp>timestamp-value</timestamp>
    <sequence>sequence-value</sequence>
    <logger>logger-value</logger>
    <level>level-value</level>
    <class>class-value</class>
    <method>method-value</method>
    <thread>thread-value</thread>
    <message>message-value</message>
    </record>
    <record>
    <timestamp>timestamp-value</timestamp>
    <sequence>sequence-value</sequence>
    <logger>logger-value</logger>
    <level>level-value</level>
    <class>class-value</class>
    <method>method-value</method>
    <thread>thread-value</thread>
    <message>message-value</message>
    <param>param1-value</param>
    <param>param2-value</param>
    <param>param3-value</param>
    <param>param4-value</param>
    <param>param5-value</param>
    </record>
    </log>

    Most records will be the like the first one and not have any occurrences of
    <param>. The remaining records will be like the second one and have several
    occurrences of <param>. 50 is not a hard limit on the number of occurrences
    of <param> - I'm not sure if there IS any hard limit - but it will be rare
    to have more than 50. But I want my code to work for any number of
    occurrences even if that is over 50. I'm just saying 50 to give you a sense
    of the number of occurrences you typically see.

    I want my XSL to create HTML with all records in a table that contains 9
    columns: timestamp, sequence, logger, level, class, method, thread, message,
    and param.

    For records that have no <param> tags, I want the first 8 columns of the
    table to contain the specific values of <timestamp> through <message> from
    that record. The 9th column of the table should simply be empty.

    For records that have <param> tags, I want one row in the table for each
    occurrence of a <param> tag in that record. In other words, for the second
    record described above, I want to generate five rows in the HTML table
    because there are five <param> values. The first of those rows should
    contain the <timestamp> thrrough <message> values in the first 8 columns and
    the first <param> value in the 9th column. The second row for that record
    should contain a single text string like "see above" that spans the first 8
    columns with the second <param> record in the 9th column. The third through
    nth rows should follow the same pattern as the second row except that they
    will show the next <param> value (the third <param> value on the 3rd row,
    the 4th <param> value on the 4th row etc.

    I've got everything except the repeating group (the <params>) working but
    I'm hitting a wall with that. Nothing I try works. It seems clear that I
    need a for-each loop on param but I'm not having any luck getting it to
    display the different param values.

    Can anyone show me the technique I need?

    --
    Rhino
    Rhino, Mar 9, 2012
    #1
    1. Advertising

  2. "Rhino" <> writes:

    > <log>

    [...]
    > <record>
    > <timestamp>timestamp-value</timestamp>
    > <sequence>sequence-value</sequence>
    > <logger>logger-value</logger>
    > <level>level-value</level>
    > <class>class-value</class>
    > <method>method-value</method>
    > <thread>thread-value</thread>
    > <message>message-value</message>
    > <param>param1-value</param>
    > <param>param2-value</param>
    > <param>param3-value</param>
    > </record>
    > </log>

    [...]
    > For records that have no <param> tags, I want the first 8 columns of
    > the table to contain the specific values of <timestamp> through
    > <message> from that record. The 9th column of the table should simply
    > be empty.
    >
    > For records that have <param> tags, I want one row in the table for
    > each occurrence of a <param> tag in that record. In other words, for
    > the second record described above, I want to generate five rows in the
    > HTML table because there are five <param> values. The first of those
    > rows should contain the <timestamp> thrrough <message> values in the
    > first 8 columns and the first <param> value in the 9th column. The
    > second [and subsequent] row for that record should contain a single
    > text string like "see above" that spans the first 8 columns with the
    > [n-th] <param> record in the 9th column.


    Something like this should work:

    <xsl:template match="record">
    <tr>
    <td><xsl:value-of select="timestamp"/></td>
    ...
    <td><xsl:value-of select="param[1]"/></td>
    </tr>
    <xsl:for-each select="param[position()&gt;1]">
    <tr>
    <td ...>see above</td>
    <td><xsl:value-of select="."/></td>
    </tr>
    </xsl:template>

    It relies on the fact the select="param[1]" will give nothing when
    there's no <param>. Likewise, the for-each won't do anything without at
    least two <param>. The function position() is provided by XPath.

    If you need more specific behavior, you can wrap the "optional" parts
    inside <xsl:if> or <xsl:choose>. Also, using templates to process
    <timestamp> etc. may be a good idea.

    -- Alain.
    Alain Ketterlin, Mar 9, 2012
    #2
    1. Advertising

  3. Rhino

    Rhino Guest

    "Alain Ketterlin" <-strasbg.fr> wrote in message
    news:-strasbg.fr...
    > "Rhino" <> writes:
    >
    >> <log>

    > [...]
    >> <record>
    >> <timestamp>timestamp-value</timestamp>
    >> <sequence>sequence-value</sequence>
    >> <logger>logger-value</logger>
    >> <level>level-value</level>
    >> <class>class-value</class>
    >> <method>method-value</method>
    >> <thread>thread-value</thread>
    >> <message>message-value</message>
    >> <param>param1-value</param>
    >> <param>param2-value</param>
    >> <param>param3-value</param>
    >> </record>
    >> </log>

    > [...]
    >> For records that have no <param> tags, I want the first 8 columns of
    >> the table to contain the specific values of <timestamp> through
    >> <message> from that record. The 9th column of the table should simply
    >> be empty.
    >>
    >> For records that have <param> tags, I want one row in the table for
    >> each occurrence of a <param> tag in that record. In other words, for
    >> the second record described above, I want to generate five rows in the
    >> HTML table because there are five <param> values. The first of those
    >> rows should contain the <timestamp> thrrough <message> values in the
    >> first 8 columns and the first <param> value in the 9th column. The
    >> second [and subsequent] row for that record should contain a single
    >> text string like "see above" that spans the first 8 columns with the
    >> [n-th] <param> record in the 9th column.

    >
    > Something like this should work:
    >
    > <xsl:template match="record">
    > <tr>
    > <td><xsl:value-of select="timestamp"/></td>
    > ...
    > <td><xsl:value-of select="param[1]"/></td>
    > </tr>
    > <xsl:for-each select="param[position()&gt;1]">
    > <tr>
    > <td ...>see above</td>
    > <td><xsl:value-of select="."/></td>
    > </tr>
    > </xsl:template>
    >
    > It relies on the fact the select="param[1]" will give nothing when
    > there's no <param>. Likewise, the for-each won't do anything without at
    > least two <param>. The function position() is provided by XPath.
    >
    > If you need more specific behavior, you can wrap the "optional" parts
    > inside <xsl:if> or <xsl:choose>. Also, using templates to process
    > <timestamp> etc. may be a good idea.
    >

    Actually, there are really two fields where I show timestamp, a date and a
    number of milliseconds, but I simplified it for my example. I'm already
    blending <date> and <millis> to create a real timestamp and it works fine.

    Tell me more about this "." construct.

    I took my existing code and simply replaced 'param' in my <xsl:value-of
    select="param"/> with <xsl:value-of select="."/> and starting getting my
    param values. I'm guessing that once you've referred to something like
    'param' in a for-each loop, you can't refer to it again the same way since
    it has already been consumed in some fashion but the '.' is sort of a
    synonym for the most recently referenced field so that you can get its value
    again. I've never seen that technique before though and I'm not sure what
    it's called so that I can Google it. If you could at least tell me its name,
    I'd be able to look for more information on how it is used. Or, of course,
    you can just tell me about it yourself ;-)

    In any case, I should now be able to modify my code so that it does what I
    want.

    I'll post back on this thread if I still have trouble and I'll check back to
    see what this "." technique is called....

    Thanks Alain!!

    --
    Rhino
    Rhino, Mar 9, 2012
    #3
  4. Rhino

    Simon Wright Guest

    "Rhino" <> writes:

    > Tell me more about this "." construct.
    >
    > I took my existing code and simply replaced 'param' in my
    > <xsl:value-of select="param"/> with <xsl:value-of select="."/> and
    > starting getting my param values. I'm guessing that once you've
    > referred to something like 'param' in a for-each loop, you can't refer
    > to it again the same way since it has already been consumed in some
    > fashion but the '.' is sort of a synonym for the most recently
    > referenced field so that you can get its value again. I've never seen
    > that technique before though and I'm not sure what it's called so that
    > I can Google it. If you could at least tell me its name, I'd be able
    > to look for more information on how it is used. Or, of course, you can
    > just tell me about it yourself ;-)


    The references I found by [1] include [2], which says, under "Selecting
    Nodes", "." "Selects the current node".

    During your for-each loop, on each pass "." refers to the current
    selected <param/> node.

    [1] google "xpath syntax"
    [2] http://www.w3schools.com/xpath/xpath_syntax.asp
    Simon Wright, Mar 10, 2012
    #4
  5. Simon Wright <> writes:

    > "Rhino" <> writes:
    >
    >> Tell me more about this "." construct.
    >>
    >> I took my existing code and simply replaced 'param' in my
    >> <xsl:value-of select="param"/> with <xsl:value-of select="."/> and
    >> starting getting my param values. I'm guessing that once you've
    >> referred to something like 'param' in a for-each loop, you can't refer
    >> to it again the same way since it has already been consumed in some
    >> fashion but the '.' is sort of a synonym for the most recently
    >> referenced field so that you can get its value again. I've never seen
    >> that technique before though and I'm not sure what it's called so that
    >> I can Google it. If you could at least tell me its name, I'd be able
    >> to look for more information on how it is used. Or, of course, you can
    >> just tell me about it yourself ;-)

    >
    > The references I found by [1] include [2], which says, under "Selecting
    > Nodes", "." "Selects the current node".
    >
    > During your for-each loop, on each pass "." refers to the current
    > selected <param/> node.
    >
    > [1] google "xpath syntax"
    > [2] http://www.w3schools.com/xpath/xpath_syntax.asp


    Exactly, at any time there is a "context node". This notion is used in
    XSLT, inherited from XPath. Actually, imho, W3C recommendations are the
    best description I know of XPath and XSLT. I think it's a good idea to
    read them at least once. I've never felt the need for any other
    documentation.

    http://www.w3.org/TR/xpath/
    http://www.w3.org/TR/xslt

    -- Alain.
    Alain Ketterlin, Mar 10, 2012
    #5
  6. Rhino

    Rhino Guest

    "Alain Ketterlin" <-strasbg.fr> wrote in message
    news:-strasbg.fr...
    > Simon Wright <> writes:
    >
    >> "Rhino" <> writes:
    >>
    >>> Tell me more about this "." construct.
    >>>
    >>> I took my existing code and simply replaced 'param' in my
    >>> <xsl:value-of select="param"/> with <xsl:value-of select="."/> and
    >>> starting getting my param values. I'm guessing that once you've
    >>> referred to something like 'param' in a for-each loop, you can't refer
    >>> to it again the same way since it has already been consumed in some
    >>> fashion but the '.' is sort of a synonym for the most recently
    >>> referenced field so that you can get its value again. I've never seen
    >>> that technique before though and I'm not sure what it's called so that
    >>> I can Google it. If you could at least tell me its name, I'd be able
    >>> to look for more information on how it is used. Or, of course, you can
    >>> just tell me about it yourself ;-)

    >>
    >> The references I found by [1] include [2], which says, under "Selecting
    >> Nodes", "." "Selects the current node".
    >>
    >> During your for-each loop, on each pass "." refers to the current
    >> selected <param/> node.
    >>
    >> [1] google "xpath syntax"
    >> [2] http://www.w3schools.com/xpath/xpath_syntax.asp

    >
    > Exactly, at any time there is a "context node". This notion is used in
    > XSLT, inherited from XPath. Actually, imho, W3C recommendations are the
    > best description I know of XPath and XSLT. I think it's a good idea to
    > read them at least once. I've never felt the need for any other
    > documentation.
    >
    > http://www.w3.org/TR/xpath/
    > http://www.w3.org/TR/xslt
    >


    Thank you both, Alain and Simon. The other question I was going to ask was
    about a good reference for XSLT and XPath and now you've answered that one
    too ;-)

    --
    Rhino
    Rhino, Mar 10, 2012
    #6
    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. Kevin Flood
    Replies:
    0
    Views:
    1,017
    Kevin Flood
    Sep 8, 2004
  2. Kevin Flood
    Replies:
    1
    Views:
    2,729
    Kevin Flood
    Sep 13, 2004
  3. Klaus Friese
    Replies:
    0
    Views:
    466
    Klaus Friese
    Nov 22, 2004
  4. Vijay singh
    Replies:
    1
    Views:
    434
    Martin Honnen
    Nov 4, 2004
  5. Replies:
    1
    Views:
    3,598
    A. Bolmarcich
    May 27, 2005
Loading...

Share This Page