Re: [xsl] How to get node with maximum child nodes??

Subject: Re: [xsl] How to get node with maximum child nodes??
From: Mukul Gandhi <mukulw3@xxxxxxxxx>
Date: Tue, 26 Aug 2003 01:02:41 -0700 (PDT)
Hi Dipesh ,
  I have deviated from your solution and have produced
the following XSL. It illustrates the concept. I hope
you can take some ideas from it. And I also hope I
understood your problem correctly.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:xalan="http://xml.apache.org/xalan";>

<xsl:output method="text" version="1.0"
encoding="UTF-8" indent="yes"/>
	
<xsl:template match="/">
   <xsl:variable name="treefrag1">
     <tables>
	<xsl:apply-templates select="//CLASS"/>
     </tables>
    </xsl:variable>
   <xsl:variable name="treefrag2">
     <tables> 
       <xsl:for-each
select="xalan:nodeset($treefrag1)/tables/table">
	<xsl:sort select="no_of_columns" data-type="number"
order="descending"/>
	<table>
	  <name>
	     <xsl:value-of select="name"/>
	  </name>
	  <no_of_columns>
	    <xsl:value-of select="no_of_columns"/>
	  </no_of_columns>
	 </table>
	</xsl:for-each>
      </tables>
    </xsl:variable>
		
    <xsl:value-of
select="xalan:nodeset($treefrag2)/tables/table[1]/name"
/><xsl:text>  :  </xsl:text><xsl:value-of
select="xalan:nodeset($treefrag2)/tables/table[1]/no_of_columns"
/> 

</xsl:template>
	
<xsl:template match="//CLASS">
  <table>
    <name>
      <xsl:value-of select="@NAME"/>
    </name>
    <no_of_columns>
      <xsl:value-of
select="count(OBJECT[1]/ATTRIBUTE)"/>
    </no_of_columns>
  </table>
</xsl:template>

</xsl:stylesheet>

The ideas behind my solution are --
1. I iterate through all the CLASS elements using //
and store its *NAME attribute value* and the no. of
instances of ATTRIBUTE elements in 1st OBJECT
element(I am assuming that all OBJECT elements of a
particular CLASS will have same no. of ATTRIBUTE
elements). I store this result(tree fragment) in a
variable treefrag1.

2. I then iterate through treefrag1 (after converting
it to a nodeset, using Xalan nodeset extension
function) and *sort the records in descending order
based on no of columns*.

3. I then access the 1st row of this sorted result.
This way I am able to find the table with maximum no.
of columns.

Regards,
Mukul


