1

artworks.xml file:

<artworks>
  <artwork>
    <title>Adoration of the Magi</title>
    <author>GHIRLANDAIO, Domenico</author>
    <date>1487</date>
    <technique>Tempera on wood, diameter: 171 cm</technique>
    <location>Galleria degli Uffizi, Florence</location>
    <form>painting</form>
    <type>religious</type>
  </artwork>
</artworks>

author.xml file :

<authors>
  <author>
    <name>AMADEO, Giovanni Antonio</name>
    <born-died>b. ca. 1447, Pavia, d. 1522, Milano</born-died>
    <nationality>Italian</nationality>
   <biography>Giovanni Antonio Amadeo was an Italian early Renaissance sculptor</biography>
  </author>
<authors>

output.xml file :

<authors>
   <author>
      <name>AMADEO, Giovanni Antonio</name>
      <born-died>b. ca. 1447, Pavia, d. 1522, Milano</born-died>
      <nationality>Italian</nationality>
      <biography>Giovanni Antonio Amadeo was an Italian early Renaissance sculptor</biography>
     <artworks form="architecture">
        <artwork date="1473">
           <title>Faهade of the church</title>
           <technique>Marble</technique>
           <location>Certosa, Pavia</location>
        </artwork>
     </artworks>
   </author>
</authors>

The artworks.xml artwork author is a foreign key, referencing the authors.xml author entries.

I would like to merge these two XML documents and create a new XML file, in which the following information should be stored for each author: name, born-died, nationality, biography, and all artworks. The artworks are grouped by form and then sorted on date. For each artwork, title, technique, and location are stored

it is challanging : )

3 Answers 3

2

A complete solution:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="authors" select="document('author.xml')" />
    <xsl:variable name="artworks" select="/artworks/artwork" />
    <xsl:key name="byNameForm" match="artworks/artwork" 
                               use="concat(author, '|', form)" />
    <xsl:template match="/">
        <authors>
            <xsl:apply-templates select="$authors/*/author" />
        </authors>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="author">
        <author>
            <xsl:apply-templates />
            <xsl:apply-templates select="$artworks[author=current()/name]" />
        </author>
    </xsl:template>
    <xsl:template match="artworks/artwork" />
    <xsl:template match="artworks/artwork[generate-id()=
            generate-id(key('byNameForm', concat(author, '|', form))[1])]">
        <artworks form="{form}">
            <xsl:apply-templates 
                select="key('byNameForm', concat(author, '|', form))"
                mode="form">
                <xsl:sort select="date" data-type="number" />
            </xsl:apply-templates>
        </artworks>
    </xsl:template>
    <xsl:template match="artworks/artwork" mode="form">
        <artwork date="{date}">
            <xsl:apply-templates select="title|technique|location" />
        </artwork>
    </xsl:template>
</xsl:stylesheet>

Input:

<artworks>
    <artwork>
        <title>Adoration of the Magi</title>
        <author>GHIRLANDAIO, Domenico</author>
        <date>1486</date>
        <technique>Tempera on wood, diameter: 171 cm</technique>
        <location>Galleria degli Uffizi, Florence</location>
        <form>painting</form>
        <type>religious</type>
    </artwork>
    <artwork>
        <title>Something</title>
        <author>AMADEO, Giovanni Antonio</author>
        <date>1484</date>
        <technique>Marble</technique>
        <location>Mars</location>
        <form>sculpture</form>
        <type>religious</type>
    </artwork>
    <artwork>
        <title>Something2</title>
        <author>AMADEO, Giovanni Antonio</author>
        <date>1487</date>
        <technique>Glue</technique>
        <location>New York</location>
        <form>sculpture</form>
        <type>secular</type>
    </artwork>
    <artwork>
        <title>Something3</title>
        <author>AMADEO, Giovanni Antonio</author>
        <date>1482</date>
        <technique>Some tech</technique>
        <location>Mars</location>
        <form>paper</form>
        <type>religious</type>
    </artwork>
</artworks>

And:

<authors>
    <author>
        <name>AMADEO, Giovanni Antonio</name>
        <born-died>b. ca. 1447, Pavia, d. 1522, Milano</born-died>
        <nationality>Italian</nationality>
        <biography>Giovanni Antonio Amadeo was an Italian early
            Renaissance sculptor</biography>
    </author>
    <author>
        <name>GHIRLANDAIO, Domenico</name>
        <born-died>b. ca. 1447, Pavia, d. 1522, Venice</born-died>
        <nationality>Italian</nationality>
        <biography>N/A</biography>
    </author>
</authors>

Output:

<authors>
    <author>
        <name>AMADEO, Giovanni Antonio</name>
        <born-died>b. ca. 1447, Pavia, d. 1522, Milano</born-died>
        <nationality>Italian</nationality>
        <biography>Giovanni Antonio Amadeo was an Italian early
            Renaissance sculptor</biography>
        <artworks form="sculpture">
            <artwork date="1484">
                <title>Something</title>
                <technique>Marble</technique>
                <location>Mars</location>
            </artwork>
            <artwork date="1487">
                <title>Something2</title>
                <technique>Glue</technique>
                <location>New York</location>
            </artwork>
        </artworks>
        <artworks form="paper">
            <artwork date="1482">
                <title>Something3</title>
                <technique>Some tech</technique>
                <location>Mars</location>
            </artwork>
        </artworks>
    </author>
    <author>
        <name>GHIRLANDAIO, Domenico</name>
        <born-died>b. ca. 1447, Pavia, d. 1522, Venice</born-died>
        <nationality>Italian</nationality>
        <biography>N/A</biography>
        <artworks form="painting">
            <artwork date="1486">
                <title>Adoration of the Magi</title>
                <technique>Tempera on wood, diameter: 171 cm</technique>
                <location>Galleria degli Uffizi, Florence</location>
            </artwork>
        </artworks>
    </author>
</authors>

Edit: Updated to drive processing by author, so that even authors without any artworks will be included.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 Very good answer: traversing authors and grouping artworks by author+form. Some minors: if you are going to overwrite identity rule use <xsl:apply-templates select="$authors/*"/> instead of <authors> <xsl:apply-templates select="$authors/*/author" /> </authors> and if you are going to use push style you could do it all the way down like select="$artworks[generate-id()= generate-id(key('byNameForm', concat(current()/name, '|', form))[1])]" or you could use a second key for authors (that will add an example of keys on external documents).
1

This does the trick. It demonstrates a number of useful XSLT techniques - extending the identity transform, Muenchian grouping, using document() to merge data from a secondary document, suppressing output of empty elements - which made it worth working out in full:

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

  <xsl:variable name="authors"
                select="document('authors.xml')/authors/author"/>
  <xsl:variable name="artworks"
                select="/artworks/artwork"/>

  <!-- use Muenchian grouping to create a list of all distinct form values -->
  <xsl:key name="form-key"
           match="/artworks/artwork/form"
           use="."/>
  <xsl:variable name="forms"
                select="/artworks/artwork/form[generate-id(.) = generate-id(key('form-key', .)[1])]"/>

  <xsl:template match="/">
    <authors>
      <xsl:apply-templates select="$authors"/>
    </authors>
  </xsl:template>

  <xsl:template match="author">
    <xsl:variable name="artworks-for-author"
                  select="$artworks[author=current()/name]"/>
    <!-- only create an author element if it will contain at least one artwork -->
    <xsl:if test="$artworks-for-author">
      <author>
        <xsl:apply-templates select="name|born-died|nationality|biography"/>
        <xsl:for-each select="$forms">
          <!-- only create an artworks element if there's at least one artwork with this form -->
          <xsl:variable name="artworks-with-form"
                        select="$artworks-for-author[form=current()]"/>
          <xsl:if test="$artworks-with-form">
            <artworks form="{current()}">
              <xsl:apply-templates select="$artworks-with-form">
                <xsl:sort select="date"/>
              </xsl:apply-templates>
            </artworks>
          </xsl:if>
        </xsl:for-each>
      </author>
    </xsl:if>
  </xsl:template>

  <xsl:template match="artwork">
    <xsl:apply-templates select="title|technique|location"/>
  </xsl:template>

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

</xsl:stylesheet>

Comments

0

I got as far as the merging part of your problem using the document() function:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" />
    <xsl:template match="authors">
        <authors>
            <xsl:for-each select="author">
                <author>
                    <xsl:copy-of select="name" />
                    <xsl:copy-of select="born-died" />
                    <xsl:copy-of select="nationality" />
                    <xsl:copy-of select="biography" />
                    <xsl:variable name="name" select="name" />
                    <artworks>
                        <xsl:for-each select="document('artworks.xml')//artwork[author=$name]">
                        <artwork>
                            <xsl:copy-of select="title" />
                            <xsl:copy-of select="date" />
                            <xsl:copy-of select="technique" />
                            <xsl:copy-of select="location" />
                            <xsl:copy-of select="form" />
                            <xsl:copy-of select="type" />
                        </artwork>
                        </xsl:for-each>
                    </artworks>
                </author>
            </xsl:for-each>
        </authors>
    </xsl:template>
</xsl:stylesheet>

I used Intel's XSLT command line tool to do the transform. Here's the command line:

soaexslt2.exe merge.xsl authors.xml output.xml

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.