|
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 |