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 + -
显示快捷键?