Help with a transform

Here should go questions about transforming XML with XSLT and FOP.
Kashman
Posts: 6
Joined: Thu Sep 14, 2006 1:45 am

Help with a transform

Post by Kashman »

Hello,
I have an XML from ADO recordset which looks like the sample below. I am transforming it to indent the z:rows based on ID and parent ID using the the XSL below.
I can nest the rows properly but I would like to have the final output look exactly like the original except the nested row.

I have a very limited knowledge of the XSLT, any help is appriciated. You can cut and paste the input XML and XSLT in oxygen to experiment



MY INPUT XML=======================================
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly">
<s:AttributeType name="ID" rs:number="1" rs:maydefer="true" rs:writeunknown="true">
<s:datatype dt:type="int" dt:maxLength="4" rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="ParentID" rs:number="2" rs:nullable="true" rs:maydefer="true" rs:writeunknown="true">
<s:datatype dt:type="int" dt:maxLength="4" rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="Title" rs:number="4" rs:nullable="true" rs:maydefer="true" rs:writeunknown="true">
<s:datatype dt:type="string" dt:maxLength="100"/>
</s:AttributeType>
<s:extends type="rs:rowbase"/>
</s:ElementType>
</s:Schema>
<rs:data>
<z:row ID="1" ParentID="0" Title="Security"/>
<z:row ID="30" ParentID="1" Title="Very nice"/>
<z:row ID="109" ParentID="30" Title="Using Event mg"/>
<z:row ID="185" ParentID="21" Title="Sub project 1"/>
<z:row ID="186" ParentID="185" Title="Sub project 1.1"/>
<z:row ID="187" ParentID="21" Title="Sub project 2"/>
<z:row ID="188" ParentID="187" Title="Sub project 2.1"/>
<z:row ID="189" ParentID="21" Title="Sub project 3"/>
<z:row ID="193" ParentID="1" Title="Sub project 4"/>
<z:row ID="194" ParentID="21" Title="Sub project 5"/>
<z:row ID="195" ParentID="0" Title="Sub project 6"/>
</rs:data>
</xml>
MY XSLT TRANSFOR======================================
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema" exclude-result-prefixes="s dt rs z" version="1.0">

<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="/xml/rs:data/z:row[not(@ParentID = /xml/rs:data/z:row/@ID)]"/>
</xsl:template>

<xsl:template match="z:row">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="/xml/rs:data/z:row[@ParentID = current()/@ID]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

MY INTENDED OUTPUT======================================
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly">
<s:AttributeType name="ID" rs:number="1" rs:maydefer="true" rs:writeunknown="true">
<s:datatype dt:type="int" dt:maxLength="4" rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="ParentID" rs:number="2" rs:nullable="true" rs:maydefer="true" rs:writeunknown="true">
<s:datatype dt:type="int" dt:maxLength="4" rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="Title" rs:number="4" rs:nullable="true" rs:maydefer="true" rs:writeunknown="true">
<s:datatype dt:type="string" dt:maxLength="100"/>
</s:AttributeType>
<s:extends type="rs:rowbase"/>
</s:ElementType>
</s:Schema>
<rs:data>
<z:row ID="1" ParentID="0" Title="Security">
<z:row ID="30" ParentID="1" Title="Very nice">
<z:row ID="109" ParentID="30" Title="Using Event mg"/>
</z:row>
<z:row ID="193" ParentID="1" Title="Sub project 4"/>
</z:row>
<z:row ID="185" ParentID="21" Title="Sub project 1">
<z:row ID="186" ParentID="185" Title="Sub project 1.1"/>
</z:row>
<z:row ID="187" ParentID="21" Title="Sub project 2">
<z:row ID="188" ParentID="187" Title="Sub project 2.1"/>
</z:row>
<z:row ID="189" ParentID="21" Title="Sub project 3"/>
<z:row ID="194" ParentID="21" Title="Sub project 5"/>
<z:row ID="195" ParentID="0" Title="Sub project 6"/>
</rs:data>
</xml>
jkmyoung
Posts: 89
Joined: Mon Mar 06, 2006 10:13 pm

Post by jkmyoung »

4 things here:
1. Key to match rows by parent.
2. Copy template for most nodes.
3. Seperate template for rs:data, so we can apply templates only to the top level rows.
4. Use of key in the z:row template

The key is not necessary, but will speed things up if you have a lot of rows.

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<xsl:key name="rowByParent" match="z:row" use="@ParentID"/>
<xsl:template match="rs:data">
<rs:data>
<xsl:apply-templates select="z:row[not (@ParentID = ../z:row/@ID)]"/>
</rs:data>
</xsl:template>
<xsl:template match="z:row">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="key('rowByParent', @ID)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Kashman
Posts: 6
Joined: Thu Sep 14, 2006 1:45 am

Post by Kashman »

Thanks, that did the trick.
Post Reply