xsl to flatten xml nodes

S

Simon

Hi,

I have generated an xml document, and would like to be able to transform it
to another such that the contents of a chosen node type are flattened (i.e.
tags removed). e.g.

<shop>
<name>super</name>
<sells>
<drink>squash</drink>
<drink>beer</drink>
<food>
<fresh>bread</fresh>
<fresh>apples</fresh>
<frozen>peas</frozen>
</food>
</sells>
</shop>

apply 'flatten' to <sells> to give...

<shop>
<name>super</name>
<sells>
squash
beer
bread
apples
peas
</sells>
</shop>

This seems like the kind of thing I could use xsl for. Could someone please
give me a xsl example showing how this would be done?

Thanks for your time,
Simon
 
S

Simon

This is quite straightforward. This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*" />

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

<xsl:template match="*[ancestor::sells]">
<xsl:apply-templates/>
</xsl:template>

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

</xsl:stylesheet>

Thanks for such a quick response! Is there any chance you could talk me
through it so I fully understand how it works? My xsl book hasn't arrived
yet!
Thanks again,
Simon
 
D

Dimitre Novatchev [MVP XML]

Simon said:
Hi,

I have generated an xml document, and would like to be able to transform it
to another such that the contents of a chosen node type are flattened (i.e.
tags removed). e.g.

<shop>
<name>super</name>
<sells>
<drink>squash</drink>
<drink>beer</drink>
<food>
<fresh>bread</fresh>
<fresh>apples</fresh>
<frozen>peas</frozen>
</food>
</sells>
</shop>

apply 'flatten' to <sells> to give...

<shop>
<name>super</name>
<sells>
squash
beer
bread
apples
peas
</sells>
</shop>

This seems like the kind of thing I could use xsl for. Could someone please
give me a xsl example showing how this would be done?


This is quite straightforward. This transformation:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*" />

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

<xsl:template match="*[ancestor::sells]">
<xsl:apply-templates/>
</xsl:template>

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

</xsl:stylesheet>

when applied on your source.xml:

<shop>
<name>super</name>
<sells>
<drink>squash</drink>
<drink>beer</drink>
<food>
<fresh>bread</fresh>
<fresh>apples</fresh>
<frozen>peas</frozen>
</food>
</sells>
</shop>

produces the wanted result:

<shop>
<name>super</name>
<sells>
squash
beer
bread
apples
peas</sells>
</shop>



Cheers,

Dimitre Novatchev [XML MVP],
FXSL developer, XML Insider,

http://fxsl.sourceforge.net/ -- the home of FXSL
Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
 
M

Martin Honnen

That template above is an identity transformation, it copies nodes from
the source document to the result document.
Many XSLT transformations use that template if much of the source
document has to be copied over to the result document.
Now you only need to write templates for those elements that are not to
be copied.
<xsl:template match="*[ancestor::sells]">
<xsl:apply-templates/>
</xsl:template>

That template matches any element nodes whose ancestor is a <sells>
element, that is your <drink> or <food> or <fresh> element. For those
you don't want to copy the element but only their text content so all
the template does is call xsl:apply-templates on the child nodes.
<xsl:template match="text()[ancestor::sells]">
<xsl:value-of select="concat('
',.)"/>
</xsl:template>

This template then deals with all the text nodes which have a <sells>
element as an ancestor and outputs any of them on a line of its own.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top