xsl-list
[Top] [All Lists]

Re: Merging and sorting files from a list

2004-08-25 09:58:39
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(_dot_)renaudin(_at_)imag(_dot_)fr
$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(_at_)telenet(_dot_)be> 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="{(_at_)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[(_at_)path=$path])">
   <subpath path="{(_at_)path}">
    <xsl:copy-of select="*"/>
    <xsl:copy-of select="following-sibling::subpath[(_at_)path=$path]/*"/>
   </subpath>
  </xsl:if>
 </xsl:template>

 <xsl:template match="time">
  <xsl:variable name="t" select="@t"/>
  <xsl:if test="not(preceding-sibling::time[(_at_)t=$t])">
   <time t="{(_at_)t}">
    <xsl:copy-of select="*"/>
    <xsl:copy-of select="following-sibling::time[(_at_)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="{(_at_)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="{(_at_)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[(_at_)path=$path])">
   <subpath path="{(_at_)path}">
    <xsl:copy-of select="*"/>
    <xsl:copy-of select="following-sibling::subpath[(_at_)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 ===



<Prev in Thread] Current Thread [Next in Thread>