114
%% @spec string(Str, Doc) -> docEntity()
112
%% @spec string(Str, Doc) -> [docEntity()] | Scalar
115
113
%% @equiv string(Str,Doc, [])
116
114
string(Str, Doc) ->
117
115
string(Str, Doc, []).
119
117
%% @spec string(Str,Doc,Options) ->
118
%% [docEntity()] | Scalar
121
119
%% @equiv string(Str,Doc, [],Doc,Options)
122
120
string(Str, Doc, Options) ->
123
121
string(Str, Doc, [], Doc, Options).
125
123
%% @spec string(Str,Node,Parents,Doc,Options) ->
124
%% [docEntity()] | Scalar
127
125
%% Str = xPathString()
128
126
%% Node = nodeEntity()
129
127
%% Parents = parentList()
130
128
%% Doc = nodeEntity()
131
129
%% Options = option_list()
132
131
%% @doc Extracts the nodes from the parsed XML tree according to XPath.
132
%% xmlObj is a record with fields type and value,
133
%% where type is boolean | number | string
133
134
string(Str, Node, Parents, Doc, Options) ->
135
%% record with fields type and value,
136
%% where type is boolean | number | string
148
151
Context=(new_context(Options))#xmlContext{context_node = ContextNode,
149
152
whole_document = WholeDoc},
150
153
%io:format("string Context=~p~n",[Context]),
151
#state{context = NewContext} = match(Str, #state{context = Context}),
154
#state{context = NewContext} = match(Str, #state{context = Context}),
152
155
%io:format("string NewContext=~p~n",[NewContext]),
153
[N || #xmlNode{node = N} <- NewContext#xmlContext.nodeset].
156
case NewContext#xmlContext.nodeset of
157
ScalObj = #xmlObj{type=Scalar}
158
when Scalar == boolean; Scalar == number; Scalar == string ->
160
#xmlObj{type=nodeset,value=NodeSet} ->
163
[N || #xmlNode{node = N} <- NewContext#xmlContext.nodeset]
156
167
whole_document(#xmlDocument{} = Doc) ->
220
231
match_expr({path, Type, Arg}, S) ->
221
eval_path(Type, Arg, S#state.context).
232
eval_path(Type, Arg, S#state.context);
234
match_expr(PrimExpr,S) ->
235
eval_primary_expr(PrimExpr,S).
237
251
?dbg("PredExpr = ~p~n", [PredExpr]),
238
252
NewContext = axis(Axis, NodeTest, C, Acc),
239
pred_expr(PredExpr, S#state{context = NewContext}).
253
pred_expr(PredExpr, S#state{context = NewContext});
243
258
pred_expr([], S) ->
250
265
%% simple case: the predicate is a number, e.g. para[5].
251
266
%% No need to iterate over all nodes in the nodeset; we know what to do.
253
eval_pred({number, N}, S = #state{context = C = #xmlContext{nodeset = NS}}) ->
254
case length(NS)>=N of
268
eval_pred({number, N0},
269
S = #state{context = C = #xmlContext{nodeset = NS,
270
axis_type = AxisType}}) ->
256
280
NewNodeSet = [lists:nth(N, NS)],
257
281
NewContext = C#xmlContext{nodeset = NewNodeSet},
258
282
S#state{context = NewContext};
297
321
eval_path(union, {PathExpr1, PathExpr2}, C = #xmlContext{}) ->
298
322
S = #state{context = C},
299
323
S1 = match_expr(PathExpr1, S),
300
NewNodeSet = (S#state.context)#xmlContext.nodeset,
301
match_expr(PathExpr2, S1#state{acc = NewNodeSet});
324
%% NewNodeSet = (S1#state.context)#xmlContext.nodeset,
325
S2 = match_expr(PathExpr2, S1#state{context=C}),
326
NodeSet1 = (S1#state.context)#xmlContext.nodeset,
327
NodeSet2 = (S2#state.context)#xmlContext.nodeset,
328
NewNodeSet = ordsets:to_list(ordsets:union(ordsets:from_list(NodeSet1),
329
ordsets:from_list(NodeSet2))),
330
S2#state{context=(S2#state.context)#xmlContext{nodeset=NewNodeSet}};
302
331
eval_path(abs, PathExpr, C = #xmlContext{}) ->
303
332
NodeSet = [C#xmlContext.whole_document],
304
333
Context = C#xmlContext{nodeset = NodeSet},
314
343
S1 = path_expr(PathExpr, S),
315
344
pred_expr(PredExpr, S1).
346
eval_primary_expr(FC = {function_call,_,_},S = #state{context = Context}) ->
347
%% NewNodeSet = xmerl_xpath_pred:eval(FC, Context),
348
NewNodeSet = xmerl_xpath_lib:eval(primary_expr, FC, Context),
349
NewContext = Context#xmlContext{nodeset = NewNodeSet},
350
S#state{context = NewContext};
351
eval_primary_expr(PrimExpr,_S) ->
352
exit({primary_expression,{not_implemented, PrimExpr}}).
318
355
%% axis(Axis,NodeTest,Context::xmlContext()) -> xmlContext()
319
356
%% axis(Axis,NodeTest,Context,[])
366
403
fwd_or_reverse(ancestor, Context) ->
367
404
reverse_axis(Context);
405
fwd_or_reverse(ancestor_or_self, Context) ->
406
reverse_axis(Context);
368
407
fwd_or_reverse(preceding_sibling, Context) ->
369
408
reverse_axis(Context);
370
409
fwd_or_reverse(preceding, Context) ->
382
421
match_self(Tok, N, Acc, Context) ->
383
422
case node_test(Tok, N, Context) of
385
%io:format("node_test -> true.~n", []),
393
431
#xmlNode{parents = Ps, node = Node, type = Type} = N,
395
433
El when El == element; El == root_node ->
398
435
match_desc(get_content(Node), NewPs, Tok, Acc, Context);
403
%match_desc(Content, Parents, Tok, Context) ->
404
% match_desc(Content, Parents, Tok, [], Context).
406
441
match_desc([E = #xmlElement{}|T], Parents, Tok, Acc, Context) ->
442
Acc1 = match_desc(T, Parents, Tok, Acc, Context),
407
443
N = #xmlNode{type = node_type(E),
409
445
parents = Parents},
410
446
NewParents = [N|Parents],
411
Acc1 = case node_test(Tok, N, Context) of
417
447
Acc2 = match_desc(get_content(E), NewParents, Tok, Acc1, Context),
418
match_desc(T, Parents, Tok, Acc2, Context);
448
match_self(Tok, N, Acc2, Context);
419
449
match_desc([E|T], Parents, Tok, Acc, Context) ->
450
Acc1 = match_desc(T, Parents, Tok, Acc, Context),
420
451
N = #xmlNode{node = E,
421
452
type = node_type(E),
422
453
parents = Parents},
423
Acc1 = case node_test(Tok, N, Context) of
429
match_desc(T, Parents, Tok, Acc1, Context);
454
match_self(Tok, N, Acc1, Context);
430
455
match_desc([], _Parents, _Tok, Acc, _Context) ->
435
460
%% "The 'descendant-or-self' axis contains the context node and the
436
461
%% descendants of the context node."
437
462
match_descendant_or_self(Tok, N, Acc, Context) ->
438
Acc1 = case node_test(Tok, N, Context) of
444
match_descendant(Tok, N, Acc1, Context).
463
Acc1 = match_descendant(Tok, N, Acc, Context),
464
match_self(Tok, N, Acc1, Context).
447
467
match_child(Tok, N, Acc, Context) ->
455
475
ThisN = #xmlNode{type = node_type(E),
457
477
parents = NewPs},
458
case node_test(Tok, ThisN, Context) of
478
match_self(Tok, ThisN, AccX, Context)
464
479
end, Acc, get_content(Node));
489
499
%% always include the root node, unless the context node is the root node."
490
500
match_ancestor(Tok, N, Acc, Context) ->
491
501
Parents = N#xmlNode.parents,
494
case node_test(Tok, PN, Context) of
504
match_self(Tok, PN, AccX, Context)
500
505
end, Acc, Parents).
506
511
%% of the context node; thus, the acestor axis will always include the
508
513
match_ancestor_or_self(Tok, N, Acc, Context) ->
509
Acc1 = case node_test(Tok, N, Context) of
514
Acc1 = match_self(Tok, N, Acc, Context),
515
515
match_ancestor(Tok, N, Acc1, Context).
526
526
[#xmlNode{type = element,
527
527
node = #xmlElement{} = PNode}|_] ->
528
FollowingSiblings = lists:nthtail(Node#xmlElement.pos,
528
FollowingSiblings = lists:nthtail(get_position(Node),
529
529
get_content(PNode)),
532
532
ThisN = #xmlNode{type = node_type(E),
535
case node_test(Tok, ThisN, Context) of
535
match_self(Tok, ThisN, AccX, Context)
541
536
end, Acc, FollowingSiblings);
547
542
%% "The 'following' axis contains all nodes in the same document as the
548
543
%% context node that are after the context node in document order, excluding
549
544
%% any descendants and excluding attribute nodes and namespace nodes."
550
%% (UW: I interpret this as "following siblings and their descendants")
551
545
match_following(Tok, N, Acc, Context) ->
552
546
#xmlNode{parents = Ps, node = Node} = N,
554
548
[#xmlNode{type = element,
555
node = #xmlElement{} = PNode}|_] ->
556
FollowingSiblings = lists:nthtail(Node#xmlElement.pos,
549
node = #xmlElement{} = PNode} = P|_] ->
550
FollowingSiblings = lists:nthtail(get_position(Node),
557
551
get_content(PNode)),
552
Acc0 = match_following(Tok, P, Acc, Context),
560
555
ThisN = #xmlNode{type = node_type(E),
564
case node_test(Tok, ThisN, Context) of
570
match_desc(get_content(E), Tok, Ps, Acc1, Context)
571
end, Acc, FollowingSiblings);
558
match_descendant_or_self(Tok, ThisN, AccX, Context)
559
end, Acc0, FollowingSiblings);
588
576
[#xmlNode{type = element,
589
577
node = #xmlElement{} = PNode}|_] ->
590
578
PrecedingSiblings = lists:sublist(get_content(PNode), 1,
591
Node#xmlElement.pos-1),
579
get_position(Node) - 1),
594
582
ThisN = #xmlNode{type = node_type(E),
597
case node_test(Tok, ThisN, Context) of
585
match_self(Tok, ThisN, AccX, Context)
603
586
end, Acc, PrecedingSiblings);
609
592
%% "The 'preceding' axis contains all nodes in the same document as the context
610
593
%% node that are before the context node in document order, exluding any
611
594
%% ancestors and excluding attribute nodes and namespace nodes."
612
%% (UW: I interpret this as "preceding siblings and their descendants".)
613
595
match_preceding(Tok, N, Acc, Context) ->
614
596
#xmlNode{parents = Ps, node = Node} = N,
616
598
[#xmlNode{type = element,
617
node = #xmlElement{} = PNode}|_] ->
599
node = #xmlElement{} = PNode} = P|_] ->
618
600
PrecedingSiblings = lists:sublist(get_content(PNode), 1,
619
Node#xmlElement.pos-1),
622
ThisN = #xmlNode{type = node_type(E),
626
case node_test(Tok, ThisN, Context) of
632
match_desc(get_content(E), Tok, Ps, Acc1, Context)
633
end, Acc, PrecedingSiblings);
601
get_position(Node) - 1),
604
ThisN = #xmlNode{type = node_type(E),
607
match_descendant_or_self(Tok, ThisN,
609
end, Acc, PrecedingSiblings),
610
match_preceding(Tok, P, Acc0, Context);
642
619
case N#xmlNode.type of
644
621
#xmlNode{parents = Ps, node = E} = N,
647
624
ThisN = #xmlNode{type = attribute,
649
626
parents = [N|Ps]},
650
case node_test(Tok, ThisN, Context) of
627
match_self(Tok, ThisN, AccX, Context)
656
628
end, Acc, E#xmlElement.attributes);
661
634
node_type(#xmlAttribute{}) -> attribute;
672
645
% erlang:fault(not_yet_implemented).
675
update_nodeset(Context = #xmlContext{axis_type = reverse}, NodeSet) ->
676
Context#xmlContext{nodeset = reverse(NodeSet)};
677
update_nodeset(Context, NodeSet) ->
678
Context#xmlContext{nodeset = forward(NodeSet)}.
681
reverse(NodeSet, 1, []).
683
reverse([H|T], Pos, Acc) ->
684
reverse(T, Pos+1, [H#xmlNode{pos = Pos}|Acc]);
685
reverse([], _Pos, Acc) ->
691
forward([H|T], Pos) ->
692
[H#xmlNode{pos = Pos}|forward(T, Pos+1)];
648
update_nodeset(Context = #xmlContext{axis_type = AxisType}, NodeSet) ->
657
lists:MapFold(fun(Node, N) ->
658
{Node#xmlNode{pos = N}, N + 1}
660
Context#xmlContext{nodeset = Result}.
736
702
case expanded_name(Prefix, Local, Context) of
738
704
?dbg("node_test(~p, ~p) -> ~p.~n",
739
[{Tag, Prefix, Local}, write_node(Name), false]),
705
[{_Tag, Prefix, Local}, write_node(Name), false]),
742
708
Res = (ExpName == {NS#xmlNamespace.default,Name}),
743
709
?dbg("node_test(~p, ~p) -> ~p.~n",
744
[{Tag, Prefix, Local}, write_node(Name), Res]),
710
[{_Tag, Prefix, Local}, write_node(Name), Res]),
747
713
node_test({name, {Tag,_Prefix,_Local}},