Subject: Re: [xsl] filtering descendent text nodes From: Peter Davis <pdavis152@xxxxxxxxx> Date: Mon, 18 Mar 2002 01:36:57 -0800 |
Child nodes are nodes that are contained within another element, and descendent nodes are children of children (of children... and so on). Also, child of an element is also a descendent of that element, but not all descendents are children. The problem here is that you have a template that matches "customer//node()", which is supposed to output the value of that node with xsl:value-of. I see what you were trying to do, but it doesn't quite work like that. It is doing exactly what you tell it to, but the node() match is not specific enough. Here is what is happening when your stylesheet executes: 1) The root (in template match="/") is selected. xsl:apply-templates is called on all the children of the root. 2) "custdet" is selected and matched by template match="*", and xsl:apply-templates is called on the children. 3) "customer" is selected by template match="*", xsl:apply-templates on the children. 4) "name" is selected by template match="customer//node()", because <name> is a descendent of <customer>. It is also a child of <customer>, but all children are also descendents, and therefore the "//" applies to it as well. So the HTML code and "First Name:" are output when the <name> element is selected. Then, you call <xsl:value-of select="."/>, which outputs the text value of *all* of the descendent nodes of <name> put together. This is why FIRST1, NAME1, and SECONDNAME1 are all output on the same line (well, not really the same line if you look at the HTML output's directly instead of in a browser, but I'll get to the whitespace problems in a minute). The solution is to make your templates more specifically match what you want them to match. If you want the result to be: First Name: FIRST1 First Name: NAME1 First Name: SECONDNAME1 then instead of matching "customer//node()", you should match "customer//text()". That way each text node within <customer> gets its own "First Name:" and associated HTML. "customer//node()" is to general, since it matches the first node it finds, even though the node is a child as well as a descendent. But since it does not appear that all of those names are actually first names, you will need to have different templates for each <firstname>, <secondname>, or <secondname1> element. If you want them to still have the same HTML, but different text, then you can do it with a named template: <!-- remove template match="customer//node()", since it is replaced by the following templates --> <xsl:template match="firstname"> <xsl:call-template name="output-name"> <xsl:with-param name="description">First Name: </xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template match="firstname"> <xsl:call-template name="output-name"> <xsl:with-param name="description">Second Name: </xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template match="secondname1"> <xsl:call-template name="output-name"> <xsl:with-param name="description">Second Name 1: </xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template name="output-name"> <xsl:param name="description"/> <xsl:copy-of select="$description"/> <b><i> <font color="red"> <xsl:value-of select="." /> <br/> </font> </i></b> </xsl:template> The other problem you are seeing, and the reason why you are getting multiple "First Name:" outputs with empty content, is because the whitespace in the source document is being matched by "customer//node()" just as the <name> is. I'm talking about the whitespace between <customer> and <name> and between </name> and </customer>. If you use something like the above example templates, the problem will go away because those templates are more specific about what they match. But if you still use your current templates, you will have to add <xsl:strip-space elements="*"> to the top of your stylesheet to remove text nodes that contain only whitespace. Hope this helps! On Sunday 17 March 2002 19:09, Aseef Jamaluddin wrote: > hi, > i am new to xslt. Given below is the files i am using. > > <?xml version="1.0" ?> > <custdet> > <customer> > <name> > <firstname>FIRST1</firstname> > <secondname>NAME1 > <secondname1>SECONDNAME1</secondname1> > </secondname> > </name> > </customer> > </custdet> > > ------------------- > I AM TRYING TO FILTER OUT ALL DESCENDENT TEXT NODES > VALUES (I.E. FIRST1,NAME1,SECONDNAME1) AND AM USING > THE FOLLOWING XSL FOR THAT. > ------------------- > > <?xml version="1.0"?> > <xsl:stylesheet > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > version="1.0"> > <xsl:template match="/"> > <xsl:apply-templates /> > </xsl:template> > <xsl:template match="*"> > <xsl:apply-templates/> > </xsl:template> > <xsl:template match="text()"> > <xsl:apply-templates/> > </xsl:template> > <!-- --> > <xsl:template match="customer//node()"> > First Name : > <b><i> > <font color="red"> > <xsl:value-of select="." /> > <br/> > </font> > </i></b> > > </xsl:template> > <!----> > </xsl:stylesheet> > > > THE expected result is three lines with "FIRST NAME:" > prefix and the corresponding text value attached. The > output i am getting is as follows > > > First Name : > First Name : FIRST1 NAME1 SECONDNAME1 > First Name : > First Name : 20one1 > First Name > > Could somebody explain what actually is happening and > also some light on the difference between child nodes > and descendent nodes. > > Thanks > Aseef.J > > __________________________________________________ > Do You Yahoo!? > Yahoo! Sports - live college hoops coverage > http://sports.yahoo.com/ > > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list -- Peter Davis If at first you don't succeed, quit; don't be a nut about success. XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] filtering descendent text, Michael Kay | Thread | Re: [xsl] filtering descendent text, Joerg Pietschmann |
Re: [xsl] XSLT 2.0 question, Jeni Tennison | Date | Re: [xsl] general purpose filter st, Robert Sösemann |
Month |