tags:

views:

83

answers:

3

XML/XSL newbie here, so please forgive my ignorance. This is the xml input given to me:

<entry>
    <desc>
        <p>Lorem ipsum <a href="http://www.google.com"&gt;dolor&lt;/a&gt; sit amet.</p>
        <p>Lorem <strong>ipsum</strong> dolor sit amet.</p>
    </desc>
</entry>

I must write an XSL to get this result:

<p>Lorem ipsum <a href="http://www.google.com"&gt;dolor&lt;/a&gt; sit amet.</p>
<p>Lorem <strong>ipsum</strong> dolor sit amet.</p>

I thought this would work, in an entry template:

<xsl:value-of select="desc"/>

but instead this is the output of the above line:

Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.

Am I correct in assuming there must be other xsl stylesheets on my system that do that? In any case, I have neither read not edit access to them, I can only add a new stylesheet, so to fix this I used this:

<xsl:for-each select="desc/*">
    <p><xsl:value-of select="."/></p>
</xsl:for-each>

This gets me, at least:

<p>Lorem ipsum dolor sit amet.</p><p>Lorem ipsum dolor sit amet.</p>

However as you can see links and formatting have gone bye bye! I have no control on the kind of html elements that get added in there. Can anybody suggest a way to preserving the formatting and all of the desc element? The engine is XSL 1 only. Thanks in advance!

+4  A: 

You need to copy the elements under desc and all of their sub-elements. The copy-of XSL element will do this for you:

<xsl:copy-of select="desc/node()"/>

That will copy all of the children of desc, including text nodes, and any of their sub-elements.

Welbog
Unless you're sure `<desc>` will only contain elements (no mixed content), I'd recommend using `"desc/node()"` instead, which will grab both elements and text nodes.
Ben Blank
@Ben Blank: The example has only elements, but your point is valid. I will add it to my answer.
Welbog
Thanks! I'll try that tomorrow at work and see if it gives me the desired output.
neobackup08
Just to add that the reason that this is the correct answer is that xsl:value-of will return the text value of all child nodes, which is why you're only getting the Lorem Ipsum without the markup. xsl:copy-of will copy the nodes as well as their text.
carolclarinet
Thanks guys, only had time to try it today and it works like a charm! And thanks so much carolclarinet too for the explanation, that makes sense!
neobackup08
A: 

Try this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="/entry/desc">
     <xsl:copy-of select="@*|node()"/>
    </xsl:template>
</xsl:stylesheet>
Andrew Hare
I'm already inside a <pre><xsl:template match="/entry"></pre> template, which I omitted for brevity. Would the @*|node() part of the select work inside such a template? I confess I'm at a loss as on what it means.
neobackup08
A: 

Your select is incorrect.

select="desc"

or

select="/entry/desc"

From http://w3schools.com/xpath/xpath%5Fsyntax.asp:

nodename Selects all child nodes of the named node

/ Selects from the root node

// Selects nodes in the document from the current node that match the selection no matter where they are

. Selects the current node

.. Selects the parent of the current node

@ Selects attributes

Eric M
His selectors are obviously right, otherwise he'd get no output at all. It's more likely that he's simply omitted the `for-each` or `template` declarations which establish the context around his snippets.
Welbog
I omitted the "entry" template declaration for brevity, but my select does get the value of the desc element, just stripped of all formatting for reasons unknown to me.
neobackup08
I stand corrected.
Eric M