Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old November 7th, 2006, 05:45 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default path for nested elements

Im looking for a path expression to detect elements where specific parent nodes may be nesting themself
for example:
Searching all <e> elements nested inside one or more c elements
and the c elements can be nested inside one or more b elements.
<a>
    <b>
        <b>
            <e>dontshowme</e>
            <c>
                <c>
                    <e>showme</e>
                </c>
            </c>
        </b>
        <b>
            <b>
                <c>
                    <e>showme</e>
                </c>
            </b>
        </b>
        <b>
            <b>
                <b>
                    <b>
                        <c>
                            <e>showme</e>
                        </c>
                    </b>
                </b>
            </b>
        </b>
        <b>
            <q>
                <c>
                    <e>dontshowme</e>
                </c>
            </q>
        </b>
    </b>
</a>

i tried it with //a/descendant-or-self::b/descendant-or-self::c/e
or /a//b//c/e but then i get the node <b><q><c><e> also
I only want nodes with
<a>one or more<b>one or more<c><e> no other nodes in between but how thats the question
 
Old November 7th, 2006, 06:25 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

>I only want nodes with <a>one or more<b>one or more<c><e> no other nodes in between


Tricky one. In XPath 2.0

a/(descendant::b except descendant::*[not(self::b)]/descendant::b)
/(descendant::c except descendant::*[not(self::c)]/descendant::c)
/e

but I can't think of a 1.0 solution. An approximation might be

a//b//c/e[not(ancestor::*[not(self::a|self::b|self::c)])]

but that will also select a/b/c/b/c/e

Yuo might be able to construct a more elaborate predicate on the ancestor axis to eliminate such cases, e.g. not(ancestor::b/ancestor::c)

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old November 7th, 2006, 06:34 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thanx Michael for the quick reply

I managed it with this expression
/a/descendant-or-self::b[parent::b|parent::a]/descendant-or-self::c[parent::c|parent::b]/e
or
/a//b[parent::b|parent::a]//c[parent::c|parent::b]/e

but is there a better way??

this still selects a/b/c/b/c/e
 
Old November 7th, 2006, 06:41 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Quote:
quote:
Tricky one. In XPath 2.0
a/(descendant::b except descendant::*[not(self::b)]/descendant::b)
/(descendant::c except descendant::*[not(self::c)]/descendant::c)
/e
...
/a//b[parent::b|parent::a]//c[parent::c|parent::b]/e
I tried this both but I get no results from this expression in xpath2.0
even not with
a/(descendant::b except descendant::*[not(self::b)]/descendant::b)
 
Old November 7th, 2006, 06:51 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Quote:
quote:a/(descendant::b except descendant::*[not(self::b)]/descendant::b)
/(descendant::c except descendant::*[not(self::c)]/descendant::c)
/e
this one did the job (forgot the preceding / before the a)
/a/(descendant::b except descendant::*[not(self::b)]/descendant::b)
/(descendant::c except descendant::*[not(self::c)]/descendant::c)
/e

thanx I can use this also with nested[list] tags
 
Old November 19th, 2006, 03:55 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I have a recursive xml structure like this
<learnerinformation xmlns="http://www.imsglobal.org/xsd/imslip_v1p0">
    <activity>
        <activity>
            <ext_activity>
                extented activity
            </ext_activity>
        </activity>
        <ext_activity>
            extented activity
        </ext_activity>
    </activity>
</learnerinformation>

When I use this expression:
//learnerinformation/(descendant::activity except descendant::*[not(self::activity)]/descendant::activity)/ext_activity
in a XPath2.0 expression builder I get the correct results:
/learnerinformation[1]/activity[1]/activity[1]/ext_activity[1]
/learnerinformation[1]/activity[1]/ext_activity[1]

But when I put the same expression insite a 'match' attribute like this
<xsl:template match="//learnerinformation/(descendant::activity except descendant::*[not(self::activity)]/descendant::activity)/ext_activity">
I get the error message: Unexpected Token.

when I put the same expression inside the select attribute I don't get an error like this
<xsl:apply-templates select="//learnerinformation/(descendant::activity except descendant::*[not(self::activity)]/descendant::activity)/ext_activity"/>

Does anyone know why this is? the same path expression works inside "select" but not inside "match" ???
 
Old November 19th, 2006, 05:29 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Match patterns in XSLT accept only a subset of the XPath expression syntax. This is supposed to make it easier for template matching to be optimized. You can often get around the restrictions by putting the logic inside a predicate, where full XPath expressions are allows. For example

//learnerinformation/(descendant::activity except descendant::*[not(self::activity)]/descendant::activity)/ext_activity

can perhaps be written as

//learnerinformation//activity[not(.[not(self::activity)]/descendant::activity)/ext_activity]

and perhaps it can be simplified further.

Incidentally "//" at the start of a match pattern is nearly always redundant. All it means is "this element must be part of a document".

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old November 20th, 2006, 05:43 AM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default

thanx for the quick reply I noticed in your book the chapter 6 about this issue. I will read it more carefully now. Before I did not understand the big relevance of this chapter.
But is this solution you give here not the same as //learnerinformation//activity/ext_activity
I still get the ext_activity nodes when I have a contruction like this
//learnerinformation/wrongnode/activity/ext_activity. But I will look at your examples and try to figure it out with the pattern syntax





Similar Threads
Thread Thread Starter Forum Replies Last Post
Finding nested elements XSLT 1? Budbertzerofluff XSLT 2 November 15th, 2008 02:45 PM
Problem nested elements Geierwally XSLT 7 May 9th, 2007 07:27 AM
transformation from attributes to nested elements e-bell XSLT 2 January 21st, 2007 07:21 PM
sorting nested elements again stekker XSLT 1 June 5th, 2006 03:38 AM
sorting nested elements stekker XSLT 5 June 5th, 2006 01:19 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.