xsl-list
[Top] [All Lists]

Re: How to get node with maximum child nodes??

2003-08-26 01:02:41
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(_at_)mailbox(_dot_)syr(_dot_)edu> 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



<Prev in Thread] Current Thread [Next in Thread>