This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: "apply-templates" doesn't work for novice


Greg:

Hi Greg,

At 06:12 PM 9/27/01, you wrote:
>I am a novice with XSL. Here is a simplified version of the XML document i 
>am  trying to transform.
>
><Notebook>
><List>
><Cell>
><CellGroupData>
><List>
>     <Cell>
>         <String>This is a Title</String>
>             <Style>
>             <String>Title</String>
>             </Style>
>     </Cell>
></List>
></CellGroupData>
></Cell>
><List>
><Options>
>     <Option>
>         <Symbol>FrontEndVersion</Symbol>
>         <String>4.1 for Microsoft Windows</String>
>     </Option>
></Options>
></Notebook>
>
>When I use a narrowing down approach for the above document like so:
>
><xsl:template match="Notebook">
>  <xsl:apply-templates select="List/*"/>
></xsl:template>
>
><!--Cell Group Level-->
><xsl:template match="CellGroupData">
>  <xsl:apply-templates select="List"/>
></xsl:template>
>
><xsl:template match="Cell/String">
><xsl:value-of select="String"/>
></xsl:template>

Oops -- this last template will get you into trouble, because it's 
effectively saying "for a String that's a child of a Cell, I want the value 
of its String child" and from what I can see, no String element has a 
String child. So you'll get nothing.

>followed by my VALUE-OF style-specific template:
>
>"<xsl:template match="Cell/Style[String='Title']">
>&#64;Title:<xsl:value-of select="../String"/></xsl:template>"

Backwards, but will sorta work. Backwards because it's generating the 
content when it finds the Style, not when it finds the content itself (the 
Cell/String).

>I get exactly the result on the text output document that I want and 
>expect. It looks like this: @Title:This is a title.

Okay!

>The problem is that my XML document is MUCH more complicated than the one 
>shown above, so the "value-of" approach ends up being incredibly buggy and 
>tedious because I have to get every instance listed: 
>"data/list/data/cell/group/testdata/style/string" for every single style 
>(of which there are hundreds). Also text with inline styles is weirdly 
>situated and it is difficult to catch this way as well.

That happens when you do things backwards. :-)

>I would very much like to use an "apply-templates" approach to avoid this; 
>but when i change the above style-specific template to:
>
>"<xsl:template match="Cell/Style[String='Title']">
>&#64;Title:<xsl:apply-templates select="../String"/></xsl:template>
>
>I get no text at all.

That's because when you select "../String" from a Style inside a Cell (a 
Cell/Style being your context node), you get a String inside the Cell, and 
applying templates to that, you get the template I warned you about above!

The strength -- and weakness -- of template-based processing is that *all 
the templates work together* (including the built-in default templates I 
mentioned, which you don't see).

>  If I change one of the narrowing templates like the third one listed 
> above(match="Cell/String) so that the value-of select ="." I get 
> duplicates of all the text:
>
>This is a title.@Title:This is a title.

Right. Because now, you're generating the content when you match the 
Cell/String (with the value-of select="." in that template), and *again* 
when you match the Cell/Style (because of the apply-templates 
select="../String", which goes and gets the same template you just used).

>Is there no happy medium between none or double using the apply-templates 
>approach?

Absolutely.

You're nearly there: just step back a bit and think about what you're 
trying to achieve where. XSLT is actually alot easier to think about if you 
frame your problem as a "for X input, I want Y" kind of thing.

In your case, what you have going in looks like
>     <Cell>
>         <String>This is a Title</String>
>             <Style>
>             <String>Title</String>
>             </Style>
>     </Cell>

and what you want out from that is

@Title:This is a title.

Or generalized, this means "when I output a Cell, I want the content in its 
String child, prefixed with a 'tag' based on the content of its Style 
element child".

This is easily done in XSLT by:

<xsl:template match="Cell">
   <xsl:apply-templates select="Style"/>
   <xsl:apply-templates select="String"/>
   <!-- selecting the children to change the default order
        (which would be document order) -->
</xsl:template>

<xsl:template match="Style">
   <!-- using this template to generate your "tag" prefix -->
   <xsl:text>@</xsl:text>
   <xsl:apply-templates/>
   <!-- you could use value-of select=".", but why not let the processor do it
        for you when it gets down to the text node -->
   <xsl:text>:</xsl:text>
</xsl:template>

You will undoubtedly discover this works, except for whitespace issues 
which come with the territory when you're driving through the default 
templates (which you are, but you don't see this since they are defaults). 
These are most easily fixed by saying

<xsl:strip-space elements="Cell Style"/>

at the top level of your stylesheet. (This tells the processor to throw 
away whitespace-only text nodes inside these two elements.) If whitespace 
is *still* a problem, only then start looking at xsl:value-of (which 
concatenates text node descendants, removing the effect of any element 
structures lower down) and the normalize-space() function.

I'm afraid, however, that for a complete explanation, you need to look at a 
high-level view of the stylesheet processing model (several are now 
available in print, and there's always the XSL FAQ and the archives of this 
list). In particular, you want to know about the built-in default templates 
and what they do.

>  I feel that there is something fundamental that i am missing here that 
> is not allowing me to use the apply-templates approach. Can it be done, 
> and if so how? An example of code WITH AN EXPLANATION of why it works 
> would be VERY much appreciated.

I hope this has been some use. You only need to see how the processor goes 
from one template to the next -- how they match, and what happens if there 
is no match (since there's always a match! ... those built-ins again).

Enjoy,
Wendell



======================================================================
Wendell Piez                            mailto:wapiez@mulberrytech.com
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
   Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]