tags:

views:

81

answers:

4

I have looked up solutions on stackflow, but none of them seem to work for me. Here is my question. Lets say I have the following text :

Source:

<greatgrandparent>
<grandparent>
    <parent>
         <sibling>
              Hey, im the sibling .
          </sibling>
        <description>
        $300$ <br/> $250 <br/> $200! <br/> <p> Yes, that is right! <br/> You can own a ps3 for only $200 </p>
        </description>
    </parent>
    <parent>
         ... (SAME FORMAT)
    </parent>
       ... (Several more parents)
</grandparent>
</greatgrandparent>

Output:

 <newprice>
        $300$ <br/> $250 <br/> $200! <br/> Yes, that is right! <br/> You can own a ps3 for only $200  
    </newprice>

I can't seem to find a way to do that.

Current XSL:

    <xsl:template match="/">
            <xsl:apply-templates />
        </xsl:template>

        <xsl:template match="greatgrandparents">
            <xsl:apply-templates />
        </xsl:template>

    <xsl:template match = "grandparent">

    <xsl:for-each select = "parent" >
          <newprice>
             <xsl:apply-templates>
           </newprice>
    </xsl:for-each>
    </xsl:template> 

<xsl:template match="description"> 
    <xsl:element name="newprice"> 
       <xsl:apply-templates/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="p"> 
   <xsl:apply-templates/> 
</xsl:template> 
A: 

Shouldn't the contents of be inside a CDATA element? And then probably disable output encoding on xsl:value-of..

CharlesLeaf
Thanks for the response! And I wasn't told that they need to be part of CDTATA from my supervisor.
Bilzac
A: 

You should look into xsl:copy-of.

You would probably wind up with somthing like:

<xsl:template match="description">
    <xsl:copy-of select="."/>
</xsl:template>
Hank Gay
Thanks for the response!
Bilzac
+5  A: 

Use templates to define behavior on specific elements

<!-- after standard identity template -->

<xsl:template match="description">
    <xsl:element name="newprice">
       <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="p">
   <xsl:apply-templates/>
</xsl:template>

The first template says to swap description with newprice. The second one says to ignore the p element.

If you're unfamiliar with the identity template, take a look here for a few examples.

EDIT: Given the new example, we can see that you want to only extract the description element and its contents. Notice that the template action starts with the match="/" template. We can use this control where our stylesheet starts and thus skip much of the riffraff we want to filter out.

change the <xsl:template match="/"> to something more like:

    <xsl:template match="/">
        <xsl:apply-templates select="//description"/>   
        <!-- use a more specific XPath if you can -->
    </xsl:template>

So altogether our solution looks like this:

<xsl:stylesheet 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    exclude-result-prefixes="xs">

<xsl:template match="/">
    <xsl:apply-templates select="//description" />
</xsl:template>

<!-- this is the identity template -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="description">
    <xsl:element name="newprice">
       <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="p">
   <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>
Jweede
Im going to give this a try. I'll let you know how it goes. I think I was having a problem with <xsl:apply-templates> It was for some weird reason adding other fields into all of this. Thanks for the response!
Bilzac
Using the identity template is key to `<xsl:apply-templates>` Let me know if you need a complete example or if this is enough.
Jweede
ehh. I can't get it to work. It seems to be adding all the siblings of description.
Bilzac
the code given works for the example you provided. Is there something more we need to know?
Jweede
i'm going to edit it just hold up a second. And thank you so much. Need this done soon, got a live presentation in June.
Bilzac
updated :). Sorry needed to remove some confidential stuff. Thanks :)
Bilzac
It's been updated. Notice that you only need four templates to get the desired result: The identity template, and the three I've shown you in this example.
Jweede
Hmm, the <br> tag seems to be disappearing still.
Bilzac
The `<br />` tag will not copy unless you use The Identity Template.
Jweede
ok, they dont disappear anymore :)
Bilzac
Glad it's working for you. :)
Jweede
A: 

Probably the shortest solution is this one:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="description">
   <newprice>
     <xsl:copy-of select="node()"/>
   </newprice>
 </xsl:template>

 <xsl:template match="text()[not(ancestor::description)]"/>
</xsl:stylesheet>

When this transformation is applied on the provided XML document, the wanted result is produced:

<newprice>
        $300$ <br /> $250 <br /> $200! <br /> <p> Yes, that is right! <br /> You can own a ps3 for only $200 </p>
        </newprice>

Do note:

  1. The use of <xsl:copy-of select="node()"/> to copy all the subtree rooted in description, without the root itself.

  2. How we override (with a specific, empty template) the XSLT built-in template, preventing any text nodes that are not descendents of a <description> element, to be output.

Dimitre Novatchev
Thanks for the response!
Bilzac