[erlang-patches] Another xmerl_xpath patch: 'descendant' axis should return nodes in document order

Matthew Dempsky <>
Fri Aug 15 22:10:18 CEST 2008


The XPath spec (implicitly) states that the descendants axis is a
forward axis and therefore it should return nodes in document order:

    An axis is either a forward axis or a reverse axis. An axis that
    only ever contains the context node or nodes that are after the
    context node in document order is a forward axis. An axis that
    only ever contains the context node or nodes that are before the
    context node in document order is a reverse axis. Thus, the
    ancestor, ancestor-or-self, preceding, and preceding-sibling axes
    are reverse axes; all other axes are forward axes.

Document order places elements before their children:

    There is an ordering, document order, defined on all the nodes in
    the document corresponding to the order in which the first
    character of the XML representation of each node occurs in the XML
    representation of the document after expansion of general
    entities. Thus, the root node will be the first node. Element
    nodes occur before their children.

Therefore, "/descendant-or-self::*" applied to
"<a><b><c/><d/></b><e><f/><g/></e></a>" should return a, b, c, d, e,
f, and g in that order.  The patch below corrects this.

Also, it corrects ancestor-or-self to be properly recognized as a
reverse axis.

--- xmerl_xpath.erl.patched	2008-08-15 13:43:40.000000000 -0500
+++ xmerl_xpath.erl	2008-08-15 15:07:24.000000000 -0500
@@ -365,6 +365,8 @@

 fwd_or_reverse(ancestor, Context) ->
     reverse_axis(Context);
+fwd_or_reverse(ancestor_or_self, Context) ->
+    reverse_axis(Context);
 fwd_or_reverse(preceding_sibling, Context) ->
     reverse_axis(Context);
 fwd_or_reverse(preceding, Context) ->
@@ -408,25 +410,25 @@
 		 node = E,
 		 parents = Parents},
     NewParents = [N|Parents],
-    Acc1 = case node_test(Tok, N, Context) of
-	       true ->
-		   [N|Acc];
-	       false ->
-		   Acc
-	   end,
+    Acc1 = match_desc(T, Parents, Tok, Acc, Context),
     Acc2 = match_desc(get_content(E), NewParents, Tok, Acc1, Context),
-    match_desc(T, Parents, Tok, Acc2, Context);
+    case node_test(Tok, N, Context) of
+        true ->
+            [N|Acc2];
+        false ->
+            Acc2
+    end;
 match_desc([E|T], Parents, Tok, Acc, Context) ->
     N = #xmlNode{node = E,
 		 type = node_type(E),
 		 parents = Parents},
-    Acc1 = case node_test(Tok, N, Context) of
-	       true ->
-		   [N|Acc];
-	       false ->
-		   Acc
-	   end,
-    match_desc(T, Parents, Tok, Acc1, Context);
+    Acc1 = match_desc(T, Parents, Tok, Acc, Context),
+    case node_test(Tok, N, Context) of
+        true ->
+            [N|Acc1];
+        false ->
+            Acc1
+    end;
 match_desc([], _Parents, _Tok, Acc, _Context) ->
     Acc.

@@ -435,13 +437,13 @@
 %% "The 'descendant-or-self' axis contains the context node and the
 %% descendants of the context node."
 match_descendant_or_self(Tok, N, Acc, Context) ->
-    Acc1 = case node_test(Tok, N, Context) of
-	       true ->
-		   [N|Acc];
-	       false ->
-		   Acc
-	   end,
-    match_descendant(Tok, N, Acc1, Context).
+    Acc1 = match_descendant(Tok, N, Acc, Context),
+    case node_test(Tok, N, Context) of
+        true ->
+            [N|Acc1];
+        false ->
+            Acc1
+    end.


 match_child(Tok, N, Acc, Context) ->



More information about the erlang-patches mailing list