Re: [xsl] Merging and sorting files from a list

Subject: Re: [xsl] Merging and sorting files from a list
From: Herve Dubreuil <hervedub@xxxxxxxxx>
Date: Wed, 25 Aug 2004 09:58:39 -0700 (PDT)
Hi,
I'm using sablotron to process the xslt and I'm getting an error while
loading the second file of my list (it takes the path of the first file
and adds its path and try to open it... which fails - like
/home/herve/work/testvcd/1.xml2.xml failed to open)
But I managed to write a script in 2 pass to transform the multiple
xmls into a vcd file (value change dump) using the munchen technique
(key and 
generate-id)
Here it is:

Pass1.xml

<?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>

<xsl:template match="component">
	<xsl:copy>
		<xsl:copy-of select="@*" />
		<xsl:for-each select="$docs">
			<xsl:apply-templates
select="document(@wavepath)/PreVCD/component/subpath">
				<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="*" />
	</xsl:copy>
</xsl:template>


<xsl:template match="dump">
	<xsl:copy>
		<xsl:for-each select="$docs">
			<xsl:apply-templates select="document(@wavepath)/PreVCD/dump/time">
				<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="*" />
	</xsl:copy>
</xsl:template>

</xsl:stylesheet>






Pass2.xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
	<xsl:output method="text" indent="no"/> 

	<xsl:key name="timelist" match="/PreVCD/dump/time" use="@t"/>
	<xsl:template match="/">
		<xsl:apply-templates select="PreVCD" />
	</xsl:template>


	<xsl:template match="PreVCD">
		<xsl:apply-templates select="component" />
		<xsl:apply-templates select="dump" />
	</xsl:template>

	<xsl:template match="component">
		<xsl:text>
$date

$end
$version
	TAST 0.6 July 2004 - TIMA Laboratory - CIS Group
	Contact: marc.renaudin@xxxxxxx
$end
$timescale
	1ns
$end
$scope module </xsl:text><xsl:value-of select="@name"/><xsl:text> $end
		</xsl:text>
		<xsl:apply-templates select="subpath" />

		<xsl:text>
$scope module $end
		</xsl:text>
	</xsl:template>

	
	<xsl:template match="subpath">
		<xsl:text>
$scope module </xsl:text><xsl:value-of select="path" /><xsl:text>
$end</xsl:text>

		<xsl:apply-templates select="subpath" />
		<xsl:apply-templates select="variable" />

		<xsl:text>
$scope module $end</xsl:text>
	</xsl:template>

	<xsl:template match="variable">
		<xsl:text>
$var wire </xsl:text><xsl:value-of select="@wireonbus" /> <xsl:text>
</xsl:text><xsl:value-of select="@symbol" /><xsl:text> </xsl:text>
<xsl:value-of select="@var" /> <xsl:text> $end</xsl:text>
	
	</xsl:template>	
	
	<xsl:template match="dump">
		<xsl:for-each
select="//time[generate-id(.)=generate-id(key('timelist', @t)[1])]">
			<xsl:sort select="@t" data-type="number"/>
			<xsl:text>
#</xsl:text><xsl:value-of select="@t" />
			<xsl:for-each select="key('timelist', @t)">
				<xsl:text>
</xsl:text>
				<xsl:value-of select="symbol/@value" /><xsl:value-of
select="symbol/@sign" />
			</xsl:for-each>	
		</xsl:for-each>
		<xsl:text>
</xsl:text>
	</xsl:template>
</xsl:stylesheet>
				

Thanks again for your time
Herve



--- cking <cking@xxxxxxxxxx> wrote:

