PipperChip
PipperChip

Reputation: 141

Growing output elements from input elements with XSLT 1.0

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.

The Problem

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?

An example

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

Answers (3)

Xavier Dass
Xavier Dass

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

John Ernst
John Ernst

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

zx485
zx485

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

Related Questions