xmerl_xpath.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 815 行 · 第 1/2 页

ERL
815
字号
		 parents = Parents},    NewParents = [N|Parents],    Acc1 = case node_test(Tok, N, Context) of	       true ->		   [N|Acc];	       false ->		   Acc	   end,    Acc2 = match_desc(get_content(E), NewParents, Tok, Acc1, Context),    match_desc(T, Parents, Tok, Acc2, Context);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);match_desc([], _Parents, _Tok, Acc, _Context) ->    Acc.			  %% "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).match_child(Tok, N, Acc, Context) ->    %io:format("match_child(~p)~n", [write_node(N)]),    #xmlNode{parents = Ps, node = Node, type = Type} = N,    case Type of	El when El == element; El == root_node ->	    NewPs = [N|Ps],	    lists:foldr(	      fun(E, AccX) ->		      ThisN = #xmlNode{type = node_type(E),				       node = E,				       parents = NewPs},		      case node_test(Tok, ThisN, Context) of			  true ->			      [ThisN|AccX];			  false ->			      AccX		      end	      end, Acc, get_content(Node));	_Other ->	    Acc    end.%% "The 'parent' axis contains the parent of the context node, %% if there is one."match_parent(Tok, N, Acc, Context) ->    case N#xmlNode.parents of	[] ->	    Acc;	[PN|_] ->	    case node_test(Tok, PN, Context) of		true ->		    [PN|Acc];		false ->		    Acc	    end    end.%% "The 'ancestor' axis contains the ancestors of the context node;%% the ancestors of the context node consists of the parent of the context%% node and the parent's parent and so on; thus, the ancestor axis will %% always include the root node, unless the context node is the root node."match_ancestor(Tok, N, Acc, Context) ->    Parents = N#xmlNode.parents,    lists:foldr(      fun(PN, AccX) ->	      case node_test(Tok, PN, Context) of		  true ->		      [PN|AccX];		  false ->		      AccX	      end      end, Acc, Parents).%% "The 'ancestor-or-self' axis contains the context node and the ancestors%% of the context node; thus, the acestor axis will always include the%% root node."match_ancestor_or_self(Tok, N, Acc, Context) ->    Acc1 = case node_test(Tok, N, Context) of	       true ->		   [N|Acc];	       false ->		   Acc	   end,    match_ancestor(Tok, N, Acc1, Context).match_following_sibling(_Tok, #xmlAttribute{}, Acc, _Context) ->    Acc;match_following_sibling(_Tok, #xmlNamespace{}, Acc, _Context) ->    Acc;match_following_sibling(Tok, N, Acc, Context) ->    #xmlNode{parents = Ps, node = Node} = N,    case Ps of	[#xmlNode{type = element,		  node = #xmlElement{} = PNode}|_] ->	    FollowingSiblings = lists:nthtail(Node#xmlElement.pos, 					      get_content(PNode)),	    lists:foldr(	      fun(E, AccX) ->		      ThisN = #xmlNode{type = node_type(E),				       node = E,				       parents = Ps},		      case node_test(Tok, ThisN, Context) of			  true ->			      [ThisN|AccX];			  false ->			      AccX		      end	      end, Acc, FollowingSiblings);	_Other ->	    Acc    end.%% "The 'following' axis contains all nodes in the same document as the%% context node that are after the context node in document order, excluding%% any descendants and excluding attribute nodes and namespace nodes."%% (UW: I interpret this as "following siblings and their descendants")match_following(Tok, N, Acc, Context) ->    #xmlNode{parents = Ps, node = Node} = N,    case Ps of	[#xmlNode{type = element,		  node = #xmlElement{} = PNode}|_] ->	    FollowingSiblings = lists:nthtail(Node#xmlElement.pos, 					      get_content(PNode)),	    lists:foldr(	      fun(E, AccX) ->		      ThisN = #xmlNode{type = node_type(E),				       node = E,				       parents = Ps},		      Acc1 =			  case node_test(Tok, ThisN, Context) of			      true ->				  [ThisN|AccX];			      false ->				  AccX			  end,		      match_desc(get_content(E), Tok, Ps, Acc1, Context)	      end, Acc, FollowingSiblings);	_Other ->	    Acc    end.%% "The preceding-sibling axis contains all the preceding siblings of the %% context node; if the context node is an attribute node or namespace node,%% the preceding-sibling axis is empty."match_preceding_sibling(_Tok, #xmlAttribute{}, Acc, _Context) ->    Acc;match_preceding_sibling(_Tok, #xmlNamespace{}, Acc, _Context) ->    Acc;match_preceding_sibling(Tok, N, Acc, Context) ->    #xmlNode{parents = Ps, node = Node} = N,    case Ps of	[#xmlNode{type = element,		  node = #xmlElement{} = PNode}|_] ->	    PrecedingSiblings = lists:sublist(get_content(PNode), 1,					      Node#xmlElement.pos-1), 	    lists:foldr(	      fun(E, AccX) ->		      ThisN = #xmlNode{type = node_type(E),				       node = E,				       parents = Ps},		      case node_test(Tok, ThisN, Context) of			  true ->			      [ThisN|AccX];			  false ->			      AccX		      end	      end, Acc, PrecedingSiblings);	_Other ->	    []    end.%% "The 'preceding' axis contains all nodes in the same document as the context%% node that are before the context node in document order, exluding any%% ancestors and excluding attribute nodes and namespace nodes."%% (UW: I interpret this as "preceding siblings and their descendants".)match_preceding(Tok, N, Acc, Context) ->    #xmlNode{parents = Ps, node = Node} = N,    case Ps of	[#xmlNode{type = element,		  node = #xmlElement{} = PNode}|_] ->	    PrecedingSiblings = lists:sublist(get_content(PNode), 1,					      Node#xmlElement.pos-1), 	    lists:foldr(	      fun(E, AccX) ->		      ThisN = #xmlNode{type = node_type(E),				       node = E,				       parents = Ps},		      Acc1 =			  case node_test(Tok, ThisN, Context) of			      true ->				  [ThisN|AccX];				  false ->				      AccX			  end,		      match_desc(get_content(E), Tok, Ps, Acc1, Context)	      end, Acc, PrecedingSiblings);	_Other ->	    []    end.%% "The 'attribute' axis contains the attributes of the context node; the%% axis will be empty unless the context node is an element."match_attribute(Tok, N, Acc, Context) ->    case N#xmlNode.type of	element ->	    #xmlNode{parents = Ps, node = E} = N,	    lists:foldl(	      fun(A, AccX) ->		      ThisN = #xmlNode{type = attribute,				       node = A,				       parents = [N|Ps]},		      case node_test(Tok, ThisN, Context) of			  true ->			      [ThisN|AccX];			  false ->			      AccX		      end	      end, Acc, E#xmlElement.attributes);	_Other ->	    []    end.node_type(#xmlAttribute{}) ->	attribute;node_type(#xmlElement{}) ->	element;node_type(#xmlText{}) ->	text;node_type(#xmlPI{}) ->		processing_instruction;node_type(#xmlNamespace{}) ->	namespace;node_type(#xmlDocument{}) ->	root_node.%% "The namespace axis contains the namespace nodes of the context node;%% the axis will be empty unless the context node is an element."%match_namespace(_Tok, _N, _Acc, _Context) ->    %% TODO: IMPLEMENT NAMESPACE AXIS%    erlang:fault(not_yet_implemented).update_nodeset(Context = #xmlContext{axis_type = reverse}, NodeSet) ->    Context#xmlContext{nodeset = reverse(NodeSet)};update_nodeset(Context, NodeSet) ->    Context#xmlContext{nodeset = forward(NodeSet)}.reverse(NodeSet) ->    reverse(NodeSet, 1, []).reverse([H|T], Pos, Acc) ->    reverse(T, Pos+1, [H#xmlNode{pos = Pos}|Acc]);reverse([], _Pos, Acc) ->    Acc.forward(NodeSet) ->    forward(NodeSet, 1).forward([H|T], Pos) ->    [H#xmlNode{pos = Pos}|forward(T, Pos+1)];forward([], _Pos) ->    [].node_test(F, N, Context) when function(F) ->    F(N, Context);node_test({wildcard, _}, #xmlNode{type=ElAt}, _Context)   when ElAt==element; ElAt==attribute ->     true;node_test({prefix_test, Prefix}, #xmlNode{node = N}, _Context) ->    case N of	#xmlElement{nsinfo = {Prefix, _}} -> true;	#xmlAttribute{nsinfo = {Prefix, _}} -> true;	_ ->	    false    end;node_test({name, {Tag, _Prefix, _Local}}, 	  #xmlNode{node = #xmlElement{name = Tag}}=_N, _Context) ->     %io:format("node_test({tag, ~p}, ~p) -> true.~n", [Tag, write_node(_N)]),    true;node_test({name, {Tag, Prefix, Local}}, 	  #xmlNode{node = #xmlElement{name = Name,				      expanded_name = EExpName,				      nsinfo = {_Prefix1, _}				     }}, Context) ->     case expanded_name(Prefix, Local, Context) of	[] ->	    Res = (Tag == Name),	    ?dbg("node_test(~p, ~p) -> ~p.~n", 		 [{Tag, Prefix, Local}, write_node(Name), Res]),	    Res;	ExpName ->	    Res = (ExpName == EExpName),	    ?dbg("node_test(~p, ~p) -> ~p.~n", 		 [{Tag, Prefix, Local}, write_node(Name), Res]),	    Res    end;node_test({name, {_Tag, Prefix, Local}}, 	  #xmlNode{node = #xmlElement{name = Name,				      expanded_name = _EExpName,				      namespace = NS				     }}, Context) ->     case expanded_name(Prefix, Local, Context) of	[] ->	    ?dbg("node_test(~p, ~p) -> ~p.~n", 		 [{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]),	    Res    end;node_test({name, {Tag,_Prefix,_Local}}, 	  #xmlNode{node = #xmlAttribute{name = Tag}}, _Context) ->     true;node_test({name, {_Tag, Prefix, Local}}, 	  #xmlNode{node = #xmlAttribute{expanded_name = {URI, Local},					nsinfo = {_Prefix1, _},					namespace = NS}}, _Context) ->     NSNodes = NS#xmlNamespace.nodes,    case lists:keysearch(Prefix, 1, NSNodes) of	{value, {_, URI}} ->	    ?dbg("node_test(~, ~p) -> true.~n", 		 [{_Tag, Prefix, Local}, write_node(NSNodes)]),	    true;	false ->	    ?dbg("node_test(~, ~p) -> false.~n", 		 [{_Tag, Prefix, Local}, write_node(NSNodes)]),	    false    end;node_test({node_type, NT}, #xmlNode{node = N}, _Context) ->    case {NT, N} of	{text, #xmlText{}} ->	    true;	{node, _} ->	    true;	{attribute, #xmlAttribute{}} ->	    true;	{namespace, #xmlNamespace{}} ->	    true;	_ ->	    false    end;node_test({processing_instruction, {literal, _, Name}}, 	  #xmlNode{node = {processing_instruction, Name, _Data}}, _Context) ->    true;node_test(_Other, _N, _Context) ->    %io:format("node_test(~p, ~p) -> false.~n", [_Other, write_node(_N)]),    false.expanded_name(Prefix, Local, #xmlContext{namespace = NS}) ->    case lists:keysearch(Prefix, 1, NS) of	{value, {_, URI}} ->	    {URI, list_to_atom(Local)};	false ->	    []    end.to_atom(A) when atom(A) -> A;to_atom(S) when list(S) -> list_to_atom(S).to_string(A) when atom(A) -> atom_to_list(A);to_string(S) when list(S) -> S.get_content(#xmlElement{content = C}) when list(C) ->    C;get_content(#xmlElement{content = F} = E) when function(F) ->    case F() of	C when list(C) ->	    C;	_Other ->	    exit({bad_content, E})    end;get_content(#xmlDocument{content = C}) when list(C) ->    C;get_content(#xmlDocument{content = C}) ->    [C].

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?