1%%%-------------------------------------------------------------------
2%%% File    : xpath_abbrev.erl
3%%% Author  : Bertil Karlsson <bertil@finrod>
4%%% Description :
5%%%
6%%% Created : 17 Jan 2006 by Bertil Karlsson <bertil@finrod>
7%%%-------------------------------------------------------------------
8-module(xpath_abbrev).
9
10-export([test/0, check_node_set/2, ticket_6873/0, ticket_7496/0, functions/0]).
11-export([namespaces/0]).
12
13-include_lib("common_test/include/ct.hrl").
14-include_lib("xmerl/include/xmerl.hrl").
15
16test() ->
17    {E,_} = xmerl_scan:file("xpath.xml"),
18
19    Res1 = xmerl_xpath:string("blipp",E),
20    ok = check_node_set("blipp",Res1),
21    Res2 = xmerl_xpath:string("*",E),
22    ok = check_node_set("*",Res2),
23    Res3 = xmerl_xpath:string("blipp/blupp/plopp/text()",E),
24    ok = check_node_set("blipp/blupp/plopp/text()",Res3),
25    Res4 = xmerl_xpath:string("blipp/blupp/@att2",E),
26    ok = check_node_set("blipp/blupp/@att2",Res4),
27    Res5 = xmerl_xpath:string("blipp/@*",E),
28    ok = check_node_set("blipp/@*",Res5),
29    Res6 = xmerl_xpath:string("blipp[2]",E),
30    ok = check_node_set("blipp[2]",Res6),
31    Res7 = xmerl_xpath:string("blipp[last()]",E),
32    ok = check_node_set("blipp[last()]",Res7),
33    Res8 = xmerl_xpath:string("*/blupp",E),
34    ok = check_node_set("*/blupp",Res8),
35    Res9 = xmerl_xpath:string("/myBS_model/blipp[3]/blupp[2]",E),
36    ok = check_node_set("/myBS_model/blipp[3]/blupp[2]",Res9),
37    Res10 = xmerl_xpath:string("blipp//plopp",E),
38    ok = check_node_set("blipp//plopp",Res10),
39    Res11 = xmerl_xpath:string("//plopp",E),
40    ok = check_node_set("//plopp",Res11),
41    Res12 = xmerl_xpath:string("//blupp/plopp",E),
42    ok = check_node_set("//blupp/plopp",Res12),
43    Res13 = xmerl_xpath:string(".",E),
44    ok = check_node_set(".",Res13),
45    Res14 = xmerl_xpath:string(".//blipp2",E),
46    ok = check_node_set(".//blipp2",Res14),
47    Res15 = xmerl_xpath:string(".//blipp2/blupp/plopp/..",E),
48    ok = check_node_set(".//blipp2/blupp/plopp/..",Res15),
49    Res16 = xmerl_xpath:string(".//blipp[2]/blupp/plopp/../@att2",E),
50    ok = check_node_set(".//blipp[2]/blupp/plopp/../@att2",Res16),
51    Res17 = xmerl_xpath:string(".//blipp/blupp/plopp[2]/../@att2",E),
52    ok = check_node_set(".//blipp/blupp/plopp[2]/../@att2",Res17),
53    Res18 = xmerl_xpath:string("blipp[@id='name2']",E),
54    ok = check_node_set("blipp[@id='name2']",Res18),
55    Res19 = xmerl_xpath:string("blipp[@id='name2'][3]",E),
56    ok = check_node_set("blipp[@id='name2'][3]",Res19),
57    Res20 = xmerl_xpath:string("//blupp[plopp=\"here are some more text\"]",E),
58    ok = check_node_set("//blupp[plopp=\"here are some more text\"]",Res20),
59    Res21 = xmerl_xpath:string("//blupp[plopp]",E),
60    ok = check_node_set("//blupp[plopp]",Res21),
61    Res22 = xmerl_xpath:string("blipp[@id and @test]",E),
62    ok = check_node_set("blipp[@id and @test]",Res22).
63
64check_node_set("blipp",[E1,E2,E3]) ->
65    ok = xml_element_name(E1,blipp),
66    ok = xml_element_name(E2,blipp),
67    ok = xml_element_name(E3,blipp),
68    ok;
69check_node_set("*",[E1,E2,E3,E4]) ->
70    ok = xml_element_name(E1,blipp),
71    ok = xml_element_name(E2,blipp),
72    ok = xml_element_name(E3,blipp),
73    ok = xml_element_name(E4,blipp2),
74    ok;
75check_node_set("blipp/blupp/plopp/text()",[T1,T2]) ->
76    #xmlText{value="here are some text"} = T1,
77    #xmlText{value="here are some more text"} = T2,
78    ok;
79check_node_set("blipp/blupp/@att2",[A1,A2]) ->
80    #xmlAttribute{name=att2} = A1,
81    #xmlAttribute{name=att2} = A2,
82    ok;
83check_node_set("blipp/@*",[A1,A2,A3,A4]) ->
84    #xmlAttribute{} = A1,
85    #xmlAttribute{} = A2,
86    #xmlAttribute{} = A3,
87    #xmlAttribute{} = A4,
88    ok;
89check_node_set("blipp[2]",[E]) ->
90    #xmlElement{name=blipp,
91                attributes=[#xmlAttribute{name=id,value="name2"}]} = E,
92    ok;
93check_node_set("blipp[last()]",[E]) ->
94    #xmlElement{name=blipp,
95                attributes=[#xmlAttribute{name=id,value="name3"}|_]} = E,
96    ok;
97check_node_set("*/blupp",[E1,E2,E3,E4,E5,E6]) ->
98    ok = xml_element_name(E1,blupp),
99    ok = xml_element_name(E2,blupp),
100    ok = xml_element_name(E3,blupp),
101    ok = xml_element_name(E4,blupp),
102    ok = xml_element_name(E5,blupp),
103    ok = xml_element_name(E6,blupp),
104    ok;
105check_node_set("/myBS_model/blipp[3]/blupp[2]",[E]) ->
106    #xmlElement{name=blupp,
107                attributes=[#xmlAttribute{name=att,value="bluppc2"}]}=E,
108    ok;
109check_node_set("blipp//plopp",[#xmlElement{name=plopp},#xmlElement{name=plopp}]) ->
110    ok;
111check_node_set("//plopp",[E1,E2,E3]) ->
112    ok = xml_element_name(E1,plopp),
113    ok = xml_element_name(E2,plopp),
114    ok = xml_element_name(E3,plopp),
115    ok;
116check_node_set("//blupp/plopp",[E1,E2,E3]) ->
117    ok = xml_element_name(E1,plopp),
118    ok = xml_element_name(E2,plopp),
119    ok = xml_element_name(E3,plopp),
120    ok;
121check_node_set(".",[#xmlElement{name=myBS_model}]) ->
122    ok;
123check_node_set(".//blipp2",[#xmlElement{name=blipp2}]) ->
124    ok;
125check_node_set(".//blipp2/blupp/plopp/..",[#xmlElement{name=blupp}]) ->
126    ok;
127check_node_set(".//blipp[2]/blupp/plopp/../@att2",[#xmlAttribute{name=att2,value="bluppb"}]) ->
128    ok;
129check_node_set(".//blipp/blupp/plopp[2]/../@att2",[#xmlAttribute{name=att2,value="bluppc"}]) ->
130    ok;
131check_node_set("blipp[@id='name2']",[E]) ->
132    #xmlElement{name=blipp,
133                attributes=[#xmlAttribute{name=id,value="name2"}]}=E,
134    ok;
135check_node_set("blipp[@id='name2'][3]",[]) ->
136    ok;
137check_node_set("//blupp[plopp=\"here are some more text\"]",[E]) ->
138    #xmlElement{name=blupp,
139                content=[_T,#xmlElement{name=plopp,content=C}|_]} = E,
140    true = lists:keymember("here are some more text",#xmlText.value,C),
141    ok;
142check_node_set("//blupp[plopp]",[E1,E2,E3]) ->
143    #xmlElement{name=blupp,
144                content=C1} = E1,
145    true = lists:keymember(plopp,#xmlElement.name,C1),
146    #xmlElement{name=blupp,
147                content=C2} = E2,
148    true = lists:keymember(plopp,#xmlElement.name,C2),
149    #xmlElement{name=blupp,
150                content=C3} = E3,
151    true = lists:keymember(plopp,#xmlElement.name,C3),
152    ok;
153check_node_set("blipp[@id and @test]",[E]) ->
154    #xmlElement{name=blipp,
155                attributes=Atts} = E,
156    true = lists:keymember(id,#xmlAttribute.name,Atts),
157    true = lists:keymember(test,#xmlAttribute.name,Atts),
158    ok;
159check_node_set(Pattern,NodeSet) ->
160    io:format("Pattern: ~p~nNodeSet: ~p~n",[Pattern,NodeSet]),
161    error.
162
163xml_element_name(E,N) ->
164    #xmlElement{name=N} = E,
165    ok.
166
167ticket_6873() ->
168    [#xmlElement{}] = xmerl_xpath:string("//foo[contains(@bar, 'oe')]",element(1,xmerl_scan:string("<foo bar=\"Joe\" />"))),
169    ok.
170
171ticket_7496() ->
172    Test = fun(Doc, XPath, Exp) ->
173                   Result = xmerl_xpath:string(XPath, Doc),
174                   Exp = [Name || #xmlElement{name = Name} <- Result],
175                   ok
176           end,
177    {Doc1,_} = xmerl_scan:string("<a><b/> <c/> <d/> <e/></a>"),
178    ok = Test(Doc1, "//b/following::*", [c, d, e]),
179    ok = Test(Doc1,"//b/following::*[1]", [c]),
180    ok = Test(Doc1,"//b/following::*[position()=1]", [c]),
181    ok = Test(Doc1,"//b/following::*[3]", [e]),
182    ok = Test(Doc1,"//b/following::*[position()=3]", [e]),
183    ok = Test(Doc1,"//e/preceding::*", [b, c, d]),
184    ok = Test(Doc1,"//e/preceding::*[1]", [d]),
185    ok = Test(Doc1,"//e/preceding::*[position()=1]", [d]),
186    ok = Test(Doc1,"//e/preceding::*[3]", [b]),
187    ok = Test(Doc1,"//e/preceding::*[position()=3]", [b]),
188    ok = Test(Doc1,"//b/following::*[position() mod 2=0]", [d]),
189    ok = Test(Doc1,"//b/self::*", [b]),
190
191    {Doc2,_} = xmerl_scan:string("<a><b/> <c><d/></c> <e/> <f><g/></f> <h/> <i><j/></i> <k/></a>"),
192    ok = Test(Doc2,"//g/preceding::*", [b, c, d, e]),
193    ok = Test(Doc2, "//g/following::*", [h, i, j, k]),
194    ok = Test(Doc2,"//g/ancestor::*", [a, f]),
195    ok = Test(Doc2,"//g/ancestor::*[1]", [f]),
196    ok = Test(Doc2,"//g/ancestor::*[2]", [a]),
197    ok = Test(Doc2,"//g/ancestor-or-self::*", [a, f, g]),
198    ok = Test(Doc2,"//g/ancestor-or-self::*[1]", [g]),
199    ok = Test(Doc2,"//g/ancestor-or-self::*[2]", [f]),
200    ok = Test(Doc2,"//g/ancestor-or-self::*[3]", [a]),
201    ok = Test(Doc2,"/descendant::*", [a, b, c, d, e, f, g, h, i, j, k]),
202    ok = Test(Doc2,"//f/preceding-sibling::*", [b, c, e]),
203    ok = Test(Doc2,"//f/following-sibling::*", [h, i, k]),
204    ok = Test(Doc2,"//f/self::*", [f]),
205    ok = Test(Doc2,"//f/ancestor::*", [a]),
206    ok = Test(Doc2,"//f/descendant::*", [g]),
207    ok = Test(Doc2,"//f/preceding::*", [b, c, d, e]),
208    ok = Test(Doc2,"//f/following::*", [h, i, j, k]),
209    ok = Test(Doc2,"//text()[1]/following-sibling::*", [c, e, f, h, i, k]),
210
211    {Doc3,_} = xmerl_scan:file("documentRoot.xml"),
212    ok = Test(Doc3,"//child",[child,child,child]),
213    ok = Test(Doc3,"//child[@name='beta']",[child]),
214    [{xmlAttribute,id,[],[],[],_,1,[],"2",false}] =
215    xmerl_xpath:string("/documentRoot/parent/child[@name='beta']/@id",Doc3),
216    ok = Test(Doc3,"/documentRoot/parent/child|/documentRoot/parent/pet",
217              [child,child,child,pet,pet]),
218    ok = Test(Doc3,"//*[starts-with(local-name(),'p')]",
219              [parent,pet,pet]).
220
221
222functions() ->
223    Test = fun(Doc, XPath, Exp) ->
224                   Result = xmerl_xpath:string(XPath, Doc),
225                   Exp = [begin
226                              case Obj of
227                                  #xmlElement{name = EName} ->
228                                      EName;
229                                  #xmlAttribute{name = AName} ->
230                                      AName;
231                                  #xmlText{value=Text} ->
232                                      Text
233                              end
234                          end|| Obj <- Result],
235                   ok
236           end,
237    Foo =
238    "<foo>"
239    "  <bar>"
240    "    <name>Xml</name>"
241    "    <value>1</value>"
242    "  </bar>"
243    "  <bar>"
244    "    <name>Xpath</name>"
245    "    <value>2</value>"
246    "  </bar>"
247    "  <bar>"
248    "    <name>Erlang</name>"
249    "    <value>3</value>"
250    "  </bar>"
251    "</foo>",
252    {Doc,_} = xmerl_scan:string(Foo),
253    ok = Test(Doc,"/foo/bar[name = 'Xml']/value/text()",["1"]),
254    ok = Test(Doc,"/foo/bar/node()/text()",
255              ["Xml","1","Xpath","2","Erlang","3"]),
256    ok = Test(Doc,"/foo/bar[contains(name, 'path')]",[bar]),
257    ok = Test(Doc,"/foo/bar[starts-with(name, 'X')]",[bar,bar]),
258    ok = Test(Doc,"/foo/bar[value = string(1)]/value/text()",["1"]),
259
260
261    {Doc2,_}= xmerl_scan:file("purchaseOrder.xml"),
262    ok = Test(Doc2,"//*[starts-with(local-name(),'c')]",
263              ['apo:comment',city,city,comment]),
264    ok = Test(Doc2,"//*[starts-with(name(),'c')]",
265              [city,city,comment]),
266    ok = Test(Doc2,"//*[starts-with(name(),'{http://www.example.com/PO1')]",
267              ['apo:purchaseOrder','apo:comment']).
268
269
270namespaces() ->
271    {Doc,_} = xmerl_scan:file("purchaseOrder.xml", [{namespace_conformant, true}]),
272
273    %% Element name using regular namespace and context namespace declaration.
274    [#xmlElement{nsinfo = {_, "purchaseOrder"}}] =
275    xmerl_xpath:string("/apo:purchaseOrder", Doc),
276    [#xmlElement{nsinfo = {_, "purchaseOrder"}}] =
277    xmerl_xpath:string("/t:purchaseOrder", Doc, [{namespace, [{"t", "http://www.example.com/PO1"}]}]),
278
279    %% Wildcard element name using regular namespace and context namespace declaration.
280    [#xmlElement{nsinfo = {_, "comment"}}] =
281    xmerl_xpath:string("./apo:*", Doc),
282    [#xmlElement{nsinfo = {_, "comment"}}] =
283    xmerl_xpath:string("./t:*", Doc, [{namespace, [{"t", "http://www.example.com/PO1"}]}]),
284
285    %% Attribute name using regular namespace and context namespace declaration.
286    [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
287    xmerl_xpath:string("//@xsi:type", Doc),
288    [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
289    xmerl_xpath:string("//@t:type", Doc, [{namespace, [{"t", "http://www.w3.org/2001/XMLSchema-instance"}]}]),
290
291    %% Wildcard attribute name using regular namespace and context namespace declaration.
292    [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
293    xmerl_xpath:string("//@xsi:*", Doc),
294    [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
295    xmerl_xpath:string("//@t:*", Doc, [{namespace, [{"t", "http://www.w3.org/2001/XMLSchema-instance"}]}]),
296    ok.
297