From b1939bd6f8a523c1121bdcc5bf5edaa43218617c Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Sun, 29 Aug 2010 15:51:03 +0000 Subject: XPath: Document order comparator refactoring, document order is now a total order even for nodes from different documents git-svn-id: http://pugixml.googlecode.com/svn/trunk@695 99668b35-9821-0410-8761-19e4c4f06640 --- src/pugixml.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 977a295..7c95e34 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4819,25 +4819,26 @@ namespace return result; } - // precondition: node_height of ln is <= node_height of rn, ln != rn bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) { - assert(lh <= rh); + // normalize heights + for (unsigned int h = rh; h < lh; h++) ln = ln.parent(); + for (unsigned int h = lh; h < rh; h++) rn = rn.parent(); - while (lh < rh) - { - --rh; - rn = rn.parent(); - } - - if (ln == rn) return true; + // one node is the ancestor of the other + if (ln == rn) return lh < rh; + // find common ancestor while (ln.parent() != rn.parent()) { ln = ln.parent(); rn = rn.parent(); } - + + // there is no common ancestor (the shared parent is null), nodes are from different documents + if (!ln.parent()) return ln < rn; + + // determine sibling order for (; ln; ln = ln.next_sibling()) if (ln == rn) return true; @@ -4858,15 +4859,19 @@ namespace { xml_node ln = lhs.node(), rn = rhs.node(); + // optimized document order based check const void* lo = lhs.attribute() ? lhs.attribute().document_order() : ln.document_order(); const void* ro = rhs.attribute() ? rhs.attribute().document_order() : rn.document_order(); if (lo && ro) return lo < ro; + // compare attributes if (lhs.attribute() && rhs.attribute()) { + // shared parent if (lhs.parent() == rhs.parent()) { + // determine sibling order for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) if (a == rhs.attribute()) return true; @@ -4874,17 +4879,20 @@ namespace return false; } + // compare attribute parents ln = lhs.parent(); rn = rhs.parent(); } else if (lhs.attribute()) { + // attributes go after the parent element if (lhs.parent() == rhs.node()) return false; ln = lhs.parent(); } else if (rhs.attribute()) { + // attributes go after the parent element if (rhs.parent() == lhs.node()) return true; rn = rhs.parent(); @@ -4895,7 +4903,7 @@ namespace unsigned int lh = node_height(ln); unsigned int rh = node_height(rn); - return (lh <= rh) ? node_is_before(ln, lh, rn, rh) : !node_is_before(rn, rh, ln, lh); + return node_is_before(ln, lh, rn, rh); } }; -- cgit v1.2.3