xsl-list
[Top] [All Lists]

RE: Grouping into a table (for vertical alignment)

2004-05-30 20:43:41
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(_at_)mulberrytech(_dot_)com]
Sent: Friday, 28 May, 2004 11:49 PM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
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