| Subject: Re: [xsl] Get Position of Node in Ancestor Context From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx> Date: Mon, 10 Mar 2003 17:33:58 +0000 | 
Hi Ted,
> Answered my own question, but would still be interested in knowing
> what others think of this solution...
>
> <xsl:template match="input|select|textarea">
>      <xsl:copy>
>          <xsl:for-each select="@*">
>              <xsl:copy />
>          </xsl:for-each>
>          <xsl:variable name="currElemId" select="@id" />
>          <xsl:attribute name="tabindex"></xsl:attribute>
>          <xsl:for-each  
> select="ancestor::form//select|ancestor::form//input|ancestor::form// 
> textarea">
>              <xsl:if test="not(@type = 'hidden') or @type = 'submit'">
>                  <xsl:if test="@id = $currElemId">
>                      <xsl:attribute name="tabindex"><xsl:value-of  
> select="position()" /></xsl:attribute>
>                  </xsl:if>
>              </xsl:if>
>          </xsl:for-each>
>          <xsl:apply-templates />
>      </xsl:copy>
> </xsl:template>
I think that you'd probably be better off using <xsl:number> here.
Try:
<xsl:template match="input | select | textarea">
  ...
  <xsl:attribute name="tabindex">
    <xsl:number from="form" level="any"
      count="*[self::input or self::select or self::textarea]
              [@type != 'hidden']" />
  </xsl:attribute>
  ...
</xsl:template>
You could use "input[@type != 'hidden'] | select[@type != 'hidden'] |
textarea[@type != 'hidden']" as the value of the count attribute if
you prefer. Note that I dropped the "or @type = 'select'" since any
element with a type attribute equal to 'select' will pass the "@type
!= 'hidden'" test.
> The style sheet basically adds tabindex attributes to all form
> elements. What I'm unhappy with is the value of the select attribute
> of the second for-each element (the one that creates a node set of
> all child elements of a FORM element, regardless of what separates
> them). It seems odd that I have to fully qualify the child element
> I'm looking for, but using ancestor::form//select|input|textarea
> only matches the first element in the list.
Yes; in XPath 2.0, we'll be able to use:
  ancestor::form//(select | input | textarea)
which is a good deal shorter, and likewise with the count attribute
above, we'll be able to do:
  (input | select | textarea)[@type != 'hidden']
> Also, what is the performance impact on setting up such for-each
> loops and is there a faster way to reproduce this node-set in the
> context of the current element (call-template with-param???)?
Numbering based on position within the node tree is always fairly
expensive because it can require a lot of node visits. If the <input>,
<select> and <textarea> elements are siblings, you can use
level="single", which will mean that the processor doesn't have to
look at quite as many nodes. Or you could use a step-by-step recursive
template and pass the current count on from sibling to sibling. But
unless you find performance is really suffering here, I'd stick with
the <xsl:number> solution above.
By the way, rather than:
  <xsl:for-each select="@*"><xsl:copy /></xsl:for-each>
you could just do:
  <xsl:copy-of select="@*" />
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
| Current Thread | 
|---|
| 
 | 
| <- Previous | Index | Next -> | 
|---|---|---|
| Re: [xsl] Get Position of Node in A, Ted Stresen-Reuter | Thread | RE: [xsl] Get Position of Node in A, Michael Kay | 
| Re: [xsl] trying to create a node-s, Robert P. J. Day | Date | RE: [xsl] Xpath patern question, Hélder Sousa | 
| Month |