f



extracting text from an XML node

Hi,

suppose i get the simple xml sample:
<foo>
  1
  <bar>2</bar>
  3
</foo>

Now suppose i want to extract all the text of only the 'foo' node, ie
expected result is '1 3'.
I tried both

  <xsl:template match="foo">
    <xsl:value-of select="text()" />
  </xsl:template>

and

  <xsl:template match="foo">
    <xsl:value-of select="." />
  </xsl:template>

but the former lead to '1' and the latter to '1 2 3' (using xsltproc &
firefox).
What did i missed ?

thanks,

-Nicolas
0
11/29/2007 9:00:50 PM
comp.text.xml 8781 articles. 0 followers. Post Follow

10 Replies
902 Views

Similar Articles

[PageSpeed] 7

nicolas.edel@gmail.com wrote:
> Now suppose i want to extract all the text of only the 'foo' node

That isn't a built-in concept; you have to recast it as "all the text 
nodes which are immediate children of the 'foo' node". (The built-in 
text value of an element, as you discovered, is the value of all text 
contained in it, directly or indirectly). Note too that the whitespace 
(line breaks and indentation) will be part of the the text nodes unless 
you explicitly strip that away.

     <xsl:value-of select="text()" />

didn't work because value-of returns the contents of only the first 
matching node. This is one case where xsl:for-each is appropriate, to 
explicitly iterate through the text children.

-- 
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
0
11/29/2007 11:34:08 PM
On Nov 30, 12:34 am, Joseph Kesselman <keshlam-nos...@comcast.net>
wrote:
> Note too that the whitespace
> (line breaks and indentation) will be part of the the text nodes unless
> you explicitly strip that away.

yes, but i didn't focused on it since this was not the main problem

>
>      <xsl:value-of select="text()" />
>
> didn't work because value-of returns the contents of only the first
> matching node. This is one case where xsl:for-each is appropriate, to
> explicitly iterate through the text children.
>

Ok, i misunderstood the 'text()' semantic. And indeed
    <xsl:for-each select="child::text()">
      <xsl:value-of select="."/>
    </xsl:for-each>
does the job.

Thanks a lot.

-Nicolas
0
11/30/2007 8:10:11 AM
On Nov 30, 9:10 am, nicolas.e...@gmail.com wrote:
>     <xsl:for-each select="child::text()">
>       <xsl:value-of select="."/>
>     </xsl:for-each>
> does the job.

Well, xsltproc and firefox do not behave the sameway.

foo.xml:
 <foo>
  1
  <bar>2</bar>
  3
</foo>

foo.xsl:
  <xsl:template match="foo">
     <xsl:for-each select="child::text()">
       <xsl:value-of select="."/>
     </xsl:for-each>
    <xsl:value-of select="." />
  </xsl:template>

Results:
   xsltproc => '1 3'
   firefox   => '1 2 3'

Which one is wrong ?

-Nicolas
0
11/30/2007 9:30:02 AM
nicolas.edel@gmail.com <nicolas.edel@gmail.com> wrote in
<b086323a-da6a-4afb-a86b-748a093a373c@j44g2000hsj.googlegroups.com>:
> On Nov 30, 9:10 am, nicolas.e...@gmail.com wrote:
>>     <xsl:for-each select="child::text()">
>>       <xsl:value-of select="."/>
>>     </xsl:for-each>
>> does the job.
> 
>   <xsl:template match="foo">
>      <xsl:for-each select="child::text()">
>        <xsl:value-of select="."/>
>      </xsl:for-each>

To blow my anti-xsl:for-each trumpet one more time,

  <xsl:apply-templates select="text()"/>

....should do the same, unless you've defined a template of
your own that would match those text nodes. The default
template for text nodes is:

  <xsl:template match="text()|@*">
    <xsl:value-of select="."/>
  </xsl:template>

>     <xsl:value-of select="." />
>   </xsl:template>

That's not a complete example, and it seems you've left some
of the chunks you used in the debugging in it.

> Results:
>    xsltproc => '1 3'
>    firefox   => '1 2 3'
> 
> Which one is wrong ?

Please post a minimal complete example that demonstrates the
problem, so that we can check ourselves. I'm unaware of any
differences between libxslt and TranforMiiX that could
cause the effect described, and, frankly, I doubt the
problem lies with the transformation engines you're using.

-- 
....also, I submit that we all must honourably commit seppuku
right now rather than serve the Dark Side by producing the
HTML 5 spec.
0
p.lepin1 (393)
11/30/2007 10:07:05 AM
On Nov 30, 11:07 am, Pavel Lepin <p.le...@ctncorp.com> wrote:
> >   <xsl:template match="foo">
> >      <xsl:for-each select="child::text()">
> >        <xsl:value-of select="."/>
> >      </xsl:for-each>
>
> To blow my anti-xsl:for-each trumpet one more time,
>
>   <xsl:apply-templates select="text()"/>
>

Oh, I didn't know the '<xsl:value-of select="."/>' may be implicit.

> ...should do the same, unless you've defined a template of
> your own that would match those text nodes. The default
> template for text nodes is:
>
>   <xsl:template match="text()|@*">
>     <xsl:value-of select="."/>
>   </xsl:template>
>

Wouldn't this would copy the attributes value too ?

