%% xpath_functions.erl %% @author Pablo Polvorin %% @doc Some core xpath functions that can be used in xpath expressions %% created on 2008-05-07 -module(xpath_functions). -export([lookup_function/1]). %% Default functions. %% The format is: {FunctionName, fun(), FunctionSignature} %% WildCard argspec must be the last spec in list. %% %% @type FunctionName = atom() %% @type FunctionSignature = [XPathArgSpec] %% @type XPathArgSpec = XPathType | WildCardArgSpec %% @type WildCardArgSpec = {'*', XPathType} %% @type XPathType = node_set | string | number | boolean %% %% The engine is responsable of calling the function with %% the correct arguments, given the function signature. -spec lookup_function(atom()) -> xpath:xpath_fun_spec() | false. lookup_function('last') -> {'last',fun last/2,[]}; lookup_function('position') -> {'position',fun position/2,[]}; lookup_function('count') -> {'count',fun count/2,[node_set]}; lookup_function('concat') -> {'concat',fun concat/2,[{'*', string}]}; lookup_function('name') -> {'name',fun 'name'/2,[node_set]}; lookup_function('starts-with') -> {'starts-with', fun 'starts-with'/2,[string,string]}; lookup_function('ends-with') -> {'ends-with', fun 'ends-with'/2,[string,string]}; lookup_function('contains') -> {'contains', fun 'contains'/2,[string,string]}; lookup_function('substring') -> {'substring', fun substring/2,[string,number,number]}; lookup_function('sum') -> {'sum', fun sum/2,[node_set]}; lookup_function('string-length') -> {'string-length', fun 'string-length'/2,[string]}; lookup_function('not') -> {'not', fun x_not/2, [boolean]}; lookup_function('string') -> {'string', fun 'string'/2, [node_set]}; lookup_function(_) -> false. %% @doc Function: int last() %% The last function returns the context size of the current node last({ctx, _, _, _, _, Size} = _Ctx, []) -> Size. %% @doc Function: number position() %% The position function returns the position of the current node position({ctx, _, _, _, Position, _} = _Ctx, []) -> Position. %% @doc Function: number count(node-set) %% The count function returns the number of nodes in the %% argument node-set. count(_Ctx,[NodeList]) -> length(NodeList). %% @doc Function: concat(binary, binary, ...) %% Concatenate string arguments (variable length) concat(_Ctx, BinariesList) -> %% list_to_binary() << <> || Str <- BinariesList>>. %% @doc Function: string name(node-set?) 'name'(_Ctx,[[{Tag,_,_,_}|_]]) -> Tag. %% @doc Function: boolean starts-with(string, string) %% The starts-with function returns true if the first argument string %% starts with the second argument string, and otherwise returns false. 'starts-with'(_Ctx,[Left,Right]) -> Size = size(Right), case Left of <> -> true; _ -> false end. %% @doc Function: boolean ends-with(string, string) %% The ends-with function returns true if the first argument string %% ends with the second argument string, and otherwise returns false. 'ends-with'(_Ctx,[Left,Right]) -> Size = size(Right), Dsize = size(Left) - Size, case Left of <<_:Dsize/binary,Right:Size/binary>> -> true; _ -> false end. %% @doc Function: checks that Where contains What contains(_Ctx,[Where, What]) -> case binary:match(Where, [What]) of nomatch -> false; {_, _} -> true end. %% @doc Function: string substring(string, number, number?) %% The substring function returns the substring of the first argument %% starting at the position specified in the second argument with length %% specified in the third argument substring(_Ctx,[String,Start,Length]) when is_binary(String)-> Before = Start -1, After = size(String) - Before - Length, case (Start + Length) =< size(String) of true -> <<_:Before/binary,R:Length/binary,_:After/binary>> = String, R; false -> <<>> end. %% @doc Function: number sum(node-set) %% The sum function returns the sum, for each node in the argument %% node-set, of the result of converting the string-values of the node %% to a number. sum(_Ctx,[Values]) -> lists:sum([xpath_utils:number_value(V) || V <- Values]). %% @doc Function: number string-length(string?) %% The string-length returns the number of characters in the string %% TODO: this isn't true: currently it returns the number of bytes %% in the string, that isn't the same 'string-length'(_Ctx,[String]) -> size(String). %% @doc Function: string string(node_set) %% %% The sum function returns the string representation of the %% nodes in a node-set. This is different from text() in that %% it concatenates each bit of the text in the node along with the text in %% any children nodes along the way, in order. %% Note: this differs from normal xpath in that it returns a list of strings, one %% for each node in the node set, as opposed to just the first node. 'string'(_Ctx, [NodeList]) -> lists:map(fun({_Elem, _Attr, Children,_Pos}) -> concat_child_text(Children, []) end, NodeList). concat_child_text([], Result) -> list_to_binary(lists:reverse(Result)); concat_child_text([{_,_,Children,_} | Rest], Result) -> concat_child_text(Rest, [concat_child_text(Children, []) | Result]); concat_child_text([X | Rest], Result) -> concat_child_text(Rest, [X | Result]). x_not(_Ctx, [Bool]) -> not Bool.