XML Editor
Sign up for a WebBoard account Sign Up Keyword Search Search More Options... Options
Chat Rooms Chat Help Help News News Log in to WebBoard Log in Not Logged in
Show tree view Topic
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Postnext
duncan skeltonSubject: Help! Transform flat XML records to complex grouping structure
Author: duncan skelton
Date: 11 May 2006 04:23 PM
Originally Posted: 11 May 2006 04:17 PM
Hi,
I'm new to XML, XSLT and Stylus Studio (evaluation of enterprise edition)

I have control over over a flat XML file containing information about software components. There are around 800 different components and each has data.

<components>
<component name="" owner="">
<layer name=""/>
<subsystem name=""/>
<module name=""/>
</component>
<component name="" owner="">
<layer name=""/>
<subsystem name=""/>
<module name=""/>
</component>
</components>

All of these components need to placed within a logical model - showing how they relate to each other.
My logical model is made up of layers, subsystems and modules - so I store that with each component.

My logical module has 7 layers; unbounded, optional subsystems whose names are unique within a layer; and mandatory unbounded numbers of modules whose names are unique within subsystems. So components are contained within modules; modules are contained (optionally) within subsystems; modules and subsystems are contained within layers.

I have a tool that will draw these relationships, and takes an XML file as input. The schema for this input file must look like...

<system_definition>
<layer>
<module>
<component name="" owner=""/>
<component name="" owner=""/>
</module>
<module>
<component name="" owner=""/>
<component name="" owner=""/>
<component name="" owner=""/>
</module>
</layer>
<layer>
<module>
<component name="" owner=""/>
</module>
<subsystem name="">
<module>
<component name="" owner=""/>
</module>
<module>
<component name="" owner=""/>
</module>
</subsystem>
</layer>
<layer>
<subsystem>
<module>
<component name="" owner=""/>
</module>
</subsystem>
</layer>
...
</system_definition>

So I am trying to generate this input file from my original XML file of flat component records.

I've reading around xsl:for-each-group - but am really struggling to make headway.

I'm looking for any pointers in the right direction. Is XSLT the right thing ? Should I instead by reading about XQuery ?

Once the file is created maintaining it will be easy. All pointers greatly appreciated - I'm sure this must be a standard pattern.

I own the orginal components XML data - so I have flexibility in its structure if that helps gain a more efficient XSL mapping.

thanks,
Duncan.

Postnext
duncan skeltonSubject: Help! Transform flat XML records to complex grouping structure
Author: duncan skelton
Date: 12 May 2006 07:07 AM
After a little research I am trying to play with..
xsl:for-each-group
...on some test data.

But I get the impression that it's not supported since it appears to get treated as a literal?!? Th syntax coloring of it is different than other xsl: statements ?

Is this xsl: statement supported ?

Postnext
(Deleted User) Subject: Help! Transform flat XML records to complex grouping structure
Author: (Deleted User)
Date: 12 May 2006 10:34 AM
Originally Posted: 12 May 2006 08:24 AM
Hi Duncan,

Here is a starter sample that creates part of the output you are looking for -

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

<xsl:key name="layerkey" match="/components/component/layer" use="@name"/>
<xsl:key name="subsystem" match="/components/component/subsystem" use="@name"/>

<xsl:template match="/">
<system_definition>
<xsl:apply-templates select="components/component/layer" mode="layer"/>
</system_definition>
</xsl:template>


<xsl:template name="layer" match="components/component/layer" mode="layer">
<xsl:if test="generate-id(.) = generate-id(key('layerkey', @name)[1])">
<xsl:element name="layer">
<xsl:attribute name="name" select="@name"/>
<xsl:apply-templates select="/" mode="subsystem">
<xsl:with-param name="layername" select="@name"/>
</xsl:apply-templates>
</xsl:element>
</xsl:if>
</xsl:template>

