[xsl] Merging and sorting files from a list

Subject: [xsl] Merging and sorting files from a list
From: Herve Dubreuil <hervedub@xxxxxxxxx>
Date: Mon, 23 Aug 2004 07:06:18 -0700 (PDT)
Hi all,
I've been trying to get this to work for around a week and I can't seem
to find the solution.

I'm parsing a list of file (from list.xml) that have the same
architecture and I want to sort and merge them.

list.xml:
<?xml version="1.0" ?>
<listoffile>
	<wave wavepath="1.xml" />
	<wave wavepath="2.xml" />
	<wave wavepath="3.xml" />
	<wave wavepath="4.xml" />
</listoffile>

1.xml:
<?xml version="1.0"?>
<PreVCD>
	<component name="stack">
		<subpath path="stack_environment">
			<subpath path="test">
				<variable var="ins" symbol="!" wireonbus="1"/>
			</subpath>
		</subpath>
	</component>
	<dump>
		<time t="5">
			<symbol sign="!" value="0"/>
		</time>
		<time t="10">
			<symbol sign="!" value="1"/>
		</time>
		<time t="25">
			<symbol sign="!" value="0"/>
		</time>
	</dump>
</PreVCD>

(same for 2.xml, 3.xml etc...)

and I want the output to look like this:

<?xml version="1.0"?>
<PreVCD>
	<component name="stack">
		<subpath path="stack_environment">
			<subpath path="test">
				<variable var="ins" symbol="!" wireonbus="1"/>
				<variable var="ins" symbol="@" wireonbus="2"/>
			</subpath>
		<subpath path="stack_behavior">
                        <subpath path="test2">
				<variable var="ins" symbol="#" wireonbus="1"/>
			</subpath>                        
		</subpath>
	</component>
	<dump>
		<time t="5">
			<symbol sign="!" value="0"/>
			<symbol sign="@" value="0"/>
		</time>
		<time t="10">
			<symbol sign="!" value="1"/>
			<symbol sign="#" value="0"/>
		</time>
		<time t="15">
			<symbol sign="@" value="1"/>
			<symbol sign="#" value="1"/>
		</time>
	</dump>
</PreVCD>


For this, I created this xslt:
<?xml version="1.0" ?>
<!-- We first start by defining the xsl/xml header -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"
encoding="UTF-8"/>
		
<!-- We load into a variable the list of file to parse -->
<xsl:variable name="docs" select="/listoffile/wave"/>


<!-- we select the first file -->
<xsl:template match="listoffile"> 
	<xsl:apply-templates select="wave[1]"/>
</xsl:template>


<xsl:template match="wave">
	<xsl:variable name="wavepath" select="@wavepath"/>
	<xsl:for-each select="document($wavepath)">
		<xsl:apply-templates select="PreVCD"/>
	</xsl:for-each>
</xsl:template>
		

<!--We apply the template component to the node component and the same
to dump -->
<xsl:template match="PreVCD">
	<xsl:copy>
		<xsl:apply-templates select="component" />
		<xsl:apply-templates select="dump" />
	</xsl:copy>
</xsl:template>

<!-- In the template component, we copy <component>, then add its
attribute (name) and then copy the subpathes -->
<xsl:template match="component">
	<xsl:copy>
		<xsl:for-each select="$docs[position() >1]">
			<xsl:copy-of select="document(@wavepath)/PreVCD/component/*" />
			<xsl:apply-templates
select="document(@wavepath)/PreVCD/component/subpath |$
docs/PreVCD/component/subpath[not(@path = current()/subpath/@path)]">
				<xsl:sort select="@path" data-type="text" order="ascending" />
			</xsl:apply-templates>
		</xsl:for-each>	
	</xsl:copy>
</xsl:template>

<xsl:template match="subpath">
	<xsl:variable name="curPath" select="@path" />
	<xsl:copy>
		<xsl:copy-of select="@*" />
		<xsl:copy-of select="* | $docs/PreVCD/component/subpath[@path
=$curPath]/*" />
	</xsl:copy>
</xsl:template>


<!-- In Dump, we have to regroup elements and sort by time -->
<xsl:template match="dump">
	<xsl:copy>
		<xsl:for-each select="$docs">
			<xsl:apply-templates select="document(@wavepath)/PreVCD/dump/time |
$docs/PreVCD/dump/time[not(@t = current()/time/@t)]">
				<xsl:sort select="@t" data-type="number" order="ascending" />
			</xsl:apply-templates>
		</xsl:for-each>
	</xsl:copy>
</xsl:template>

<xsl:template match="time">
	<xsl:variable name="curTime" select="@t" />
	<xsl:copy>
		<xsl:copy-of select="@*" />
		<xsl:copy-of select="* | $docs/PreVCD/dump/time[@t =$curTime]/*" />
	</xsl:copy>
</xsl:template>

</xsl:stylesheet>



But I can't get it to work properly. It seems like there is a problem
with the $docs/PreVCD

Here is the output I'm having
<?xml version="1.0" encoding="UTF-8"?>
<PreVCD>
  <component>
    <subpath path="stack_behavior">
			<variable var="i" symbol="@" wireonbus="1"/>
		</subpath>
    <subpath path="stack_behavior">
      <variable var="i" symbol="@" wireonbus="1"/>
    </subpath>
    <subpath path="stack_environment">
			<variable var="ins" symbol="#" wireonbus="2"/>
		</subpath>
    <subpath path="stack_environment">
      <variable var="ins" symbol="#" wireonbus="2"/>
    </subpath>
    <subpath path="stack_environment">
			<variable var="ins" symbol="#" wireonbus="2"/>
		</subpath>
    <subpath path="stack_environment">
      <variable var="ins" symbol="#" wireonbus="2"/>
    </subpath>
  </component>
  <dump>
    <time t="5">
      <symbol sign="!" value="0"/>
    </time>
    <time t="10">
      <symbol sign="!" value="1"/>
    </time>
    <time t="25">
      <symbol sign="!" value="0"/>
    </time>
    <time t="0">
      <symbol sign="@" value="0"/>
    </time>
    <time t="5">
      <symbol sign="@" value="1"/>
    </time>
    <time t="10">
      <symbol sign="@" value="0"/>
    </time>
    <time t="20">
      <symbol sign="@" value="1"/>
    </time>
    <time t="0">
      <symbol sign="#" value="0"/>
    </time>
    <time t="15">
      <symbol sign="#" value="1"/>
    </time>
    <time t="20">
      <symbol sign="#" value="0"/>
    </time>
    <time t="0">
      <symbol sign="#" value="0"/>
    </time>
    <time t="15">
      <symbol sign="#" value="1"/>
    </time>
    <time t="20">
      <symbol sign="#" value="0"/>
    </time>
  </dump>
</PreVCD>

The documents are not entirely merged.....

Thanks in advance if you manage to find the bug!

Herve

Current Thread