user3631019
user3631019

Reputation:

Combine XML documents with XSLT with grouping

I am trying to combine two XML documents, one is a list of movies and the other is a list of directors. they look like this. directors

<directors>
  <director>
    <name>director 1</name>
    <born> 5/12/1992 </born>
    <nationality>Italian</nationality>
    <biography>some info on director</biography>
  </director>
  <director>
    <name>director 2 </name>
    <born>21/2/1980</born>
    <nationality>french</nationality>
    <biography>a bit about me</biography>
  </director>

movies

<movies>
  <movie>
    <title> movie1</title>
    <director> director 1 </director>
    <date> 1/2/2010 </date>
    <genre> Action</genre>
  </movie>
  <movie>
    <title> movie2</title>
    <director> director 1 </director>
    <date> 1/2/2010 </date>
    <genre> romance</genre>
  </movie>
  <movie>
    <title> movie3</title>
    <director> director 2 </director>
    <date> 1/2/2010 </date>
    <genre> Action</genre>
  </movie>

and i want to make the output

<director>
<name>director 1</name>
<born> 5/12/1992 </born>
<nationality>Italian</nationality>
<biography>some info on director</biography>
<movies genre="action">
  <movie>
    <title> movie1</title>
    <date> 1/2/2010 </date>
 </movie>
 <movie>
    <title> movie2</title>
    <date> 1/2/2010 </date>
 </movie>
 <movies genre="romance">
  <movie>
    <title> movie1</title>
    <date> 1/2/2010 </date>
 </movie>
 <movie>
    <title> movie2</title>
    <date> 1/2/2010 </date>
 </movie>

add movies that each director made, grouped by genre.

Upvotes: 0

Views: 105

Answers (1)

Tobias Klevenz
Tobias Klevenz

Reputation: 1645

This is rather simple, let's assume you have an XML directors.xml:

<directors>
<director>
    <name>director 1</name>
    <born> 5/12/1992 </born>
    <nationality>Italian</nationality>
    <biography>some info on director</biography>
</director>
<director>
    <name>director 2</name>
    <born>21/2/1980</born>
    <nationality>french</nationality>
    <biography>a bit about me</biography>
</director>
</directors>

and an XML movies.xml:

<movies>
<movie>
    <title>movie1</title>
    <director> director 1 </director>
    <date> 1/2/2010 </date>
    <genre> Action</genre>
</movie>
<movie>
    <title>movie2</title>
    <director>director 1</director>
    <date> 1/2/2010 </date>
    <genre> romance</genre>
</movie>
<movie>
    <title> movie3</title>
    <director> director 2</director>
    <date> 1/2/2010 </date>
    <genre> Action</genre>
</movie>
</movies>

If you transform directors.xml with the following XSL Stylesheet, assuming movies.xml is in the same directory as the Stylesheet, you get your desired Output:

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

<xsl:output indent="yes"/>

<xsl:key name="movies-by-genre" match="movie" use="genre"/>

<xsl:template match="directors">
    <directors>
        <xsl:apply-templates select="director"/>
    </directors>
</xsl:template>

<xsl:template match="director">
    <xsl:variable name="name" select="normalize-space(name)"/>
    <xsl:copy>
        <xsl:copy-of select="*"/>
        <xsl:for-each
            select="document('movies.xml')//movie
            [count(. | key('movies-by-genre',genre)[1]) = 1]">
            <xsl:if test="key('movies-by-genre',genre)[normalize-space(director)=$name]">
                <movies genre="{genre}">
                    <xsl:for-each select="key('movies-by-genre',genre)">
                        <xsl:if test="normalize-space(director)=$name">
                            <xsl:apply-templates select="."/>
                        </xsl:if>
                    </xsl:for-each>
                </movies>
            </xsl:if>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

<xsl:template match="movie">
    <movie>
        <xsl:copy-of select="title | date"/>
    </movie>
</xsl:template>

</xsl:stylesheet>

You could also move the filename/path of movies.xml to a parameter and control that from your transformation arguments if you need to be more flexible.

Upvotes: 1

Related Questions