<xsl:template name="subsystem" match="/" mode="subsystem">
<xsl:param name="layername"/>
<xsl:for-each select="components/component/subsystem[generate-id(.) = generate-id(key('subsystem', @name)[1])]">
<xsl:message><xsl:value-of select="../layer/@name"/><xsl:value-of select="$layername"/></xsl:message>
<xsl:if test="$layername = ../layer/@name">
<xsl:element name="subsystem">
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>


I tried it with the following sample input xml



<?xml version="1.0"?>
<components>
<component name="" owner="">
<layer name="abc"/>
<subsystem name="layerabc"/>
<module name=""/>
</component>
<component name="" owner="">
<layer name="cde"/>
<subsystem name="layercde"/>
<module name=""/>
</component>
<component name="" owner="">
<layer name="cde"/>
<subsystem name="layerfgh"/>
<module name=""/>
</component>
</components>

Hope this helps.

Regards
Srini

Postnext
(Deleted User) Subject: Help! Transform flat XML records to complex grouping structure
Author: (Deleted User)
Date: 12 May 2006 08:46 AM
Regarding xsl:for-each-group, it is supported in XSLT 2.0. Stylus Studio 2006 supports XSLT 1.0 and XSLT 2.0. The Stylus Studio built-in XSLT processor is version aware.

If you change the
<xsl:stylesheet version="1.0"........

to

<xsl:stylesheet version="2.0"........

you should see the correct syntax coloring.

Regard
Srini

Posttop
duncan skeltonSubject: Help! Transform flat XML records to complex grouping structure
Author: duncan skelton
Date: 16 May 2006 07:36 AM
Hi Srinivas
First, thank you for your detailed response - it really set me off in a good direction. Over the weekend Ive progressed very well, and would have something to share with you, and some further questions.

First, I see now where your example code was going, and pursued it so that it generated the output I was looking for. This involved simply nesting further occurrences of the same pattern to sort by 4 levels of containment. (For each component that I have as source it is contained within a module, which is contained within a logicalsubset, within a logicalset within a layer).

But I found a shortcoming with this scheme that I couldn't find an easy solution for. That is the fact that my container IDs are only unique within that level. ie within LayerID=1 I can have a module called 'general', and within LayerID=2 I can have another module called 'general'.
Using the key approach you outline this second occurrence of the 'general' module present in a different layer is not processed, since it will never match the first occurrence of that module within the key.
I experimented and read around using multiple or compound identifiers in the key() function but couldnt understand how to get that to work.

In the meantime then I came across an approach using for-each-group in xslt2.0.

This approach works a treat and is simpler to code and to read.

But I found that I had to code the whole lot in a single template. Ideally I wanted to split the processing of each level of containment into it's own template. That didnt work because I need to act on a node-set, not individual nodes that are passed to a template.

So I looked at user-defined functions - where I could pass a parameter that is a node list, extracted from current-group()
This did the right thing, but I found that for some reason the <xsl:element> and <xsl:attribute> tags within this function were never being output - only the leaf nodes of the component data. I couldnt understand this at all and assume there is some loss of context when calling a function as opposed to keeping everything together inline in a single template.

This is a shame. A couple of the containment levels (logicalset and logicalsubset) are optional. This means I dont want to output elements for these items, and skip straight to the mandatory Module data. This meant using conditional branching and replicating chunks of code.

I think that if I can get the function calls working correctly that the code will be greatly simplified and more readable.

Do you have any ideas of how I could do this, or alternatively why I was seeing the behaviour that I was ?

Ive attached the XSLT2.0 code that I finally got working.

kind regards
duncan.


Documentv2transform.xsl
Grouping using for-each-group()

 
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Download A Free Trial of Stylus Studio 6 XML Professional Edition Today! Powered by Stylus Studio, the world's leading XML IDE for XML, XSLT, XQuery, XML Schema, DTD, XPath, WSDL, XHTML, SQL/XML, and XML Mapping!  
go

Log In Options

Site Map | Privacy Policy | Terms of Use | Trademarks
Stylus Scoop XML Newsletter:
W3C Member
Stylus Studio® and DataDirect XQuery ™are from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2016 All Rights Reserved.