Subject: [xsl] Re: How to get nodes with maximum attributes ?? From: Dipesh Khakhkhar <dkhakhkh@xxxxxxxxxxxxxxx> Date: Sun, 24 Aug 2003 23:03:20 -0400 |
Hi Dimitre, Thanks a lot for responding and explaining and providing two solutions to solve my problem. Thanks Mike to give me hints to use EXSLT. I will go for that as well if this tough problem is not achieved with usual methods. I used Wendell's solution to find the node with maximum attributes and printing them as per my requirement which i stated in my previous postions. Here is the xsl which I am writting. My Input XML is =============== <?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> <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> <ATTRIBUTE NAME="Additional Column">additional column value</ATTRIBUTE> </IDENTIFICATION> </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"> </RESOURCE> </RESOURCE_TYPE> </AEXDATAEXTRACT> Current 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:template match="/"> <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="$r> <!-- Here I want to output the value of the attributes for the node with the same name as the node having maximum column. I am having the value of maximum node in the variable i.e. the unique identifie for that node from which i can get the other node. I wish to compare the attribute names here if it matches then printing their value otherwise printing separator. Do i have to run two for loop or storing value of one node into variable and running for loop for the other and comparing attribute values. Please help me to do this.--> <xsl:if test="position()!=last()">,</xsl:if> </xsl:for-each> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet> ------------------------------------------------------------------- Expected output is ================== DTD_VERSION,EXTRACT_START_DATETIME,EXTRACT_TYPE,EXTRACT_COLLECTION,ParentID,GU ID,NAME,DESCRIPTION,SOURCE,CREATED_DATE,MODIFIED_DATE,DELETED,ParentID,GUID,NA MESOURCE,SITE_CODE,DOMAIN,SYSTEM_TYPE,OS_NAME,OS_TYPE,OS_VERSION,OS_REVISION,L AST_LOGON_USER,LAST_LOGON_DOMAIN,ParentID,SelfID(Inventory),ParentID(Inventory ),SelfID(Asset),TableName,ParentID(Assetid), SelfID(idForTable1 i.e. Identification),Name,Domain,Altkey1,Altkey2,ParentID(Asset node is parent),SelfID(idForTable2),Agent Name,Product Version,Build Number,Install Path,ParentID(Asset node id),SelfID(Self id for table3),Collection Time,File Count,Total Size,Version 2.2,1/9/2003,4:49:39 PM,FULL,,ParentID,{493435f7-3b17-4c4c-b07f-c23e7ab7781f},Computer,Asset Type definition for Computer,Asset, 7/16/2002 5:22:23 PM,9/23/2002 2:17:48 PM,0,ParentId,{C116FCBF-5B94-4F15-BF95-5795DBD384CD},ALTIRISTEST_CPQ,,756win,F IDD,Win32,Microsoft Windows XP,Professional,5.1,Service Pack 1,,,ParentID,InventoryID(selfId),ParentID(Inventory ID),AssetID(selfid),TableName(Identification),ALTIRISTEST_CPQ,FIDDOMRTLSLC,,00 -02-A5-1A-67-A6 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,(Inventory ID),AssetID(selfid),TableName(ClientAgent),parentID(AssetID),TableID(obtained using generateid()),Altiris eXpress NS Client,5.5.0.517,517,C:\Program Files\Altiris\eXpress\NS Client ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Altiris eXpress Inventory Solution,5.5.0.424,424,C:\Program Files\Altiris\eXpress\NS Client\Software Delivery\Software Packages\{01B54EB5-3679-4C73-9E10-E169D5A5EC59} ,,,,,,,,,,,,,,,,,,,,,,,,,,,,(Inventory ID),AssetID(selfid),TableName(Inventory_Results),,,,,,ParentID(AsseId),TableID ,1/9/2003 3:06:56 AM,3,139271,5: 5: 0: 423 and so on.... -------------------------------------------------------------------- My xml is like it has tables corresponding to nodes in the database. Each table (node in the xml) has columns in it. The way i get tables from the input xml are. 1) Each node is a table. And attributes with it if present are the columns for it. (Example : Resource, Resouce_Type in the above example) 2) Node where attributes are not present are still a table with columns like primary key and foreign key which i am generating using generate-id function. I am relating all the tables like this. (Example, Asset, Inventory etc) 3)There are nodes which has tables and has many records in it. (Example Class node contains Object node (rows) and Attribute nodes (as column). As per requirement I have to get the column header in the first line of my output and column data in the succeeding lines. To sovle this problem. As i informed earlier the no. of columns in the table are changing in the input xml. So i m trying to find first the tables with maximum column and printing them as my header in the first line. To solve this problem i got the first thing after lot of struggle. I got the table name of i.e. node having maximum attributes and printing the header (column names). For test purpose i was trying to get data but got stucked. If i am getting that I can proceed with further processing. Now can i find the nodes having maximum child nodes in the same input xml ? And storing the unique identifier for it as well ?? This is of type 3 table listed above. Can anyone tell me will that be the way or someother way ? I am trying my best to get the expected output. I appreciate the kind of help I am getting for this list and from all the gurus like Mike, David, Wendell and all. Eagerly waiting for reply. Regards, Dipesh Date: Fri, 22 Aug 2003 22:26:39 +0200 From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx> Subject: [xsl] Re: How to get nodes with maximum attributes ?? > I am trying to get the node with maximum attributes. How do i get that. Facing It is not necessary at all to modify the value of a variable in order to find the maximum (and then the node with the maximum). Here are two solutions: <!-- Solution 1 (O(N)) --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:call-template name="max"> <xsl:with-param name="pNodes" select="/*/*"/> </xsl:call-template> </xsl:template> <xsl:template name="max"> <xsl:param name="pNodes" select="/.."/> <xsl:variable name="vnumNodes" select="count($pNodes)"/> <xsl:choose> <xsl:when test="$vnumNodes < 2"> <xsl:value-of select="count($pNodes[1]/@*)"/> </xsl:when> <xsl:otherwise> <xsl:variable name="vHalf" select="$vnumNodes div 2"/> <xsl:variable name="max1"> <xsl:call-template name="max"> <xsl:with-param name="pNodes" select="$pNodes[position() <= $vHalf]"/> </xsl:call-template> </xsl:variable> <xsl:variable name="max2"> <xsl:call-template name="max"> <xsl:with-param name="pNodes" select="$pNodes[position() > $vHalf]"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="$max1 * ($max1 >= $max2) + $max2 * ($max1 < $max2)"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> <!-- Solution 2 (O(N*log2(N))) but faster in almost all real cases --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:call-template name="max"> <xsl:with-param name="pNodes" select="/*/*"/> </xsl:call-template> </xsl:template> <xsl:template name="max"> <xsl:param name="pNodes" select="/.."/> <xsl:for-each select="$pNodes"> <xsl:sort select="count(@*)" data-type="number" order="descending"/> <xsl:if test="position() = 1"> <xsl:value-of select="count(@*)"/> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> When applied on this source.xml: <t> <e a1="1" a2="2"/> <e a1="1" a2="2" a3="3"/> <e a1="1" a2="2"/> <e a1="1" a2="2"/> <e a1="1" a2="2"/> <e a1="1" a2="2" a3="3" a4="4"/> <e a1="1" a2="2"/> <e a1="1" a2="2"/> <e a1="1" a2="2"/> <e a1="1" a2="2"/> </t> the correct result is produced: 4 One can also find a node (or all nodes) having this maximum value -- either by modifying the above solutions to return a node (the first solution will need the xxx:node-set() extension) or simply with this XPath expression: $allNodes[count(@*) = $maxValueFound] ===== Cheers, Dimitre Novatchev. http://fxsl.sourceforge.net/ -- the home of FXSL XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Invitation to XSL-FO Chef's T, B. Tommie Usdin | Thread | [xsl] Display value of varying attr, rajith r |
[xsl] Invitation to XSL-FO Chef's T, B. Tommie Usdin | Date | Re: [xsl] EXSLT/XALAN 2.5.1 Current, Mukul Gandhi |
Month |