1%% @author Pablo Polvorin
2%% @doc Compile XPath expressions.
3%% This module uses the xpath parser of xmerl.. that interface isn't documented
4%% so could change between OTP versions.. its know to work with OTP R12B2
5%% created on 2008-05-07
6-module(mochiweb_xpath_parser).
7
8-export([compile_xpath/1]).
9
10%% Return a compiled XPath expression
11compile_xpath(XPathString) ->
12    {ok,XPath} = xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens(XPathString)),
13    simplify(XPath).
14
15
16
17%% @doc Utility functions to convert between the *internal* representation of
18%       xpath expressions used in xmerl(using lists and atoms), to a
19%       representation using only binaries, to match the way in
20%       which the mochiweb html parser represents data
21simplify({path, union, {Path1, Path2}})->
22    %% "expr1 | expr2 | expr3"
23    {path, union, {simplify(Path1), simplify(Path2)}};
24simplify({path,Type,Path}) ->
25    {path,Type,simplify_path(Path)};
26simplify({comp,Comp,A,B}) ->
27    {comp,Comp,simplify(A),simplify(B)};
28simplify({literal,L}) ->
29    {literal,list_to_binary(L)};
30simplify({number,N}) ->
31    {number,N};
32simplify({negative, Smth}) ->
33    {negative, simplify(Smth)};
34simplify({bool, Comp, A, B}) ->
35    {bool, Comp, simplify(A), simplify(B)};
36simplify({function_call,Fun,Args}) ->
37    {function_call,Fun,lists:map(fun simplify/1,Args)};
38simplify({arith, Op, Arg1, Arg2}) ->
39	{arith, Op, simplify(Arg1), simplify(Arg2)}.
40
41
42simplify_path({step,{Axis,NodeTest,Predicates}}) ->
43    {step,{Axis,
44            simplify_node_test(NodeTest),
45            simplify_predicates(Predicates)}};
46simplify_path({refine,Path1,Path2}) ->
47    {refine,simplify_path(Path1),simplify_path(Path2)}.
48
49
50simplify_node_test({name,{Tag,Prefix,Local}}) ->
51    {name,{to_binary(Tag),Prefix,Local}};
52
53simplify_node_test(A={node_type, _Type}) ->
54    A;
55simplify_node_test({processing_instruction, Name}) ->
56    {processing_instruction, list_to_binary(Name)};  % strictly, this must be node_type too!
57simplify_node_test(A={wildcard,wildcard}) ->
58    A;
59simplify_node_test({prefix_test, Prefix}) ->
60    %% [37] /prefix:*/ - namespace test
61    {prefix_test, list_to_binary(Prefix)}.
62
63
64simplify_predicates(X) -> lists:map(fun simplify_predicate/1,X).
65simplify_predicate({pred,Pred}) ->
66    {pred,simplify(Pred)}.
67
68to_binary(X) when is_atom(X) -> list_to_binary(atom_to_list(X)).
69
70
71
72
73