Subject: Re: [xsl] Hierearchy navigation in XSL From: Scott Bronson <bronson@xxxxxxxxxxx> Date: 26 Oct 2002 09:55:20 -0700 |
No, I didn't see your message the first time around. That's strange. I ended up using a very different method to solve this problem suggested by David McNally and David Carlisle (current version included below). Thanks for sending this one! I definitely learned from it, even if I didn't use it. :) I'm glad to see that there are very different ways of solving the same problem. - Scott <!-- outputs all the namespaces immediately after this one --> <xsl:template match="/masterdoc" mode="list"> <xsl:variable name="thisns"> <xsl:if test="$ns"> <xsl:value-of select="concat($ns,'.')"/> </xsl:if> </xsl:variable> <xsl:for-each select="class[starts-with(@namespace,$ns)]"> <xsl:sort select="@namespace"/> <xsl:variable name="nsafter" select="substring-before(concat(substring-after(@namespace,$thisns),'.'),'.')"/> <xsl:if test="not(preceding-sibling::class[starts-with(@namespace,concat($thisns,$nsafter))]) and ($thisns='' or not($nsafter=''))"> <tr><td> <xsl:call-template name="namespace-link"> <xsl:with-param name="ns" select="concat($thisns,$nsafter)"/> <xsl:with-param name="assembly" select="$assembly"/> <xsl:with-param name="content" select="$nsafter"/> </xsl:call-template> </td></tr> </xsl:if> </xsl:for-each> </xsl:template> On Wed, 2002-10-16 at 00:07, Dimitre Novatchev wrote: > I tried to send this twice two days ago, but due to some reason, I > cannot see it in the archives and the digests. > > Sorry, if someone has received more than one instance of this message. > > > --- Scott Bronson wrote: > > > Hello. I've solved most of this problem, but the last tiny bit has > > me > > stumped. I'm hoping someone can tell me how to fix this. > > > > Here's some input: > > > > > > <masterdoc> > > <class name="Object" namespace="System"/> > > <class name="Array" namespace="System"/> > > <class name="ArrayList" namespace="System.Collections"/> > > <class name="Comparer" namespace="System.Collections"/> > > <class name="Grimey" > > namespace="System.Collections.Overkill"/> > > <class name="Formatter" > > namespace="System.Runtime.Serialization"/> > > <class name="ObjectHandle" namespace="System.Runtime.Remoting"/> > > <class name="Garbage" namespace="Other.SubAPI"/> > > </masterdoc> > > > > > > My script accepts a parameter that tells where it is in the > > hierarchy. > > It then outputs all immediate child nodes at that level in the > > hierarchy. > > > > Some examples: if we're at "System", the script should output > > "Collections" and "Runtime". If we're at "System.Collections", it > > should output "Overkill". If we're at "", it should output "System" > > and > > "Other". If at "Other", output "SubAPI". Seems a fairly easy > > problem, > > right? > > > > > > > > Here's my script right now: > > > > > > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > > version="1.0"> > > <xsl:output method="text"/> > > <xsl:param name="ns"/> > > <xsl:key name='uniq' match='class' use='@namespace'/> > > > > <xsl:template match="/masterdoc"> > > <xsl:for-each > > select="class[generate-id()=generate-id(key('uniq',@namespace)[1])]"> > > <xsl:sort select="@namespace"/> > > <xsl:choose> > > <xsl:when test="string-length($ns)=0"> > > <xsl:value-of select="@namespace"/> > > </xsl:when> > > <xsl:when test="starts-with(@namespace,concat($ns,'.'))"> > > <xsl:value-of > > select="substring(@namespace,string-length($ns)+2)"/> > > </xsl:when> > > </xsl:choose> > > <xsl:text> > > </xsl:text> > > </xsl:for-each> > > </xsl:template> > > > > </xsl:stylesheet> > > > > > > > > Here are some example runs of this script: > > > > xalan -Q -XSL samp1.xsl -IN sample.xml -PARAM ns > > "'System.Collections'" > > Overkill > > > > xalan -Q -XSL samp1.xsl -IN sample.xml -PARAM ns "'System'" > > Collections > > Collections.Overkill > > Runtime.Remoting > > Runtime.Serialization > > > > > > The last one illustrates the problem. It should have output only > > "Collections" and "Runtime". > > > > I picture the algorithm being something like: > > if(not(already copied string-before("Runtime.Remoting", ".")) > > then copy string-before("Runtime.Remoting", ".") to output > > > > I've tried various combinations of preceding, preceding sibling, and > > position to try to figure out what I've already output. I even tried > > key() and using IDs to navigate the parent. All has resulted in > > frustration. > > > > Does anyone have any idea of what I can do? I'm out of ideas. > > > > Thank you! > > > > - Scott > > > Hi Scott, > > Here is a solution: > > The Muenchian method for grouping cannot be directly applied, as > xsl:key cannot contain a reference to an xsl:variable. > > Therefore, I'm doing this in two passes and do not depend on the > "class" elements being initially sorted on the values of their > "namespace" attribute: > > First get an RTF containing "childName" elements whose value is every > token in any "namespace" attribute, which immediately follows the > string contained in your parameter. > > Then convert this RTF to a regular xml document and process it with the > Muenchian method. > > > Here's the transformation: > ========================= > <xsl:stylesheet version="1.0" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > xmlns:vendor="urn:schemas-microsoft-com:xslt" > exclude-result-prefixes="vendor"> > > <xsl:output method="text"/> > > <xsl:key name="kChildren" match="childName" use="."/> > > <xsl:template match="/"> > <xsl:param name="pPrefix" select="'System'"/> > > <xsl:variable name="vprefTest"> > <xsl:choose> > <xsl:when test="$pPrefix"> > <xsl:value-of select="concat('.', $pPrefix, '.')"/> > </xsl:when> > <xsl:otherwise> > <xsl:value-of select="'.'"/> > </xsl:otherwise> > </xsl:choose> > </xsl:variable> > > > <xsl:variable name="vrtfImmChildren"> > <xsl:for-each > select="/*/*/@namespace > [starts-with(concat('.', .), > $vprefTest > )]"> > <childName> > <xsl:variable name="vSuffix" > select="substring-after(concat('.', .), > $vprefTest > )"/> > <xsl:choose> > <xsl:when test="contains($vSuffix, '.')"> > <xsl:value-of select="substring-before($vSuffix, '.')" /> > </xsl:when> > <xsl:otherwise> > <xsl:value-of select="$vSuffix"/> > </xsl:otherwise> > </xsl:choose> > </childName> > > </xsl:for-each> > </xsl:variable> > > <xsl:variable name="vImmChildren" > select="vendor:node-set($vrtfImmChildren)"/> > > <xsl:for-each select="$vImmChildren"> > <xsl:for-each select="*[generate-id() > = > generate-id(key('kChildren', > . > )[1] > ) > ]"> > > <xsl:value-of select="concat(., '
')"/> > </xsl:for-each> > </xsl:for-each> > > </xsl:template> > </xsl:stylesheet> > > > When applied on your source xml document: > ======================================== > <masterdoc> > <class name="Object" namespace="System"/> > <class name="Array" namespace="System"/> > <class name="ArrayList" namespace="System.Collections"/> > <class name="Comparer" namespace="System.Collections"/> > <class name="Grimey" namespace="System.Collections.Overkill"/> > <class name="Formatter" namespace="System.Runtime.Serialization"/> > <class name="ObjectHandle" namespace="System.Runtime.Remoting"/> > <class name="Garbage" namespace="Other.SubAPI"/> > </masterdoc> > > the result is: > ============= > Collections > Runtime > > > If I change the "pPrefix" parameter to "", > now the result is: > ================= > System > Other > > > > Hope this helped. > > > > > > ===== > Cheers, > > Dimitre Novatchev. > http://fxsl.sourceforge.net/ -- the home of FXSL > > > > __________________________________________________ > Do you Yahoo!? > Faith Hill - Exclusive Performances, Videos & More > http://faith.yahoo.com > > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list > > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Hierearchy navigation in , Dimitre Novatchev | Thread | [xsl] xsl: display only a specified, Jan Krattiger |
RE: [xsl] Inheriting an attribute f, James Carlyle | Date | [xsl] Sorting on a transformed stri, Scott Bronson |
Month |