--- Dipesh Khakhkhar <dkhakhkh@xxxxxxxxxxxxxxx> wrote:
> Hi,
> 
> I am having the following xml Document
> 
> Xml
> ====
> <?xml version="1.0" encoding="UTF-8"?>
> <AEXDATAEXTRACT DTD_VERSION="2.2"
> EXTRACT_START_DATETIME="1/9/2003 4:49:39 PM" 
> EXTRACT_TYPE="FULL" EXTRACT_COLLECTION="">
> <RESOURCE_TYPE
> GUID="{493435f7-3b17-4c4c-b07f-c23e7ab7781f}"
> NAME="Computer" 
> DESCRIPTION="Asset Type definition for Computer"
> SOURCE="Asset" 
> CREATED_DATE="7/16/2002 5:22:23 PM"
> MODIFIED_DATE="9/23/2002 2:17:48 PM" 
> DELETED="0">
> <RESOURCE
> GUID="{C116FCBF-5B94-4F15-BF95-5795DBD384CD}"
> NAME="ALTIRISTEST_CPQ" 
> SOURCE="" SITE_CODE="756win" DOMAIN="FIDD"
> SYSTEM_TYPE="Win32" 
> OS_NAME="Microsoft Windows XP"
> OS_TYPE="Professional" OS_VERSION="5.1" 
> OS_REVISION="Service Pack 1" LAST_LOGON_USER=""
> LAST_LOGON_DOMAIN="">
> <INVENTORY>
> <ASSET>
> <IDENTIFICATION>
> <ATTRIBUTE NAME="Name">ALTIRISTEST_CPQ</ATTRIBUTE>
> <ATTRIBUTE NAME="Domain">FIDDOMRTLSLC</ATTRIBUTE>
> <ATTRIBUTE NAME="Altkey1" NULL="FALSE" />
> <ATTRIBUTE
> NAME="Altkey2">00-02-A5-1A-67-A6</ATTRIBUTE>
> </IDENTIFICATION>
> 
> <CLASS NAME="Client_Agent">
> <OBJECT>
> <ATTRIBUTE NAME="Agent Name">Altiris eXpress NS
> Client</ATTRIBUTE>
> <ATTRIBUTE NAME="Product
> Version">5.5.0.517</ATTRIBUTE>
> <ATTRIBUTE NAME="Build Number">517</ATTRIBUTE>
> <ATTRIBUTE NAME="Install Path">C:\Program
> Files\Altiris\eXpress\NS 
> Client</ATTRIBUTE>
> </OBJECT>
> <OBJECT>
> <ATTRIBUTE NAME="Agent Name">Altiris eXpress
> Inventory Solution</ATTRIBUTE>
> <ATTRIBUTE NAME="Product
> Version">5.5.0.424</ATTRIBUTE>
> <ATTRIBUTE NAME="Build Number">424</ATTRIBUTE>
> <ATTRIBUTE NAME="Install Path">C:\Program
> Files\Altiris\eXpress\NS 
> Client\Software Delivery\Software 
>
Packages\{01B54EB5-3679-4C73-9E10-E169D5A5EC59}</ATTRIBUTE>
> </OBJECT>
> </CLASS>
> <CLASS NAME="Inventory_Results">
> <OBJECT>
> <ATTRIBUTE NAME="Collection Time">1/9/2003 3:06:56
> AM</ATTRIBUTE>
> <ATTRIBUTE NAME="File Count">3</ATTRIBUTE>
> <ATTRIBUTE NAME="Total Size">139271</ATTRIBUTE>
> <ATTRIBUTE NAME="Version">5: 5: 0: 423</ATTRIBUTE>
> 
> </OBJECT>
> </CLASS>
> </ASSET>
> </INVENTORY>
> </RESOURCE>
> 
> <RESOURCE
> GUID="{C116FCBF-5B94-4F15-BF95-5795DBD384CD}"
> NAME="ALTIRISTEST_CPQ" 
> SOURCE="" SITE_CODE="756win" DOMAIN="FIDD"
> SYSTEM_TYPE="Win32" 
> OS_NAME="Microsoft Windows XP"
> OS_TYPE="Professional" OS_VERSION="5.1" 
> OS_REVISION="Service Pack 1" LAST_LOGON_USER=""
> LAST_LOGON_DOMAIN="" 
> AdditionalCol="Additional Col Value">
> <INVENTORY>
> <ASSET>
> <CLASS NAME="Client_Agent">
> <OBJECT>
> <ATTRIBUTE NAME="Agent Name">Altiris eXpress NS
> Client</ATTRIBUTE>
> <ATTRIBUTE NAME="Product
> Version">5.5.0.517</ATTRIBUTE>
> <ATTRIBUTE NAME="Extra Column">Extra COlumn
> Value1</ATTRIBUTE>
> <ATTRIBUTE NAME="Build Number">517</ATTRIBUTE>
> <ATTRIBUTE NAME="Install Path">C:\Program
> Files\Altiris\eXpress\NS 
> Client</ATTRIBUTE>
> </OBJECT>
> <OBJECT>
> <ATTRIBUTE NAME="Agent Name">Altiris eXpress
> Inventory Solution</ATTRIBUTE>
> <ATTRIBUTE NAME="Product
> Version">5.5.0.424</ATTRIBUTE>
> <ATTRIBUTE NAME="Extra Column">Extra COlumn
> Value2</ATTRIBUTE>
> <ATTRIBUTE NAME="Build Number">424</ATTRIBUTE>
> <ATTRIBUTE NAME="Install Path">C:\Program
> Files\Altiris\eXpress\NS 
> Client\Software Delivery\Software 
>
Packages\{01B54EB5-3679-4C73-9E10-E169D5A5EC59}</ATTRIBUTE>
> </OBJECT>
> </CLASS>
> </ASSET>
> </INVENTORY>
> </RESOURCE>
> </RESOURCE_TYPE>
> </AEXDATAEXTRACT>
> 
>
---------------------------------------------------------------------
> 
> In the above xml document I CLASS node corresponds
> to the table i the database 
> and OBJECTS are the records within that table.
> ATTRIBUTE node contains the 
> names of the columns and their values.
> 
> As shown in the above example, in the input document
> there can be same table 
> with unequal number of columns. I have to find the
> table name with maximum 
> columns.
> 
> I have written the following xsl to do this. I have
> got the node (CLASS 
> NODE)having a node (Row or Record) having maximum
> column. To get this node 
> name i am storing the unique identifier for this
> node i.e. I am storing 
> generate-id for this node. But I am getting generate
> id for both the CLASS 
> node in the above example (I am using xml spy's
> debugger to go step by step). 
> The same construct i am using to find a node with
> maximum attributes in the 
> document. I got only one id for it.
> 
> Had i take wrong approach to do this or something
> else is wrong ?
> 
> Second problem is printing the values for the
> attribtues. I have written the 
> match template construct and there I need to print
> value corresponding to the 
> column headers which are stored in the variable. I
> am not able to write 
> suitable construct to do this. Please tell me how do
> i do this. I have tried 
> to use name function to do this but it is giving me
> invalid Xpath expression.
> 
>                                                     
>                  Xsl
> ====
> 
>         
> <xsl:stylesheet
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
> version="1.0">
> <xsl:output method="text"/>
> <xsl:variable name="mostattributes">
> <xsl:for-each select="//RESOURCE">
> <xsl:sort select="count(attribute::*)"
> order="descending" data-type="number"/>
> <xsl:if test="position()=1">
> <xsl:value-of select="generate-id()"/><!-- this line
> has changed! -->
> </xsl:if>
> </xsl:for-each>
> </xsl:variable>
> <xsl:variable name="mostattributes-node"
> select="//node()[generate-id() = 
> $mostattributes]"/>
> 
> <xsl:variable name="maxattClientAgentTable">
> <xsl:for-each select="//CLASS">
> 	<xsl:choose>
> 		<xsl:when
> test="normalize-space(@NAME)='Client_Agent'">
> 			<xsl:for-each select="OBJECT">
> 				<xsl:sort select="count(ATTRIBUTE)"
> order="descending"/>
> 					<xsl:if test="position()=1">
> 						<xsl:value-of select="generate-id(..)"/><!--
> this line has changed! -->
> 					</xsl:if>
> 			</xsl:for-each>
> 		</xsl:when>
> 	</xsl:choose>
> </xsl:for-each>
> </xsl:variable>
> <xsl:variable name="mostChildattributes-node"
> select="//node()[generate-id() = 
> $maxattClientAgentTable]"/>
> 
> <xsl:template match="/">
> <xsl:text>RESOURCE_TYPE.GUID,RESOURCE.</xsl:text>
> <xsl:for-each select="//node()[generate-id() =
> $mostattributes]/@*">
> <xsl:value-of select="name(.)" ></xsl:value-of>
> <xsl:if test="position()!=last()">,</xsl:if>
> </xsl:for-each>
> <xsl:text>
</xsl:text>
> <xsl:apply-templates select="//RESOURCE"/>
> </xsl:template>
> 
> <xsl:template match="RESOURCE">
> <xsl:variable name="r" select="."/>
> <xsl:for-each select="//node()[generate-id() =
> $mostattributes]/@*">
> <!--Note: How do i get the values according to the
> column names ? I mean I 
> will check if the name of the attribues are same
> then print the value for it 
> otherwise print seperator. How do i do this
> ?<xsl:value-of 
>
select="normalize-space($r/[name(@)=current()/name(@)])"/>
> -->
> <xsl:if test="position()!=last()">,</xsl:if>
> </xsl:for-each>
> <xsl:text>
</xsl:text>
> </xsl:template>
> </xsl:stylesheet>
> 
>
---------------------------------------------------------------------
> 
> Thanks in advance for any help.
> Waiting for reply.
> 
> Regards
> Dipesh
> 
> 
>  XSL-List info and archive: 
> http://www.mulberrytech.com/xsl/xsl-list
> 


__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread