Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

XPath.descendant problem?

Moderators: kris

Posted: 02/27/08 12:02:38 Modified: 02/27/08 12:03:40

This might be the default XPath behaviour (I've just started looking at it), but it seems a bit odd to me Look at the last line. I would expect descendant to also include the children of the node, but it doesn't. If this is the intended behaviour, a way to concat NodeSets? would be nice.

I found this in the w3 docs:

the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on

So this looks like a bug, right?

module test;

import tango.io.Stdout;
import tango.text.xml.Document;
import tango.io.File;

char[] xml = "
<p>
	<c>
		<c/>
		<c/>
	</c>
	<c>
		<c/>
		<c/>
	</c>
</p>
";

void main() {
	auto doc = new Document!(char);
	doc.parse(xml);
	auto p = doc.query["p"].nodes[0];

	Stdout.formatln( // Prints 6
			"doc.query[].descendant(\"c\").count = {}",
			doc.query[].descendant("c").count);

	Stdout.formatln( // Prints 2
			"p.child(\"c\").count = {}",
			p.query["c"].count);

	Stdout.formatln( // Prints 4 - Should be 6?
			"p.descendant(\"c\").count = {}",
			p.query[].descendant("c").count);
}
Author Message

Posted: 02/27/08 12:12:13

Index: Document.d
===================================================================
--- Document.d  (revision 3301)
+++ Document.d  (working copy)
@@ -1466,8 +1466,10 @@
                         NodeSet set = {host};
                         auto mark = host.mark;

-                        foreach (node; nodes)
+                        foreach (node; nodes) {
+                                 test(filter, node);
                                  traverse (node);
+                                               }
                         return set.assign (mark);
                 }

Posted: 02/27/08 21:19:17 -- Modified: 02/28/08 01:59:21 by
kris -- Modified 4 Times

module test;

import tango.io.Stdout;
import tango.text.xml.Document;
import tango.io.File;

char[] xml = "
<p>
	<c>
		<c/>
		<c/>
	</c>
	<c>
		<c/>
		<c/>
	</c>
</p>
";

void main() {
	auto doc = new Document!(char);
	doc.parse(xml);
        auto p = doc.query["p"].nodes[0];

        // all descendants of <p> - looks correct
	Stdout.formatln( // Prints 6
			"doc.child.descendant(\"c\").count = {}",
			doc.query[].descendant("c").count);

        // immediate children of p called 'c' - looks correct
	Stdout.formatln( // Prints 2
			"p.child(\"c\").count = {}",
			p.query["c"].count);

        // all descendants of the children of p - looks correct
	Stdout.formatln( // Prints 4 - Should be 6?
			"p.child.descendant(\"c\").count = {}",
			p.query[].descendant("c").count);

        // all descendants of p - should print 6
	Stdout.formatln( 
			"p.descendant(\"c\").count = {}",
			p.query.descendant("c").count);

        // all 'c' descendants of the document - should print 6
	Stdout.formatln( 
			"doc.descendant(\"c\").count = {}",
			doc.query.descendant("c").count);

        // all descendants of the doc - should print 7
	Stdout.formatln( 
			"doc.descendant.count = {}",
			doc.query.descendant.count);
}

Currently missing from Tango is support for descendant-or-self (and other axis with 'self')

Posted: 02/28/08 01:47:40

BTW, I'm not at all sure that using [] syntax for selecting child nodes is the best idea. It is certainly more compact than using method names, but is perhaps misleading at the same time. For clarification, [] is merely a substitute for .child(), for example:

p.query[].descendant  =>  p.query.child.descendant

doc.query[][]["c"]    =>  doc.query.child.child.child("c")