RE: [xsl] trouble with preceding:: and parsing xhtml

Subject: RE: [xsl] trouble with preceding:: and parsing xhtml
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Sat, 3 Oct 2009 21:17:13 +0100
You're nearly there: you want  

preceding::div[@tid='field'][1]

Without the [1], you select all of them throughout the document; and if you
then use something like xsl:value-of (in XSLT 1.0) then you get the one that
is first in document order.

>Then I tried preceding::div[@tid='field' and last()] 

last() always gives a number that is 1 or more. "and last()" converts this
number to a boolean, and any number other than 1 is treated as true. So
you're adding "and true()" to your predicate, which doesn't change its
result. You were probably thinking of

preceding::div[@tid='field'][last()]

which means

preceding::div[@tid='field'][position() = last()]

But numeric predicates attached to a reverse axis step count the nodes in
reverse document order: 1 is the nearest, and last() is the furthest. So the
correct predicate is [1].

Regards,

Michael Kay
http://www.saxonica.com/
http://twitter.com/michaelhkay 
 

> -----Original Message-----
> From: Chris Wolf [mailto:cw10025@xxxxxxxxx] 
> Sent: 03 October 2009 20:37
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] trouble with preceding:: and parsing xhtml
> 
> I have some xhtml documents that I want to process with XSL.  
> The patterns that I'm interested in have a series of 
> occurances of "div" element in pairs as in:
> 
> <xhtml...>
> <head/>
> <body..>
> <table...>
> <tr..>
> <td...>
> <div tid="field"><a href="...">Foo</a></div> <table...> 
> <tr...> <td...> <div class="category_data">Bla,Bla,Bla</div>
> <...>
> 
> this pattern of the two pairs of div variations repeats an 
> arbitrary number of times throughout the document and there 
> could be other "div" elements interspersed, but not with the 
> same qualifying attributes.
> 
> 
> Note that the "div" with "class='category_data'" is not a 
> descendant of the first "div[@tid='field']"
> I don't think these pairs of DIVs are siblings either (at the 
> same level).
> 
> Basically, I'm trying to generate XML of name-value pairs 
> where the name
> comes from the content of the <a/> in the first 
> "div[@tid='field']", and the value is the
> content of the second "div[@class='category_data']".
> 
> So the output should be:
> <Field name="Foo">Bla,Bla,Bla</Field>
> 
> Where the value of the "name" attribute is the content of the 
> input doc's
> div[@tid='field']/a, i.e. in this example, 'Foo'
> 
> ...and the content of "Field" is the content of the input doc's
> div[@class='category_data']
> 
> 
> 
> Since the the second div is not a descendant of the first, I 
> can't capture 
> the <a/> content in a variable and call <xsl:apply-templates 
> select="div[@class='category_data']"/>
> with a parameter.
> 
> The question is how else to pass data from one template to 
> another template?
> 
> I tried "reaching back" from the second template by using 
> preceding::div[@tid='field']
> but this retrieved the value of the first node matching 
> "div[@tid='field']" not
> the immediately preceding node that matches, as I would have 
> expected.  Then I tried
> preceding::div[@tid='field' and last()] - same result; always 
> the same value and
> always the value of the very first node that matched.
> 
> I guess I have no idea how "preceding::" is supposed to work.
> 
> 
> I would greatly appreciate any help.  
> 
> Thanks,
> 
>    -Chris
> 
> <xsl:stylesheet version="1.0"
>     xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>     xmlns:h="http://www.w3.org/1999/xhtml";>
> 
> <xsl:output method="xml" indent="yes"/>
> <xsl:strip-space elements="div a"/>
> 
> <xsl:template match="/">
>   <xsl:message>***** ROOT</xsl:message>
>     <xsl:apply-templates select="//h:div"/>
> </xsl:template>
> 
> <xsl:template match="h:div[@tid='field']">
>   <xsl:message>***** DIV1</xsl:message>
>   <xsl:apply-templates select="h:div"/>
> </xsl:template>
> 
> <xsl:template match="h:div[@class='category_data']">
>   <xsl:param name="fname"/>
>   <xsl:message>***** DIV2</xsl:message>
>   <xsl:message>^<xsl:value-of 
> select="preceding::h:div[@tid='field']"/>^</xsl:message>
>   <xsl:element name="Field">
>     <xsl:attribute name="name">
>       <xsl:value-of select="preceding::h:div[@tid='field']"/>
>     </xsl:attribute>
>     <xsl:value-of select="."/>
>   </xsl:element><xsl:text>
> </xsl:text>
>         <xsl:apply-templates/>
> </xsl:template>
> 
> <xsl:template match="text()">
>   <xsl:message>***** TEXT</xsl:message>
>     <xsl:apply-templates/>
> </xsl:template>
> 
> </xsl:stylesheet>

Current Thread