[erlang-bugs] xmerl_xpath doesn't handle "//@*" correctly?

Matthew Dempsky <>
Tue Aug 12 08:11:49 CEST 2008


Here is a patch for a handful of XPath bugs I found while trying to
track down the previous issue.

The first four hunks and the seventh hunk fix the handling of
'preceding', 'preceding-sibling', 'following', and 'following-sibling'
to handle when the context nodeset includes a text node.  E.g.,
"//text()/preceding::*" or "//b/following::text()" against
"<a>x<b/>x</a>".

The fifth hunk fixes match_attribute to not throw away any accumulated
context nodes just because a non-element node was tested.  E.g.,
"//@*" against "<a b='c'>x</a>".

The sixth hunk fixes xmerl_xpath.erl to compile correctly when
-Ddebug=true is given.

(I'm not an xpath guru, so someone should double check that my test
cases aren't bogus.  I just used
http://www.whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm as
a sanity check.)

--- xmerl_xpath.erl.orig	2008-08-12 00:28:54.000000000 -0500
+++ xmerl_xpath.erl	2008-08-12 00:50:16.000000000 -0500
@@ -525,7 +525,7 @@ match_following_sibling(Tok, N, Acc, Con
     case Ps of
 	[#xmlNode{type = element,
 		  node = #xmlElement{} = PNode}|_] ->
-	    FollowingSiblings = lists:nthtail(Node#xmlElement.pos,
+	    FollowingSiblings = lists:nthtail(get_position(Node),
 					      get_content(PNode)),
 	    lists:foldr(
 	      fun(E, AccX) ->
@@ -553,7 +553,7 @@ match_following(Tok, N, Acc, Context) ->
     case Ps of
 	[#xmlNode{type = element,
 		  node = #xmlElement{} = PNode}|_] ->
-	    FollowingSiblings = lists:nthtail(Node#xmlElement.pos,
+	    FollowingSiblings = lists:nthtail(get_position(Node),
 					      get_content(PNode)),
 	    lists:foldr(
 	      fun(E, AccX) ->
@@ -588,7 +588,7 @@ match_preceding_sibling(Tok, N, Acc, Con
 	[#xmlNode{type = element,
 		  node = #xmlElement{} = PNode}|_] ->
 	    PrecedingSiblings = lists:sublist(get_content(PNode), 1,
-					      Node#xmlElement.pos-1),
+                                              get_position(Node) - 1),
 	    lists:foldr(
 	      fun(E, AccX) ->
 		      ThisN = #xmlNode{type = node_type(E),
@@ -616,7 +616,7 @@ match_preceding(Tok, N, Acc, Context) ->
 	[#xmlNode{type = element,
 		  node = #xmlElement{} = PNode}|_] ->
 	    PrecedingSiblings = lists:sublist(get_content(PNode), 1,
-					      Node#xmlElement.pos-1),
+                                              get_position(Node) - 1),
 	    lists:foldr(
 	      fun(E, AccX) ->
 		      ThisN = #xmlNode{type = node_type(E),
@@ -655,7 +655,7 @@ match_attribute(Tok, N, Acc, Context) ->
 		      end
 	      end, Acc, E#xmlElement.attributes);
 	_Other ->
-	    []
+	    Acc
     end.

 node_type(#xmlAttribute{}) ->	attribute;
@@ -736,12 +736,12 @@ node_test({name, {_Tag, Prefix, Local}},
     case expanded_name(Prefix, Local, Context) of
 	[] ->
 	    ?dbg("node_test(~p, ~p) -> ~p.~n",
-		 [{Tag, Prefix, Local}, write_node(Name), false]),
+		 [{_Tag, Prefix, Local}, write_node(Name), false]),
 	    false;
 	ExpName ->
 	    Res = (ExpName == {NS#xmlNamespace.default,Name}),
 	    ?dbg("node_test(~p, ~p) -> ~p.~n",
-		 [{Tag, Prefix, Local}, write_node(Name), Res]),
+		 [{_Tag, Prefix, Local}, write_node(Name), Res]),
 	    Res
     end;
 node_test({name, {Tag,_Prefix,_Local}},
@@ -811,4 +811,11 @@ get_content(#xmlElement{content = F} = E
 get_content(#xmlDocument{content = C}) when list(C) ->
     C;
 get_content(#xmlDocument{content = C}) ->
-    [C].
+    [C];
+get_content(#xmlText{}) ->
+    [].
+
+get_position(#xmlElement{pos = N}) ->
+    N;
+get_position(#xmlText{pos = N}) ->
+    N.



More information about the erlang-bugs mailing list