Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old August 28th, 2013, 02:02 AM
Registered User
 
Join Date: Aug 2013
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default How to Optimize XSLT for Referencing data in other XMLs

Hi All,

In an input XML file, along with Static Columns, columns expecting data from other files (reference)is also available. But for each reference, the input xml has separate row with same ID or UID.

The output file has to have all references and relations in one row (based on the ID or UID)

I wrote the XSLT for this transformation also. This XSLT is faster when the row count is less (< 100 or < 200). But, as the count grows, the output xml generation taking long time (for count of 1000 rows, around 30 mins).

I am using

Code:
<xsl:for-each select="z:row/@ID[generate-id() = generate-id(key('UniqueID',.))]">
in the XSLT. Because for the same ID in each row of input xml, it has to check for multiple references (like section) and relations (like Child) and populate the same as columns

Input Raw XML File.

Code:
<xml xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:z="#RowsetSchema">
<rs:data>
    <z:row UID="PARENT_001_1221AD_A878" GroupID="" GroupRel="" ID="37" Name="Outer Asset Details" RelProduct="Line1" RelUID="CHILD1_101_9899_9POOU99" RelName="CHILD1" RelType="Child" Size="22"/>
    <z:row UID="PARENT_001_1221AD_A878" GroupID="" GroupRel="" ID="37" Name="Outer Asset Details" RelProduct="Line1" RelUID="CHILD2_201_5646546_9890PBS" RelName="CHILD1" RelType="Child" Size="22"/>
    <z:row UID="PARENT_001_1221AD_A878" GroupID="" GroupRel="" ID="37" Name="Outer Asset Details" RelProduct="Line1" RelUID="SEC_999_99565_998AFSD" RelName="Hydraulic Section" RelType="Section" Size="22"/>
</rs:data>
Child.xml

Code:
<Child xsi:noNamespaceSchemaLocation="../XSD/Child.xsd" FILE="Child" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Row UID="CHILD1_101_9899_9POOU99">
    <Name>CHILD1</Name>
    <Description>This has details about the Hydraulic sections of the automobile</Description>
</Row>
<Row UID="CHILD2_201_5646546_9890PBS">
    <Name>CHILD2</Name>
    <Description>This has details about the manual sections of the automobile</Description>
</Row>
Section.xml

Code:
<Section xsi:noNamespaceSchemaLocation="../XSD/Section.xsd" FILE="Section" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Row UID="SEC_999_99565_998AFSD">
    <Name>Hydraulic Section</Name>
    <Description>This has details about the Sections in which the Hydraulic Systems are used.</Description>
</Row>
XSLT File
Code:
<xsl:stylesheet version="1.0" 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 z rs msxsl" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="UniqueID" match="z:row/@ID" use="."/>
<xsl:template match="/">
    <Parent xsi:noNamespaceSchemaLocation="../XSD/Parent.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" FILE="Parent">
        <xsl:for-each select="xml">
            <xsl:apply-templates select="rs:data"/>
        </xsl:for-each>
    </Parent>
</xsl:template>
<xsl:template match="rs:data">
    <xsl:for-each select="z:row/@ID[generate-id() = generate-id(key('UniqueID',.))]">
        <xsl:variable name="FRId">
            <xsl:value-of select="current()"/>
        </xsl:variable>
        <xsl:variable name="curNSet" select="//z:row[@ID=$FRId]"/>
        <xsl:copy-of select="current()"/>
        <Record>
            <xsl:attribute name="UID"><xsl:value-of select="$curNSet/@UID"/></xsl:attribute>
            <xsl:element name="Size">
                <xsl:value-of select="$curNSet/@Size"/>
            </xsl:element>
            <xsl:element name="Child">
                <xsl:apply-templates select="$curNSet[@RelType='Child']" mode="Relations">
                    <xsl:with-param name="RelType" select="'Child'"/>
                    <xsl:with-param name="DstFileName" select="'../Files/Child.xml'"/>
                </xsl:apply-templates>
            </xsl:element>
            <xsl:element name="Section">
                <xsl:apply-templates select="$curNSet[@RelType='Section']" mode="References">
                    <xsl:with-param name="RelType" select="'Section'"/>
                    <xsl:with-param name="DstFileName" select="'../Files/Section.xml'"/>
                </xsl:apply-templates>
            </xsl:element>
        </Record>
    </xsl:for-each>
</xsl:template>
<xsl:template match="z:row" mode="Relations">
    <xsl:param name="RelType"/>
    <xsl:param name="DstFileName"/>
    <xsl:element name="{$RelType}">
        <xsl:attribute name="DestinationKey"><xsl:value-of select="@RelUID"/></xsl:attribute>
        <xsl:attribute name="RelFilePath"><xsl:value-of select="$DstFileName"/></xsl:attribute>
        <xsl:attribute name="SequenceNumber"><xsl:value-of select="position()"/></xsl:attribute>
        <xsl:value-of select="@RelName"/>
    </xsl:element>
</xsl:template>
<xsl:template match="z:row" mode="References">
    <xsl:param name="DstFileName"/>
    <xsl:attribute name="DestinationKey"><xsl:value-of select="@RelUID"/></xsl:attribute>
    <xsl:attribute name="RelFilePath"><xsl:value-of select="$DstFileName"/></xsl:attribute>
    <xsl:attribute name="SequenceNumber"><xsl:value-of select="position()"/></xsl:attribute>
    <xsl:value-of select="@RelName"/>
</xsl:template>
Output.xml

Code:
<Parent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../XSD/Parent.xsd" FILE="Parent" ID="37">
<Record UID="PARENT_001_1221AD_A878">
    <Size>22</Size>
    <Child>
        <Child DestinationKey="CHILD1_101_9899_9POOU99" RelFilePath="../Files/Child.xml" SequenceNumber="1">CHILD1</Child>
        <Child DestinationKey="CHILD2_201_5646546_9890PBS" RelFilePath="../Files/Child.xml" SequenceNumber="2">CHILD1</Child>
    </Child>
    <Section DestinationKey="SEC_999_99565_998AFSD" RelFilePath="../Files/Section.xml" SequenceNumber="1">Hydraulic Section</Section>
</Record>
Please help me in optimizing the XSLT, so that the output file is generated faster

Thanks
Ramm
 
Old August 28th, 2013, 03:19 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

You've defined a key for accessing rows quickly by ID, so instead of this:

Code:
<xsl:variable name="curNSet" select="//z:row[@ID=$FRId]"/>
you can use the key:

Code:
<xsl:variable name="curNSet" select="key('UniqueID', $FRId)"/>
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old August 28th, 2013, 03:51 AM
Registered User
 
Join Date: Aug 2013
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thanks Micheal for the suggested change.
Observations,
1. Just updating the XSLT with "key('UniqueID', $FRId)", I am seeing all the rows blank.
2. I tested in XMLSPY 2010 with the changes suggested and took 20 seconds. Prior to this change it used close to 30 seconds.

I have one question for you.

I am using a web application and on click of button, the XSLT is applied on the input XML (fetched from SQL DB) using Saxon 7.9.1. Now, this is consuming close to 43 mins for this file alone having 8000 rows. Please advice on this.

Thanks
Ramm

Last edited by Krishna410; August 28th, 2013 at 03:54 AM.. Reason: Grammatical
 
Old August 28th, 2013, 04:40 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Saxon 7.9.1 is an absurdly old release to be using. It predates the XSLT 2.0 specification! First thing to do is to get yourself up to date.

I failed to notice that your key was defined as

Code:
<xsl:key name="UniqueID" match="z:row/@ID" use="."/>
rather than the more conventional

Code:
<xsl:key name="UniqueID" match="z:row" use="@ID"/>
This means that instead of

Code:
<xsl:variable name="curNSet" select="key('UniqueID', $FRId)"/>
you should use

Code:
<xsl:variable name="curNSet" select="key('UniqueID', $FRId)/.."/>
Note: if I were doing this, I would rewrite the stylesheet to use xsl:for-each-group rather than Muenchian grouping, but that's up to you.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference





Similar Threads
Thread Thread Starter Forum Replies Last Post
xslt footnotes from 2 xmls sunnykeerthi XSLT 0 April 12th, 2013 10:23 AM
XSLT from two XMLs sunnykeerthi XSLT 1 April 10th, 2013 01:14 PM
Referencing data from another table to generate SendMail Data Macro G_S Access 0 November 13th, 2012 11:12 PM
XML element referencing to other xmls alexhinz XSLT 0 February 8th, 2007 09:32 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.