Reputation: 141
I'm running into a bit of an problem with XSLT while transforming an xml to another xml. The xml and xslt I am working with is more complex, and this problem is just a section of it.
I want information stored in a single element to go to two different elements in the output, and then do the same operation on the next element.
My programming instinct was to find the XSLT 1.0 version of making two lists and appending the correct data, but I don't see how to do that in pure XSLT 1.0.
The current solution is to call for-each statements for every kind of data I want to extract from these elements, but this ends up with a lot of repeating code. There has to be a better way! What is it and can you explain it well?
I have an xml of character elements. I want to extract names and quotes from each character, and put the names in a "character" element and quotes in a "taglines" element.
Initial XML:
<Cast>
<Character>
<name>The Cheat</name>
<quote>Meh</quote>
</Character>
<Character>
<name>Homsar</name>
<quote>eey-y-yy</quote>
</Character>
</Cast>
Output XML:
<Cast>
<Character>
<name>The Cheat</name>
<name>Homsar</name>
</Character>
<taglines>
<quote>Meh</quote>
<quote>eey-y-yy</quote>
</taglines>
</Cast>
Upvotes: 1
Views: 48
Reputation: 575
I would simply just set up the skeleton and xsl:copy-of
all relevant elements under their parents:
<xsl:template match="Cast">
<Cast>
<Character>
<xsl:copy-of select="//name"/>
</Character>
<taglines>
<xsl:copy-of select="//quote"/>
</taglines>
</Cast>
</xsl:template>
The resultant XML:
<Cast>
<Character>
<name>The Cheat</name>
<name>Homsar</name>
</Character>
<taglines>
<quote>Meh</quote>
<quote>eey-y-yy</quote>
</taglines>
</Cast>
Upvotes: 0
Reputation: 1235
Try this:
<xsl:template match="Cast">
<xsl:copy>
<xsl:element name="Character">
<xsl:apply-templates select="Character/name"/>
</xsl:element>
<xsl:element name="taglines">
<xsl:apply-templates select="Character/quote"/>
</xsl:element>
</xsl:copy>
</xsl:template>
<!-- Identity -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
Upvotes: 0
Reputation: 29042
With XSLT-1.0 you can achieve that with the following templates:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Cast">
<xsl:copy>
<Character>
<xsl:apply-templates select="Character/name" />
</Character>
<taglines>
<xsl:apply-templates select="Character/quote" />
</taglines>
</xsl:copy>
</xsl:template>
<xsl:template match="name">
<name><xsl:value-of select="." /></name>
</xsl:template>
<xsl:template match="quote">
<quote><xsl:value-of select="." /></quote>
</xsl:template>
</xsl:stylesheet>
Output is:
<?xml version="1.0"?>
<Cast>
<Character>
<name>The Cheat</name>
<name>Homsar</name>
</Character>
<taglines>
<quote>Meh</quote>
<quote>eey-y-yy</quote>
</taglines>
</Cast>
Upvotes: 0