Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old May 16th, 2007, 09:23 AM
Authorized User
 
Join Date: Apr 2007
Posts: 18
Thanks: 1
Thanked 0 Times in 0 Posts
Default last template getting processed again

Hi,
Am converting html to XML using XSLT. The html could be in the form of:
Code:
<html><body><span>span starts<strong>bold here[u]bold and underline</u>bold again</strong>normal text</span></body></html>
There could be multiple occurrences of span tags. The xml generated should be in the form of
Code:
<richtext>span starts</richtext><richtext bold="true">bold here</richtext><richtext bold="true" underline="true">bold and underline</richtext><richtext bold="true">bold again</richtext><richtext>noraml text</richtext>
Am using following xsl to convert html into desired xml
Code:
<xsl:template match="html">
        <xsl:apply-templates select="body" />
</xsl:template>
<xsl:template match="body">
    <xsl:apply-templates />
<xsl:template match="span//text()">
<RICHTEXT>
      <xsl:apply-templates/>
      <xsl:value-of select="."/>
</RICHTEXT>
</xsl:template>

<<xsl:template match="span//text()">
<RICHTEXT>
    <xsl:apply-templates/>
         <xsl:value-of select="."/>
</RICHTEXT>
</xsl:template>
<xsl:template match="strong//text()">
<RICHTEXT>
        <xsl:attribute name="BOLD">true</xsl:attribute>
        <xsl:for-each select="ancestor::*">
    <xsl:variable name="tagName" select="name(..)"></xsl:variable>
    <xsl:if test="$tagName='u'">
       <xsl:attribute name="UNDERLINE">true</xsl:attribute>
    </xsl:if>

        </xsl:for-each>                
 <xsl:value-of select="."/>
</RICHTEXT>
</xsl:template>
<xsl:template match="u//text()">
<RICHTEXT>
        <xsl:attribute name="UNDERLINE">true</xsl:attribute>
        <xsl:for-each select="ancestor::*">
    <xsl:variable name="tagName" select="name(..)"></xsl:variable>
    <xsl:if test="$tagName='strong'">
       <xsl:attribute name="BOLD">true</xsl:attribute>
    </xsl:if>
        </xsl:for-each>                
 <xsl:value-of select="."/>
</RICHTEXT>
</xsl:template>
This works fine if the html contains strong first and then u tag. But if the html contains u first and then strong, the strong//text() template is not processed at all and the u//text() template is processed again. This may be because the xslt engine is not able to identify the template to execute and it is executing the last template again. Please help me on this.
Thanks
 
Old May 16th, 2007, 09:46 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Technically it's an error to have two template rules that match the same node. Some products will give you a warning message about this, but if they don't, they invoke the last template that matches. So if you have a rule for u//text() and a rule for i//text(), then a text node that is inside a u element and also inside an i element matches both, and the second rule will always be the one that fires (unless the error is reported).

I think this transformation is best tackled by having a single template rule that matches all text nodes, it can then look at its ancestors and decide what attributes to put on the constructed richtext element.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old May 16th, 2007, 10:25 AM
Authorized User
 
Join Date: Apr 2007
Posts: 18
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Thanks for your quick reply Michael. Could you please explain how can I declare a generic text node that will looks for all its ancestor node?
Thanks once again,
Kapil
 
Old May 16th, 2007, 10:49 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

I would do something like this:

<xsl:template match="text()">
<RICHTEXT>
  <xsl:apply-templates select="ancestor::*" mode="text-ancestor"/>
  <xsl:value-of select="."/>
</RICHTEXT>
</xsl:template>

<xsl:template match="u" mode="text-ancestor">
  <xsl:attribute name="UNDERLINE">true</xsl:attribute>
</xsl:template>

<xsl:template match="b" mode="text-ancestor">
  <xsl:attribute name="BOLD">true</xsl:attribute>
</xsl:template>

<xsl:template match="i" mode="text-ancestor">
  <xsl:attribute name="ITALIC">true</xsl:attribute>
</xsl:template>

<xsl:template match="*" mode="text-ancestor">

</xsl:template>

etc


Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old May 16th, 2007, 12:18 PM
Authorized User
 
Join Date: Apr 2007
Posts: 18
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Thanks Miachel. Your solution is working to perfection.
Is it possible to override the text() template for certain nodes, for example i would like to handle the span//text() and div//text() node differently. Since the div/span tag may contain a class attribute and in that case I have to set a class attribute of Richtext.
Regards,
Kapil

 
Old May 16th, 2007, 01:02 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

What if the text node is a child of <b> which is a child of <span> or <div>?

I would handle this by adding a rule such as:

<xsl:template match="span|div" mode="text-ancestor">
  <xsl:attribute name="class">
    <xsl:value-of select="@class"/>
  </xsl:attribute>
</xsl:template>

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old May 17th, 2007, 08:48 AM
Authorized User
 
Join Date: Apr 2007
Posts: 18
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Thanks Michael. Your solution is working in all scenarios.
I have adoubt aboutThe statement <xsl:apply-templates select="ancestor::*" mode="text-ancestor"/>
Will it be called for all the nodes ? My html is in the form of
<html><body><div><span>text<b>bold</span></div><div><span><i>italic</i></span></div></body></html>
When the italic text is processed will it process the template for body and html? My requirement is to process till the last div tag.
Thanks,
Kapil
 
Old May 17th, 2007, 09:19 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Yes, the apply-templates select="ancestor::*" will process all the ancestors. But because of this template rule:

<xsl:template match="*" mode="text-ancestor">

</xsl:template>

that doesn't do any harm.



Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old May 17th, 2007, 09:54 AM
Authorized User
 
Join Date: Apr 2007
Posts: 18
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Ok. Can't I limit it to traverse ancestors till the last div tag?

 
Old May 17th, 2007, 10:11 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

> Ok. Can't I limit it to traverse ancestors till the last div tag?

You can do it, but not easily, which is why I didn't. You would have to do something like

select="ancestor::* except ancestor::div[last()]/ancestor::*"

which is more code to write and probably much slower than the solution I gave you, and it relies on there being a div element ancestor.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference





Similar Threads
Thread Thread Starter Forum Replies Last Post
problem retrieving data processed by class library maricar C# 0 October 23rd, 2008 10:27 PM
template uicdbd XSLT 5 March 15th, 2007 12:54 PM
template uicdbd XSLT 1 March 14th, 2007 05:16 PM
file upload processed on separate page vauneen ASP.NET 2.0 Professional 0 August 8th, 2006 03:03 AM
calling one template in other template VijayKumar XSLT 3 September 15th, 2005 11:12 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.