EMAD SEYED
EMAD SEYED

Reputation: 13

Merging XML in different sequences

I know there have been other questions on this topic, but what I'm looking for its not there.

What I want to do is to combine 2 XML files, but not exactly one XML file after another.

For example my first xml file would be game.xml:

<forSale>
<game>
    <title>Mass Effect 3</title>
    <releaseDate>
        <yyyy>2012</yyyy>
        <mm>03</mm>
        <dd>06</dd>
    </releaseDate>
    <esrbRating>M</esrbRating>
    <platforms>
        <platform>X360</platform>
    </platforms>
</game>
<game>
    <title>Borderlands 2</title>
    <releaseDate>
        <yyyy>2012</yyyy>
        <mm>09</mm>
        <dd>18</dd>
    </releaseDate>
    <esrbRating>M</esrbRating>
    <platforms>
        <platform>PC</platform>
    </platforms>
</game>

And my second xml file reviews.xml

<reviews>
<game>
    <title>Mass Effect 3</title>
    <review>
        <critic>Kevin VanOrd</critic>
        <pros>
            <pro><![CDATA[Fantastic, moving story that balances plot and character]]></pro>
        </pros>
        <cons>
            <con><![CDATA[Some glitches and bugs]]></con>
        </cons>
    </review>
</game>

<game>
    <title>Borderlands 2</title>
    <review>
        <critic>Chris Watters</critic>
        <pros>
            <pro><![CDATA[A ton of great mission writing and dialogue]]></pro>
        </pros>
        <cons>
            <con><![CDATA[Spoken messages sometimes interrupt each other]]></con>
        </cons>
    </review>
</game>

And I want my resulting master XML to be like this:

<forSale>
<game>
    <title>Mass Effect 3</title>
    <releaseDate>
        <yyyy>2012</yyyy>
        <mm>03</mm>
        <dd>06</dd>
    </releaseDate>
    <esrbRating>M</esrbRating>
    <platforms>
        <platform>X360</platform>
    </platforms>
    <review>
        <critic>Kevin VanOrd</critic>
        <synopsis>
            Mass Effect 3 is a remarkably satisfying conclusion to a beloved trilogy, and a poignant and memorable role-playing action game in its own right.
        </synopsis>
        <pros>
            <pro>Fantastic, moving story that balances plot and character</pro>
        </pros>
        <cons>
            <con>Some glitches and bugs</con>
        </cons>
    </review>
</game>
<game>
    <title>Borderlands 2</title>
    <releaseDate>
        <yyyy>2012</yyyy>
        <mm>09</mm>
        <dd>18</dd>
    </releaseDate>
    <esrbRating>M</esrbRating>
    <platforms>
        <platform>PC</platform>
    </platforms>
    <review>
        <critic>Chris Watters</critic>
        <synopsis>
            Stellar writing and a host of small improvements help Borderlands 2 stand tall on the shoulders of its predecessor.
        </synopsis>
        <pros>
            <pro>A ton of great mission writing and dialogue</pro>
        </pros>
        <cons>
            <con>Spoken messages sometimes interrupt each other</con>
        </cons>
    </review>
</game>

I tried this code, but it outputs the games first then the reviews

<xsl:template match="/forSale">
<xsl:copy>
    <xsl:apply-templates select="game"/>
    <xsl:apply-templates select="document('reviews.xml')/reviews/game/review"/>
    </xsl:copy>
</xsl:template>
<xsl:template match =" @* | node()">
<xsl:copy>
  <xsl:apply-templates select="@* | node() | text()"/>
</xsl:copy>
</xsl:template>

Upvotes: 0

Views: 70

Answers (1)

Tim C
Tim C

Reputation: 70648

This is because this line...

<xsl:apply-templates select="document('reviews.xml')/reviews/game/review"/>

is independent from the previous line where you select the games, and so will copy all games, not just a specific line.

What you need to do is more this line into a template that matches the game element, and amend it to output the selected game only

<xsl:apply-templates select="document('reviews.xml')/reviews/game[title=current()/title]/review"/>

Try this XSLT

<xsl:template match="/forSale">
   <xsl:copy>
       <xsl:apply-templates select="game"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="game">
   <xsl:copy>
       <xsl:apply-templates select="@* | node() | text()"/>
       <xsl:apply-templates select="document('reviews.xml')/reviews/game[title=current()/title]/review"/>
   </xsl:copy>
</xsl:template>

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

Upvotes: 1

Related Questions