Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition ISBN: 978-0-470-19274-0
This is the forum to discuss the Wrox book XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition by Michael Kay; ISBN: 9780470192740
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition ISBN: 978-0-470-19274-0 section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old July 27th, 2009, 07:29 PM
Authorized User
Points: 102, Level: 2
Points: 102, Level: 2 Points: 102, Level: 2 Points: 102, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default Excluding elements in XPath

I'm trying to exclude certain elements using XPath within an ASP.NET C# application. My XML structure is as follows:

Code:
<A>
  <B>
     <C>
       <D>
       <D>
What I want is the following:
Code:
<A>
  <B>
     <C>
       <D>
where the only <D> element left meets a certain criterion. I've been looking online and experimenting for some time now but not able to figure this out. So as a precursor, I'm trying to just exclude all <D> elements in the document with the following XPath code string that goes into the SelectNodes method in my .NET app:

"(//*)[not(self::D)]"

This doesn't work. Not sure what's the right way to do this (and I'm hoping I can do this with just XPath and not XSLT to minimize overhead in loading a stylesheet file) .. thanks!

Last edited by baseliner; July 27th, 2009 at 08:38 PM.
Reply With Quote
  #2 (permalink)  
Old July 28th, 2009, 02:07 AM
samjudson's Avatar
Friend of Wrox
Points: 8,687, Level: 40
Points: 8,687, Level: 40 Points: 8,687, Level: 40 Points: 8,687, Level: 40
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Aug 2007
Location: Newcastle, , United Kingdom.
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

"//*[not(self::D)]" should select all nodes except 'D' elements.

This will exclude ALL D elements. Given the example you've shown there is no way of us knowing how you want to show the 1 'D' element you have shown so we can't really help you further.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
Reply With Quote
  #3 (permalink)  
Old July 28th, 2009, 02:34 AM
Authorized User
Points: 102, Level: 2
Points: 102, Level: 2 Points: 102, Level: 2 Points: 102, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Thanks Sam. As I mentioned, I was trying to exclude ALL D elements as a precursor to the end-goal of excluding based on a criterion (I think I can manage the additional predicates if I can get the ALL exclusion to work OK). But the problem I'm having is that neither "(//*)[not(self::D)]" nor "//*[not(self::D)]" is excluding all the D elements. Below is my .NET code where I execute this XPath expression to compute newNodeList (the code is trying to generate a new XML doc where all D elements are excluded; eventually I want it to generate a new XML doc based on the values of @myAttr). When I look at the value of newDoc after the AppendChild, all the D elements are still there. Maybe it's something in this code that's incorrect? Thanks!

Code:
          XmlDocument Doc = new XmlDocument();
                    Doc.LoadXml(xmlInputString);
                    XmlNodeList nodeList = Doc.SelectNodes("/A/B/C/D/@myAttr");


                    for (int i = 0; i < nodeList.Count; i++ )
                    {
                        string myVal = nodeList.Item(i).ToString();

                        XmlDocument newDoc = new XmlDocument();
                        string query = "//*[not(self::D)]";
                        
                        XmlNodeList newNodeList = Doc.SelectNodes(query);
                        newDoc.AppendChild(newDoc.ImportNode(newNodeList[0], true));
                        
                        ... more code
                     }
Reply With Quote
  #4 (permalink)  
Old July 28th, 2009, 03:49 AM
mhkay's Avatar
Wrox Author
Points: 18,438, Level: 59
Points: 18,438, Level: 59 Points: 18,438, Level: 59 Points: 18,438, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,954
Thanks: 0
Thanked 290 Times in 285 Posts
Default

Your XPath is working fine; it's what you do with the result that's the problem. Your XPath result doesn't include the D node, but it does include its parent, and when you Append the parent to the new tree, it will bring its children with it.

Why not write this whole thing in XSLT or XQuery - it's so much easier than low-level procedural DOM coding!
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #5 (permalink)  
Old July 28th, 2009, 12:26 PM
Authorized User
Points: 102, Level: 2
Points: 102, Level: 2 Points: 102, Level: 2 Points: 102, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Thanks for pointing this out, Michael. I was trying to avoid XSLT since I need to perform this logic multiple times in the for loop so I was trying to avoid the overhead associated with loading an XSLT file from disk every time (my application's users are very sensitive to time it takes to execute). Not sure if there's a way to load the XSLT file just once prior to the for loop and then use it from memory within the for loop?

Also, the following XSLT code doesn't seem to work for this (I"m getting empty output, I think I'm doing something silly):

Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>
    
    <xsl:template match="*" mode="copy">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates mode="copy"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="D" mode="copy"/>
</xsl:stylesheet>
I haven't programmed with XQuery yet but it looks like it's inline code (no external file needed) so I'll look into this more.. How does it compare with XSLT in terms of performance (given that the XSLT file has to be loaded from disk)?

Thanks!
Reply With Quote
  #6 (permalink)  
Old July 28th, 2009, 12:30 PM
samjudson's Avatar
Friend of Wrox
Points: 8,687, Level: 40
Points: 8,687, Level: 40 Points: 8,687, Level: 40 Points: 8,687, Level: 40
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Aug 2007
Location: Newcastle, , United Kingdom.
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Why do you think that XSLT has to be loaded from a string?

Check out the XslCompiledTransform.Load method, which can be passed a XmlReader - you can load this from an embedded string, or from a file or whatever.

The following would copy all elements apart from the 'D' element:

<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<xsl:template match="D"/>
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
Reply With Quote
  #7 (permalink)  
Old July 28th, 2009, 12:44 PM
mhkay's Avatar
Wrox Author
Points: 18,438, Level: 59
Points: 18,438, Level: 59 Points: 18,438, Level: 59 Points: 18,438, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,954
Thanks: 0
Thanked 290 Times in 285 Posts
Default

I think every XSLT processor I know of allows you (a) to read the stylesheet from a string in your host application, and (b) to compile it once and execute it repeatedly. The same is true of XQuery - there's no intrinsic reason why one should be faster than the other.

However, rather than calling an XSLT transformation repeatedly from procedural code, why not be more radical, and get rid of the procedural code entirely?
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #8 (permalink)  
Old July 28th, 2009, 12:46 PM
mhkay's Avatar
Wrox Author
Points: 18,438, Level: 59
Points: 18,438, Level: 59 Points: 18,438, Level: 59 Points: 18,438, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,954
Thanks: 0
Thanked 290 Times in 285 Posts
Default

Oh, I forgot: the problem with your code is that the first template does apply-templates without specifying mode="copy". You don't actually need modes here at all.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #9 (permalink)  
Old July 29th, 2009, 11:34 AM
Authorized User
Points: 102, Level: 2
Points: 102, Level: 2 Points: 102, Level: 2 Points: 102, Level: 2
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Michael and Sam - thanks a lot for your help! The compiled transform was just what I needed and I have it all working now.

Michael - not sure I follow your suggestion of getting rid of the procedural code completely.. this XSL transformation is within an ASP.NET webservice app that does other stuff after the transform is done..
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
XSLT excluding elements based on an external document ashcarrot XSLT 5 January 12th, 2009 12:05 PM
Including some records and excluding others RussLewis XSLT 2 March 3rd, 2008 11:36 AM
Excluding Elements based on a Predicate Condition tasmisr XSLT 3 February 27th, 2008 12:00 PM
Excluding Rows fs22 SQL Language 2 August 17th, 2005 12:58 PM
excluding archives of a folder thomaz C# 4 March 8th, 2004 08:09 AM



All times are GMT -4. The time now is 04:18 AM.


Powered by vBulletin®
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.