|
|
 |
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 p2p Programmer to Programmer discussion community. This is a community of more than 40,000 computer programmers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining our free Wrox p2p community you can post your own programming questions and respond to other programmers’ questions. Registered users also don't have to see the ads that are displayed to guests. Registration is fast, simple and absolutely free so please, join today!
Join today and post to win prizes! Post more to increase your chances of being Wrox’s top poster of the month.
|
 |

July 27th, 2009, 08:29 PM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 7
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
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:
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 09:38 PM.
|

July 28th, 2009, 03:07 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Location: Newcastle, , United Kingdom.
Posts: 1,359
Thanks: 0
Thanked 31 Times in 31 Posts
|
|
"//*[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 -/
|

July 28th, 2009, 03:34 AM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 7
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
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
}
|

July 28th, 2009, 04:49 AM
|
 |
Wrox Author
Points: 12,735, Level: 48 |
|
|
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 3,923
Thanks: 0
Thanked 82 Times in 80 Posts
|
|
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
|

July 28th, 2009, 01:26 PM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 7
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
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!
|

July 28th, 2009, 01:30 PM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Location: Newcastle, , United Kingdom.
Posts: 1,359
Thanks: 0
Thanked 31 Times in 31 Posts
|
|
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 -/
|

July 28th, 2009, 01:44 PM
|
 |
Wrox Author
Points: 12,735, Level: 48 |
|
|
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 3,923
Thanks: 0
Thanked 82 Times in 80 Posts
|
|
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
|

July 28th, 2009, 01:46 PM
|
 |
Wrox Author
Points: 12,735, Level: 48 |
|
|
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 3,923
Thanks: 0
Thanked 82 Times in 80 Posts
|
|
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
|

July 29th, 2009, 12:34 PM
|
|
Registered User
|
|
Join Date: Jul 2009
Posts: 7
Thanks: 2
Thanked 0 Times in 0 Posts
|
|
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..
|
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
 |