RE: [xsl] Grouping into a table (for vertical alignment)

Subject: RE: [xsl] Grouping into a table (for vertical alignment)
From: "Daniel Joshua" <daniel.joshua@xxxxxxxxxxxx>
Date: Mon, 31 May 2004 11:43:41 +0800
>The trade-off is that walking the tree explicitly makes for more complex
>templates that work in what, to a newbie, is a highly unorthodox way

COMPLETED! Well just for the record, this is my "not so elegant" approach...

XML:

      <form>
        <name>loginForm</name>
        <action>submit.do</action>
        <method>post</method>
        <content>

          <text>
            <value>Please login here...</value>
          </text>

          <input>
            <name>userName</name>
            <label>User Name</label>
            <value></value>
          </input>

          <password>
            <name>password</name>
            <label>Password</label>
            <value></value>
          </password>
          <check>
            <name>stayLogin</name>
            <label>Stay Logged In</label>
            <value>true</value>
            <selected>true</selected>
          </check>
        </content>

      </form>


XSL:

  <xsl:template match="form">
    <form>
      <xsl:for-each select="name | action | method">
        <xsl:attribute name="{name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:for-each>

      <xsl:for-each select="content/*">
        <xsl:call-template name="line"/>
      </xsl:for-each>
    </form>
  </xsl:template>



  <xsl:template name="line" match="line">
    <xsl:choose>
      <xsl:when test="not(self::info or self::input or self::password or
self::memo or self::check or self::radio or self::combo)">
        <div class="line">
          <xsl:apply-templates select="."/>
        </div>
      </xsl:when>
      <xsl:when test="position() = 1 or not(preceding-sibling::info or
preceding-sibling::input or preceding-sibling::password or
preceding-sibling::memo or preceding-sibling::check or
preceding-sibling::radio or preceding-sibling::combo)">
        <table>
          <xsl:call-template name="lineInTable"/>
        </table>
      </xsl:when>
      <!-- Otherwise ignore -->
    </xsl:choose>
  </xsl:template>



  <xsl:template name="lineInTable">
    <tr>
      <xsl:apply-templates select="."/>
    </tr>

    <xsl:if test="following-sibling::info or following-sibling::input or
following-sibling::password or following-sibling::memo or
following-sibling::check or following-sibling::radio or
following-sibling::combo">
      <xsl:for-each select="following-sibling::node()[1]">
        <xsl:call-template name="lineInTable"/>
      </xsl:for-each>
    </xsl:if>
  </xsl:template>



  <xsl:template match="input">
    <xsl:apply-templates select="label"/>

    <td class="data">
      <xsl:element name="input">
        <xsl:attribute name="type">
          <xsl:text>text</xsl:text>
        </xsl:attribute>

        <xsl:for-each select="name | value">
          <xsl:attribute name="{name()}">
            <xsl:value-of select="."/>
          </xsl:attribute>
        </xsl:for-each>
      </xsl:element>
    </td>

    <xsl:apply-templates select="error"/>
  </xsl:template>



  <xsl:template match="label">
    <td class="label">
      <xsl:value-of select="."/>
      <xsl:text>: </xsl:text>
    </td>
  </xsl:template>



  <xsl:template match="error">
    <td class="error">
      <xsl:value-of select="."/>
    </td>
  </xsl:template>


Just a short comment, when using <xsl:call-template/> you cannot use a
"select="... really find that inconvienent.


Regards,
Daniel


-----Original Message-----
From: Wendell Piez [mailto:wapiez@xxxxxxxxxxxxxxxx]
Sent: Friday, 28 May, 2004 11:49 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: RE: [xsl] Grouping into a table (for vertical alignment)


Hi Daniel,

At 11:01 PM 5/27/2004, you wrote:
>Thanks Wendell... trying to figure it out now :p
>
> >Jeni works through one of these in entry 12 in the FAQ
> >page at http://www.dpawson.co.uk/xsl/sect2/N4486.html#d4726e727.
>
>Looking at it too, entry 12 actually allows me to handle my problem without
>a <xsl:key> ...

That's right: it's the other technique I mentioned: the "forward walk" or
"tree visitor". The key-based technique is just called "key-based
positional grouping" (since the nodes are grouped based on their relative
positions), although I like to call it "levitation".

The trade-off is that walking the tree explicitly makes for more complex
templates that work in what, to a newbie, is a highly unorthodox way, since
they use <xsl:apply-templates select="following-sibling::*[1]"
mode="walk"/> or the like. Using keys is a bit more elegant in the XSLT,
arguably, but lays the stress on that key declaration, whose XPath (as you
saw) can be ... "ornate", let's say.


>I got a question on entry 17:
>
> > <xsl:apply-templates mode="inGroup"
> >   select="following-sibling::*[position() &lt; $vGroupLength]"/>
>
>"vGroupLength" is the number of elements in the group.
>
>How does the "position()" work when used in the above manner,
>is it just the "context position" within (1) the node list of only
>"following-sibling"
>or (2) a node list of all siblings? I guess the first, but I just want to
>confirm.

You are correct, it's the node list of the following siblings. (The context
of a predicate is provided by the nodes and node-set the predicate operates
on.)

But you don't actually want this as it groups by a count -- first three
nodes, next three nodes, next three nodes -- or they could be in twelves or
nineteens: you get the idea. Whereas you need to group based on what nodes'
neighbors are (which is why your problem is a bit harder).

>I really appreciate all the help I am getting from this list. Thanks all.

Sure. You have a toughie, but it's been done. Digging in the archives for
"forward walk" or "tree visitor" would be a way to learn more about the
technique I did *not* explain (but which some say is easier: I dunno, if
you understand keys I think they're about the same).

Cheers,
Wendell


Current Thread