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
Conferences Close Tree View
+ Stylus Studio Feature Requests (1192)
+ Stylus Studio Technical Forum (14621)
+ Website Feedback (249)
- XSLT Help and Discussion (7625)
-> - How do I substitute element ty... (1)
-> + How does one add working days ... (4)
-> - Help, I have existing XLT and... (1)
-> + Need help on XSLT issue - (2)
-> + EDI to XML Conversion (7)
-> - XML To JSON Conversion using X... (1)
-> + Formatting Paragraphs to same ... (2)
-> - Grouping of records (1)
-> + Problems with xsd 1.1 (4)
-> + XML to HL7 mapping (3)
-> + XSLT 3 and Iterate (2)
-> + XSL-FO to PDF preview (3)
-> + java.lang.RuntimeException: Er... (2)
-> + Create Acroforms with Stylus X... (2)
-- [1-20] [21-40] [41-60] Next
+ XQuery Help and Discussion (2017)
+ Stylus Studio FAQs (159)
+ Stylus Studio Code Samples & Utilities (364)
+ Stylus Studio Announcements (113)
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()

   
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.