> Please post a minimal complete example that demonstrates the
> problem, so that we can check ourselves. I'm unaware of any
> differences between libxslt and TranforMiiX that could
> cause the effect described, and, frankly, I doubt the
> problem lies with the transformation engines you're using.
>

foo.xml
----------------- 8< -----------------------
<?xml version="1.0"?>
<?xml-stylesheet href='foo.xsl'?>
<foo>
  1  <bar>2</bar>  3
</foo>
----------------- 8< -----------------------

foo.xsl (according to your advice)
----------------- 8< -----------------------
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
  <xsl:template match="foo">
    <xsl:apply-templates select='text()'/>
  </xsl:template>
</xsl:stylesheet>
----------------- 8< -----------------------

Not taking output layout into account , xsltproc produces '1 3' while
firefox still produces '1 2 3'

-Nicolas
0
11/30/2007 10:35:14 AM
On Nov 30, 11:35 am, nicolas.e...@gmail.com wrote:
> > To blow my anti-xsl:for-each trumpet one more time,
>
> >   <xsl:apply-templates select="text()"/>
>
> Oh, I didn't know the '<xsl:value-of select="."/>' may be implicit.

Now I understand http://www.w3.org/TR/xslt#built-in-rule ;)

-Nicolas
0
11/30/2007 10:39:06 AM
nicolas.edel@gmail.com <nicolas.edel@gmail.com> wrote in
<6d619ec9-0130-40af-a895-56cd5b955425@y5g2000hsf.googlegroups.com>:
> On Nov 30, 11:07 am, Pavel Lepin <p.le...@ctncorp.com>
> wrote:
>> >   <xsl:template match="foo">
>> >      <xsl:for-each select="child::text()">
>> >        <xsl:value-of select="."/>
>> >      </xsl:for-each>
>>
>> To blow my anti-xsl:for-each trumpet one more time,
>>
>>   <xsl:apply-templates select="text()"/>
>>
>> ...should do the same, unless you've defined a template
>> of your own that would match those text nodes. The
>> default template for text nodes is:
>>
>>   <xsl:template match="text()|@*">
>>     <xsl:value-of select="."/>
>>   </xsl:template>
> 
> Wouldn't this would copy the attributes value too ?

It would, in case you applied templates to attributes
somewhere without specifying another template that would
match said attributes.

> <?xml version="1.0"?>
> <?xml-stylesheet href='foo.xsl'?>

This must be:

  <?xml-stylesheet href="foo.xsl" type="text/xsl"?>

(I'm not sure whether it's mandated somewhere in the specs,
and cannot spare any time to look it up right now, but the
fact is that Firefox won't grok it otherwise.)

> <foo>
>   1  <bar>2</bar>  3
> </foo>
> 
> <?xml version="1.0"?>
> <xsl:stylesheet
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="1.0">

You'll need:

  <xsl:output method="text"/>

here. Otherwise Firefox will expect the transformation to
produce an XML document. Which it doesn't do.

>   <xsl:template match="foo">
>     <xsl:apply-templates select='text()'/>
>   </xsl:template>
> </xsl:stylesheet>
> 
> Not taking output layout into account , xsltproc produces
> '1 3' while firefox still produces '1 2 3'

Firefox doesn't actually run the transformation because it
cannot parse the PI you wrote. If you fix the PI without
changing the output method, it will simply display an empty
document, since the transformation doesn't actually produce
an XML document. If you fix both of those problems, Firefox
will display the expected resulting document.

-- 
....also, I submit that we all must honourably commit seppuku
right now rather than serve the Dark Side by producing the
HTML 5 spec.
0
p.lepin1 (393)
11/30/2007 11:38:19 AM
On Nov 30, 12:38 pm, Pavel Lepin <p.le...@ctncorp.com> wrote:
>
> Firefox doesn't actually run the transformation because it
> cannot parse the PI you wrote. If you fix the PI without
> changing the output method, it will simply display an empty
> document, since the transformation doesn't actually produce
> an XML document. If you fix both of those problems, Firefox
> will display the expected resulting document.

Indeed.
Many thanks for your precious help.

-Nicolas
0
11/30/2007 12:59:00 PM
>>  <xsl:apply-templates select="text()"/>
>>...should do the same, unless you've defined a template of
>>your own that would match those text nodes.

Granted.

-- 
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
0
11/30/2007 4:43:43 PM
<nicolas.edel@gmail.com> wrote in message 
news:e9e64863-aafb-43ed-9d0d-f2c187ea0b36@y43g2000hsy.googlegroups.com...
> Hi,
>
> suppose i get the simple xml sample:
> <foo>
>  1
>  <bar>2</bar>
>  3
> </foo>
>
> Now suppose i want to extract all the text of only the 'foo' node, ie
> expected result is '1 3'.
> I tried both
>
>  <xsl:template match="foo">
>    <xsl:value-of select="text()" />
>  </xsl:template>
>
> and
>
>  <xsl:template match="foo">
>    <xsl:value-of select="." />
>  </xsl:template>
>
> but the former lead to '1' and the latter to '1 2 3' (using xsltproc &
> firefox).
> What did i missed ?


This is pretty simple.
Use:

  <xsl:template match="foo/text()">
    <xsl:value-of select='concat(.,' ')'/>
  </xsl:template>


Cheers,
Dimitre Novatchev. 


0
dimitren1 (155)
12/1/2007 5:53:47 AM
Reply: