⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmerl_xpath.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 2 页
字号:
%%% The contents of this file are subject to the Erlang Public License,%%% Version 1.0, (the "License"); you may not use this file except in%%% compliance with the License. You may obtain a copy of the License at%%% http://www.erlang.org/license/EPL1_0.txt%%%%%% Software distributed under the License is distributed on an "AS IS"%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%%% the License for the specific language governing rights and limitations%%% under the License.%%%%%% The Original Code is xmerl-0.13%%%%%% The Initial Developer of the Original Code is Ericsson Telecom%%% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson%%% Telecom AB. All Rights Reserved.%%%%%% Contributor(s): ______________________________________.%%%%%%----------------------------------------------------------------------%%% #0.    BASIC INFORMATION%%%----------------------------------------------------------------------%%% File:       xmerl_xpath.erl%%% Author       : Ulf Wiger <ulf.wiger@ericsson.com>%%% Description  : Implements a search engine based on XPath%%% %%% Modules used : lists, xmerl_xpath_parse, xmerl_xpath_pred, %%%		   xmerl_xpath_scan%%% %%%----------------------------------------------------------------------%% @doc The xmerl_xpath module handles the entire XPath 1.0 spec%% XPath expressions typically occurs in XML attributes and are used to addres%% parts of an XML document.%     The grammar is defined in <code>xmerl_xpath_parse.yrl</code>.%     The core functions are defined in <code>xmerl_xpath_pred.erl</code>.%%     <p>Some useful shell commands for debugging the XPath parser</p>% <pre>% c(xmerl_xpath_scan).% yecc:yecc("xmerl_xpath_parse.yrl", "xmerl_xpath_parse", true, []).% c(xmerl_xpath_parse).%% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("position() > -1")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("5 * 6 div 2")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("5 + 6 mod 2")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("5 * 6")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("-----6")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("parent::node()")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("descendant-or-self::node()")).% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("parent::processing-instruction('foo')")).%% </pre>%%%% @type docEntity() = %%      xmlElement()%%    | xmlAttribute()%%    | xmlText() %%    | xmlPI()%%    | xmlComment()%% @type nodeEntity() = %%      xmlElement()%%    | xmlAttribute()%%    | xmlText() %%    | xmlPI()%%    | xmlNamespace()%%    | xmlDocument()%% @type option_list(). <p>Options allows to customize the behaviour of the%%     XPath scanner.%% </p>%% Possible options are:%% <dl>%%  <dt><code>{namespace, #xmlNamespace}</code></dt>%%    <dd>Set namespace nodes, from XmlNamspace, in xmlContext</dd>%%  <dt><code>{namespace, Nodes}</code></dt>%%    <dd>Set namespace nodes in xmlContext.</dd>%% </dl>%%  <dt><code>{bindings, Bs}</code></dt>%%   <dd></dd>%% <dt><code>{functions, Fs}</code></dt>%%   <dd></dd>-module(xmerl_xpath).-vsn('0.13').-date('01-02-21').-author('ulf.wiger@ericsson.com').%% main API-export([string/2,	 string/3,	 string/5]).%% exported helper functions, internal for the XPath support-export([eval_path/3,	 axis/3, axis/4]).%% debug function-export([write_node/1]).-include("xmerl.hrl").-record(state, {context = #xmlContext{},		acc = []}).%% -record(node, {node,%% 	       pos,%% 	       parents}).-define(nodeset(NS), #state{context = #xmlContext{nodeset = NS}}).-define(context(C), #state{context = C}).%% @spec string(Str, Doc) -> docEntity()%% @equiv string(Str,Doc, [])string(Str, Doc) ->    string(Str, Doc, []).%% @spec string(Str,Doc,Options) -> %%      docEntity()%% @equiv string(Str,Doc, [],Doc,Options)string(Str, Doc, Options) ->    string(Str, Doc, [], Doc, Options).%% @spec string(Str,Node,Parents,Doc,Options) ->%%      docEntity()%%   Str     = xPathString()%%   Node    = nodeEntity()%%   Parents = parentList()%%   Doc     = nodeEntity()%%   Options = option_list()%% @doc Extracts the nodes from the parsed XML tree according to XPath.string(Str, Node, Parents, Doc, Options) ->    FullParents = 	case Parents of	    [] ->		[];	    [{H, P}|_] when atom(H), integer(P) ->		full_parents(Parents, Doc)	end,%io:format("string FullParents=~p~n",[FullParents]),    ContextNode=#xmlNode{type = node_type(Node),			 node = Node,			 parents = FullParents},%io:format("string ContextNode=~p~n",[ContextNode]),    WholeDoc = whole_document(Doc),%io:format("string WholeDoc=~p~n",[WholeDoc]),    Context=(new_context(Options))#xmlContext{context_node = ContextNode,					      whole_document = WholeDoc},%io:format("string Context=~p~n",[Context]),    #state{context =  NewContext} = match(Str, #state{context = Context}),%io:format("string NewContext=~p~n",[NewContext]),    [N || #xmlNode{node = N} <- NewContext#xmlContext.nodeset].whole_document(#xmlDocument{} = Doc) ->    #xmlNode{type = root_node,	     node = Doc,	     parents = []};whole_document(Other) ->    #xmlNode{type = root_node,	     node = #xmlDocument{content = Other},	     parents = []}.new_context(Options) ->    new_context(Options, #xmlContext{}).new_context([{namespace, #xmlNamespace{nodes = Nodes}}|T], C) ->    new_context(T, C#xmlContext{namespace = ns_nodes(Nodes)});new_context([{namespace, Nodes}|T], C) ->    new_context(T, C#xmlContext{namespace = ns_nodes(Nodes)});new_context([{bindings, Bs}|T], C) ->    new_context(T, C#xmlContext{bindings = Bs});new_context([{functions, Fs}|T], C) ->    new_context(T, C#xmlContext{functions = Fs});new_context([], C) ->    C.ns_nodes([{Prefix, URI}|T]) ->    [{to_string(Prefix), to_atom(URI)}|ns_nodes(T)];ns_nodes([]) ->    [].full_parents(Ps, Doc) ->    full_parents1(lists:reverse(Ps), [Doc], []).full_parents1([{Name, Pos}|Ns], Content, Parents) ->    E = locate_element(Name, Pos, Content),    PN = #xmlNode{type = element,		  node = E,		  parents = Parents},    full_parents1(Ns, get_content(E), [PN|Parents]);full_parents1([], _E, Parents) ->    Parents.locate_element(Name, Pos, [E = #xmlElement{name = Name, pos = Pos}|_]) ->    E;locate_element(_Name, Pos, [#xmlElement{pos = P}|_]) when P >= Pos ->    %% we've passed Pos (P > Pos) or the name is wrong (P == Pos)    exit(invalid_parents);locate_element(_Name, _Pos, []) ->    exit(invalid_parents);locate_element(Name, Pos, [_|T]) ->    locate_element(Name, Pos, T).match(Str, S = #state{}) ->    Tokens = xmerl_xpath_scan:tokens(Str),    case xmerl_xpath_parse:parse(Tokens) of	{ok, Expr} ->	    match_expr(Expr, S);	Error ->	    Error    end.match_expr({path, Type, Arg}, S) ->    eval_path(Type, Arg, S#state.context).path_expr({refine, StepExpr1, StepExpr2}, S) ->    ?dbg("StepExpr1=~p StepExpr2=~p~n", [StepExpr1,StepExpr2]),    ?dbg("length(nodeset) = ~p~n", 	 [length((S#state.context)#xmlContext.nodeset)]),    S1 = path_expr(StepExpr1, S),    ?dbg("length(nodeset1) = ~p~n", 	 [length((S1#state.context)#xmlContext.nodeset)]),    path_expr(StepExpr2, S1);path_expr({step, {Axis, NodeTest, PredExpr}}, S = #state{context = C,							 acc = Acc}) ->    ?dbg("PredExpr = ~p~n", [PredExpr]),    NewContext = axis(Axis, NodeTest, C, Acc),    pred_expr(PredExpr, S#state{context = NewContext}).pred_expr([], S) ->    S;pred_expr([{pred, Pred}|Preds], S = #state{}) ->    ?dbg("Pred = ~p~n", [Pred]),    NewS = eval_pred(Pred, S),    pred_expr(Preds, NewS).%% simple case: the predicate is a number, e.g. para[5].%% No need to iterate over all nodes in the nodeset; we know what to do.%%eval_pred({number, N}, S = #state{context = C = #xmlContext{nodeset = NS}}) ->    case length(NS)>=N of	true ->	    NewNodeSet = [lists:nth(N, NS)],	    NewContext = C#xmlContext{nodeset = NewNodeSet},	    S#state{context = NewContext};	false -> S#state{context = C#xmlContext{nodeset = []}}    end;eval_pred(Predicate, S = #state{context = C = 				#xmlContext{nodeset = NodeSet}}) ->    NewNodeSet = 	lists:filter(	  fun(Node) ->		  %io:format("current node: ~p~n", [write_node(Node)]),		  ThisContext = C#xmlContext{context_node = Node},		  xmerl_xpath_pred:eval(Predicate, ThisContext)	  end, NodeSet),    NewContext = C#xmlContext{nodeset = NewNodeSet},    S#state{context = NewContext}.        %% write_node(Node::xmlNode()) -> {Type,Pos,Name,Parents}%% Helper function to access essential information from the xmlNode record.%% @hiddenwrite_node(#xmlNode{pos = Pos,		    node = #xmlAttribute{name = Name,					 parents = Ps}}) ->    {attribute, Pos, Name, Ps};write_node(#xmlNode{pos = Pos,		    node = #xmlElement{name = Name,				       parents = Ps}}) ->    {element, Pos, Name, Ps};write_node(#xmlNode{pos = Pos,		    node = #xmlText{value = Txt,				    parents = Ps}}) ->    {text, Pos, Txt, Ps};write_node(_) ->    other.%% eval_path(Type,Arg,S::state()) -> state()%% Eval path%% @hiddeneval_path(union, {PathExpr1, PathExpr2}, C = #xmlContext{}) ->    S = #state{context = C},    S1 = match_expr(PathExpr1, S),    NewNodeSet = (S#state.context)#xmlContext.nodeset,    match_expr(PathExpr2, S1#state{acc = NewNodeSet});eval_path(abs, PathExpr, C = #xmlContext{}) ->    NodeSet = [C#xmlContext.whole_document],    Context = C#xmlContext{nodeset = NodeSet},    S = #state{context = Context},    path_expr(PathExpr, S);eval_path(rel, PathExpr, C = #xmlContext{}) ->    NodeSet = [C#xmlContext.context_node],    Context = C#xmlContext{nodeset = NodeSet},    S = #state{context = Context},    path_expr(PathExpr, S);eval_path(filter, {PathExpr, PredExpr}, C = #xmlContext{}) ->    S = #state{context = C},    S1 = path_expr(PathExpr, S),    pred_expr(PredExpr, S1).%% axis(Axis,NodeTest,Context::xmlContext()) -> xmlContext()%% axis(Axis,NodeTest,Context,[])%% @hiddenaxis(Axis, NodeTest, Context) ->    axis(Axis, NodeTest, Context, []).%% axis(Axis,NodeTest,Context::xmlContext(),Acc) -> xmlContext()%%  %% An axis specifies the tree relationship between the nodes selected by%% the location step and the context node.%% @hiddenaxis(Axis, NodeTest, Context = #xmlContext{nodeset = NS0}, Acc) ->    NewNodeSet=lists:foldr(		 fun(N, AccX) ->			 axis1(Axis, NodeTest, N, AccX, Context)		 end, Acc, NS0),    update_nodeset(fwd_or_reverse(Axis, Context), NewNodeSet).axis1(self, Tok, N, Acc, Context) ->    match_self(Tok, N, Acc, Context);axis1(descendant, Tok, N, Acc, Context) ->    match_descendant(Tok, N, Acc, Context);axis1(child, Tok, N, Acc, Context) ->    match_child(Tok, N, Acc, Context);axis1(parent, Tok, N, Acc, Context) ->    match_parent(Tok, N, Acc, Context);axis1(ancestor, Tok, N, Acc, Context) ->    match_ancestor(Tok, N, Acc, Context);axis1(following_sibling, Tok, N, Acc, Context) ->    match_following_sibling(Tok, N, Acc, Context);axis1(preceding_sibling, Tok, N, Acc, Context) ->    match_preceding_sibling(Tok, N, Acc, Context);axis1(following, Tok, N, Acc, Context) ->    match_following(Tok, N, Acc, Context);axis1(preceding, Tok, N, Acc, Context) ->    match_preceding(Tok, N, Acc, Context);axis1(attribute, Tok, N, Acc, Context) ->    match_attribute(Tok, N, Acc, Context);%axis1(namespace, Tok, N, Acc, Context) ->%    match_namespace(Tok, N, Acc, Context);axis1(ancestor_or_self, Tok, N, Acc, Context) ->    match_ancestor_or_self(Tok, N, Acc, Context);axis1(descendant_or_self, Tok, N, Acc, Context) ->    match_descendant_or_self(Tok, N, Acc, Context).fwd_or_reverse(ancestor, Context) ->    reverse_axis(Context);fwd_or_reverse(preceding_sibling, Context) ->    reverse_axis(Context);fwd_or_reverse(preceding, Context) ->    reverse_axis(Context);fwd_or_reverse(_, Context) ->    forward_axis(Context).reverse_axis(Context) ->    Context#xmlContext{axis_type = reverse}.forward_axis(Context) ->    Context#xmlContext{axis_type = forward}.match_self(Tok, N, Acc, Context) ->    case node_test(Tok, N, Context) of	true ->	    %io:format("node_test -> true.~n", []),	    [N|Acc];	false ->	    Acc    end.match_descendant(Tok, N, Acc, Context) ->    #xmlNode{parents = Ps, node = Node, type = Type} = N,    case Type of	El when El == element; El == root_node ->%	element ->	    NewPs = [N|Ps],	    match_desc(get_content(Node), NewPs, Tok, Acc, Context);	_Other ->	    Acc    end.%match_desc(Content, Parents, Tok, Context) ->%    match_desc(Content, Parents, Tok, [], Context).match_desc([E = #xmlElement{}|T], Parents, Tok, Acc, Context) ->    N = #xmlNode{type = node_type(E),		 node = E,

⌨️ 快捷键说明

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