> Herve,
> 
> I haven't seen any reply to your message, 
> so let me throw in what I found...
> 
> Monday, August 23, 2004 4:06 PM, you wrote:
> >
> > 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>
> > 
> [big snip]
> > 
> > The documents are not entirely merged.....
> > 
> > Thanks in advance if you manage to find the bug!
> 
> I did find a few bugs, but I also found that your stylesheet
> after all, just tries to copy nodes from the input files, without
> really doing anything to "merge" them (as you can see in
> the output you are getting).
> 
> I went looking in the FAQ, there's a chapter on merging:
> http://www.dpawson.co.uk/xsl/sect2/merge.html
> but all the examples are about merging _two_ input files,
> whereas you want to merge an arbitrary number of files...
> so maybe the problem is more complicated than you would
> think at first.
> 
> I'm far from an expert myself, so I didn't have much hope but
> I wanted to give it a try - and yes! I think I found a solution.
> It's not a generalized solution (only works with the organisation
> and tag names of your input files) and it involves several steps,
> but it does give an output like the one you wanted.
> 
> In short, the idea is to transform the input files in two passes.
> The first (pass1.xsl) collects all the nodes from all the input
> files, 
> sorts them and puts them into an intermediate output file. Then,
> the second pass stylesheet (pass2.xsl) merges the nodes.
> In fact, I needed a third pass because of the nested <subpath>
> elements (pass2 merges the component/subpath elements, then
> pass3 merges component/subpath/subpath).
> 
> Here's the stylesheets:
> (I posted all the files to my website so you can download them 
> there; that will save you some copy & paste)
> http://users.telenet.be/cking/webstuff/test/herve/
> 
> --- pass1.xsl ---
> 
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> 
>  <xsl:output method="xml" version="1.0" encoding="UTF-8"
> indent="yes"/>
> 
>  <xsl:variable name="docs"
> select="document(/listoffile/wave/@wavepath)"/>
> 
>  <xsl:strip-space elements="*"/>
> 
>  <xsl:template match="/">
>   <PreVCD>
>    <component name="stack">
>     <xsl:for-each select="$docs/PreVCD/component/subpath">
>      <xsl:sort select="@path" data-type="text" order="ascending"/>
>      <xsl:copy-of select="."/>
>     </xsl:for-each>
>    </component>
>    <dump>
>     <xsl:for-each select="$docs/PreVCD/dump/time">
>      <xsl:sort select="@t" data-type="number" order="ascending"/>
>      <xsl:copy-of select="."/>
>     </xsl:for-each>
>    </dump>
>   </PreVCD>
>  </xsl:template>
> 
> </xsl:stylesheet>
> 
> --- pass2.xsl ---
> 
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> 
>  <xsl:output method="xml" version="1.0" encoding="UTF-8"
> indent="yes"/>
> 
>  <xsl:strip-space elements="*"/>
> 
>  <xsl:template match="/PreVCD">
>   <PreVCD>
>    <xsl:apply-templates select="component"/>
>    <xsl:apply-templates select="dump"/>
>   </PreVCD>
>  </xsl:template>
> 
>  <xsl:template match="component">
>   <component name="{@name}">
>    <xsl:apply-templates select="subpath"/>
>   </component>
>  </xsl:template>
> 
>  <xsl:template match="dump">
>   <dump>
>    <xsl:apply-templates select="time"/>
>   </dump>
>  </xsl:template>
> 
>  <xsl:template match="subpath">
>   <xsl:variable name="path" select="@path"/>
>   <xsl:if test="not(preceding-sibling::subpath[@path=$path])">
>    <subpath path="{@path}">
>     <xsl:copy-of select="*"/>
>     <xsl:copy-of select="following-sibling::subpath[@path=$path]/*"/>
>    </subpath>
>   </xsl:if>
>  </xsl:template>
> 
>  <xsl:template match="time">
>   <xsl:variable name="t" select="@t"/>
>   <xsl:if test="not(preceding-sibling::time[@t=$t])">
>    <time t="{@t}">
>     <xsl:copy-of select="*"/>
>     <xsl:copy-of select="following-sibling::time[@t=$t]/*"/>
>    </time>
>   </xsl:if>
>  </xsl:template>
> 
> </xsl:stylesheet>
> 
> --- pass3.xsl ---
> 
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> 
>  <xsl:output method="xml" version="1.0" encoding="UTF-8"
> indent="yes"/>
> 
>  <xsl:strip-space elements="*"/>
> 
>  <xsl:template match="/PreVCD">
>   <PreVCD>
>    <xsl:apply-templates select="component"/>
>    <xsl:apply-templates select="dump"/>
>   </PreVCD>
>  </xsl:template>
> 
>  <xsl:template match="component">
>   <component name="{@name}">
>    <xsl:apply-templates select="subpath"/>
>   </component>
>  </xsl:template>
> 
>  <xsl:template match="dump">
>   <xsl:copy-of select="."/>
>  </xsl:template>
> 
>  <xsl:template match="subpath">
>   <subpath path="{@path}">
>    <xsl:apply-templates select="subpath"/>
>   </subpath>
>  </xsl:template>
> 
>  <xsl:template match="subpath/subpath">
>   <xsl:variable name="path" select="@path"/>
>   <xsl:if test="not(preceding-sibling::subpath[@path=$path])">
>    <subpath path="{@path}">
>     <xsl:copy-of select="*"/>
>     <xsl:copy-of select="following-sibling::subpath[@path=$path]/*"/>
>    </subpath>
>   </xsl:if>
>  </xsl:template>
> 
> </xsl:stylesheet>
> 
> Processed with Saxon 6.5.3:
>   saxon -o pass1.xml  list.xml  pass1.xsl
>   saxon -o pass2.xml  pass1.xml pass2.xsl
>   saxon -o output.xml pass2.xml pass3.xsl
> gives this output:
> 
> --- output.xml ---
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <PreVCD>
>    <component name="stack">
> 
=== message truncated ===

Current Thread