[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] Conditioned merge of XML from two files


Subject: RE: [xsl] Conditioned merge of XML from two files
From: cknell@xxxxxxxxxx
Date: Wed, 27 Jul 2005 17:13:38 -0400

Karl, the next time you think you need an <xsl:for-each>, stop. Stand up, walk around a little bit, maybe take a cold shower, and think again. Almost the only time you need one is if you are sorting or grouping. It is procedural programmer's security blanket. Let it go.

Now, assuming that each <loc_id> in the locations XML file is unique, this stylesheet will do what you asked. I couldn't figure out what the template matching the <event> element was supposed to do, so I took the liberty of assuming that you meant that to be a <book> element and proceeded accordingly. I named the locations file "kkoch5.xml" on my file system. This stylesheet should do the trick. 

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes" encoding="UTF-8" />
 <xsl:strip-space elements="*" />
 <xsl:variable name="locs" select="document('kkoch5.xml')" />

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

 <xsl:template match="bookshelf">
  <xsl:apply-templates />
 </xsl:template>

 <xsl:template match="book">
  <xsl:copy>
   <xsl:apply-templates />
  </xsl:copy>
 </xsl:template>

 <xsl:template match="location">
  <xsl:copy>
   <xsl:apply-templates />
   <xsl:copy-of select="$locs/locations/location[loc_id = loc_id]/*[local-name() != 'loc_id']" />
  </xsl:copy>
 </xsl:template>

 <xsl:template match="id|title|desc|loc_id">
  <xsl:copy-of select="." />
 </xsl:template>


</xsl:stylesheet>
-- 
Charles Knell
cknell@xxxxxxxxxx - email



-----Original Message-----
From:     Karl Koch <TheRanger@xxxxxxx>
Sent:     Wed, 27 Jul 2005 22:43:42 +0200 (MEST)
To:       "Mulberry list" <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Subject:  [xsl] Conditioned merge of XML from two files

Hello Experts,

I have a question resulting from a problem I could not resolve. I have one
XML file which contains information about books (books.xml). I have a second
xml file which contains information about book locations (locations.xml). I
have a location id in books.xml and each location in locations.xml has a
location id of the same sort. I would like to have a stylesheet that looks
up the ids from books.xml in locations.xml and copies the location into a
certain position of the book. After the transformation, each book in
books.xml has a location XML stubstructure.

Here example data from both XML files:

(books.xml - only one book to keep it short)

<bookshelf>
  <book>
    <id>1</id>
    <title>Alice in Wonderland</title>
    <desc>Alice is tumbling down the rabit hole.</desc>
    <location>
      <loc_id>L2</loc_id>
    </location>
  </book>
  ... and many many more ...
</bookshelf>


(locations.xml - only one location to keep it short)

<locations>
  <location>
    <loc_id>L1</loc_id>
    <name>Location 1</name>
    ... many more attributes...
  </location>
  .. many more locations
</locations>


After the transformation I wouild like to have the following:

<bookshelf>
  <book>
    <id>1</id>
    <title>Alice in Wonderland</title>
    <desc>Alice is tumbling down the rabit hole.</desc>
    <location>
      <loc_id>L1</loc_id>
      <name>Location 1</name>
      ... many more attributes...
    </location>
  </book>
  ... and many many more ...
</bookshelf>


I have developed the following XSLT:


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="UTF-8" />
  <xsl:strip-space elements="*" />
  <xsl:variable name="locationFile" select="document('locations.xml')" />
  
  <!-- Match with root -->
  <xsl:template match="/">
    <bookshelf>
    	<xsl:for-each select="/bookshelf/book">
     		<book>
	        		<xsl:apply-templates select="." />
	        </book>
      	</xsl:for-each>
    </bookshelf>    
   </xsl:template>

  <xsl:template match="event">
    	<xsl:copy-of select="./id" />
    	<xsl:copy-of select="./title" />
    	<xsl:copy-of select="./desc" />
    	<location>
    		<xsl:copy-of
select="$locationFile/locations/location/*[.//location/loc_id=$locationFile/locations//location/id]"/>
    	</location>
   </xsl:template>
       	
</xsl:stylesheet>



.. however, it does not work: What is wrong? I guess it is far from optimal
anyway so I am happy to get completely different solutions as well. As you
can see in the stylesheet, I would like to "hardcode" the lcoations file,
but provide the book data as parameter (for flexiblity reasons).

Any form of help would be highly appreciated.

Kind regards,
Karl





-- 
5 GB Mailbox, 50 FreeSMS http://www.gmx.net/de/go/promail
+++ GMX - die erste Adresse f|r Mail, Message, More +++


Current Thread
Keywords