%%%------------------------------------------------------------------- %%% File : xpath_lib.erl %%% Author : Bertil Karlsson %%% Description : %%% %%% Created : 13 Jan 2006 by Bertil Karlsson %%%------------------------------------------------------------------- -module(xpath_lib). -export([test/0,check_node_set/2,ticket_6873/0]). -include_lib("common_test/include/ct.hrl"). -include_lib("xmerl/include/xmerl.hrl"). test() -> {E,_} = xmerl_scan:file("myBS_model.xml"), Res1 = xmerl_xpath:string("blipp",E), ok = check_node_set("blipp",Res1), Res2 = xmerl_xpath:string("//blipp",E), ok = check_node_set("//blipp",Res2), Res3 = xmerl_xpath:string("/myBS_model/blipp",E), ok = check_node_set("/myBS_model/blipp",Res3), Res4 = xmerl_xpath:string("blipp[@id=\"name1\"]",E), ok = check_node_set("blipp[@id=\"name1\"]",Res4), Res5 = xmerl_xpath:string("//blipp[@id=\"name1\"]",E), ok = check_node_set("//blipp[@id=\"name1\"]",Res5), Res6 = xmerl_xpath:string("/myBS_model/blipp[@id=\"name1\"]",E), ok = check_node_set("/myBS_model/blipp[@id=\"name1\"]",Res6). check_node_set("blipp",[H1,H2]) -> #xmlElement{name = blipp} = H1, #xmlElement{name = blipp} = H2, ok; check_node_set("//blipp",[H1,H2]) -> #xmlElement{name = blipp} = H1, #xmlElement{name = blipp} = H2, ok; check_node_set("/myBS_model/blipp",[H1,H2]) -> #xmlElement{name = blipp} = H1, #xmlElement{name = blipp} = H2, ok; check_node_set("blipp[@id=\"name1\"]",[H]) -> H#xmlElement{attributes=#xmlAttribute{name=id,value="name1"}}, ok; check_node_set("//blipp[@id=\"name1\"]",[H]) -> H#xmlElement{attributes=#xmlAttribute{name=id,value="name1"}}, ok; check_node_set("/myBS_model/blipp[@id=\"name1\"]",[H]) -> H#xmlElement{attributes=#xmlAttribute{name=id,value="name1"}}, ok. ticket_6873() -> GetId = fun(Atts) -> case lists:keysearch(id,#xmlAttribute.name,Atts) of {value,#xmlAttribute{value=AttV}} -> AttV; _ -> novalue end end, Test = fun(Doc, XPath, Exp) -> Result = xmerl_xpath:string(XPath, Doc), Exp = [begin case Obj of #xmlElement{name = EName,attributes=Atts} -> {EName,GetId(Atts)}; #xmlAttribute{name = AName} -> AName; #xmlText{value=Text} -> Text end end|| Obj <- Result], ok end, Doc1 = get_doc("e1074"), ok = Test(Doc1,"/*",[{root,"1"}]), ok = Test(Doc1,"/root",[{root,"1"}]), ok = Test(Doc1,"/root/*",[{elem1,"2"},{elem1,"8"},{e,"12"}]), ok = Test(Doc1,"/root/e",[{e,"12"}]), ok = Test(Doc1,"//e",[{e,"12"},{e,"4"},{e,"6"},{e,"10"},{e,"11"}]), ok = Test(Doc1,"//*[name() != 'e']", [{root,"1"},{elem1,"2"},{elem1,"8"},{elem2,"3"}, {elem3,"5"},{elem3,"7"},{elem2,"9"}]), ok = Test(Doc1,"//elem1/e",[{e,"10"},{e,"11"}]), ok = Test(Doc1,"//elem1//e",[{e,"4"},{e,"6"},{e,"10"},{e,"11"}]), ok = Test(Doc1,"//*[*]", [{root,"1"},{elem1,"2"},{elem1,"8"}, {elem2,"3"},{elem3,"5"}]), ok = Test(Doc1,"//*[not(*)]", [{e,"12"},{e,"4"},{elem3,"7"},{e,"6"}, {elem2,"9"},{e,"10"},{e,"11"}]), %% contents would be empty in the above expression [#xmlElement{content=[]}|_] = xmerl_xpath:string("//*[not(*)]",Doc1), ok = Test(Doc1,"//*[e]",[{root,"1"},{elem1,"8"},{elem2,"3"},{elem3,"5"}]), ok = Test(Doc1,"//*[count(e)>1]",[{elem1,"8"}]), ok = Test(Doc1,"//*[not(e) and name() != 'e']", [{elem1,"2"},{elem3,"7"},{elem2,"9"}]), ok = Test(Doc1,"/*/*/*/e",[{e,"4"}]), ok = Test(Doc1,"//*[starts-with(name(), 'el')]", [{elem1,"2"},{elem1,"8"},{elem2,"3"}, {elem3,"5"},{elem3,"7"},{elem2,"9"}]), ok = Test(Doc1,"//*[contains(name(), 'lem1')]", [{elem1,"2"},{elem1,"8"}]), ok = Test(Doc1,"/*/e | //elem2/e",[{e,"4"},{e,"12"}]), io:format("Tested ~p~n",[e1074]), Doc2 = get_doc("e1075"), ok = Test(Doc2,"/*/*[1]",[{elem1,"2"}]), ok = Test(Doc2,"/root/elem1[2]",[{elem1,"8"}]), %% Get all first-born e elements in the document; that is, for all %% e elements with e element siblings, include only the first %% sibling.Note that //e[1] does not return the first e element in %% the document because the [1] predicate applies to e, which %% represents the set of e elements under one element and not to %% //e, which represents the set of e elements in the document. %% ok = Test(Doc2,"//e[1]",[{e,"4"},{e,"6"},{e,"10"},{e,"12"}]), %% The following expression retrieves the first e element in the %% document: %% ok = Test(Doc2,"(//e)[1]",[{e,4}]), %% For all e elements with e element siblings, include only the %% first 3 siblings %% ok = Test(Doc2,"//e[position() <= 3]",[{e,"4"},{e,"6"},{e,"10"},{e,"11"},{e,"12"}]), %% Get all last-born e elements in the document; that is, for all %% e elements with e element siblings, include only the last %% sibling %% ok = Test(Doc2,"//e[last()]",[{e,"4"},{e,"6"},{e,"11"},{e,"12"}]), %% Get the last e element in the document %% ok = Test(Doc2,"(//e)[last()]", [{e,"12"}]), io:format("Tested ~p~n",[e1075]), Doc3 = get_doc("e1076"), ok = Test(Doc3,"//*[.='cat']",[{elem1,"2"},{elem3,"6"}]), ok = Test(Doc3,"//*[.='dog']",[]), ok = Test(Doc3,"//*[contains(.,'cat')]", [{elem1,"2"},{elem1,"4"},{elem3,"6"}]), ok = Test(Doc3,"//elem3[contains(.,'cat')]",[{elem3,"6"}]), ok = Test(Doc3,"//*[contains(child::text(),'cat')]",[{elem1,"2"},{elem1,"4"},{elem3,"6"}]), ok = Test(Doc3,"//*[count(*)=0 and contains(.,'cat')]",[{elem1,"2"},{elem3,"6"}]), ok = Test(Doc3,"//*[contains(translate(.,'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),'CAT')]",[{elem1,"2"},{elem1,"4"},{elem1,"7"},{elem3,"6"}]), io:format("Tested ~p~n",[e1076]), Doc4 = get_doc("e1078"), ok = Test(Doc4,"//*[@pet='cat']",[{elem1,"2"}]), ok = Test(Doc4,"//*[@pet='dog']",[{elem1,"7"}]), ok = Test(Doc4,"//*[contains(@pet,'dog')]", [{elem1,"3"},{elem1,"7"}]), ok = Test(Doc4,"//*[@age]",[{elem1,"3"},{elem3,"6"}]), ok = Test(Doc4,"//elem1[@age]",[{elem1,"3"}]), ok = Test(Doc4,"//*[@pet and @age]",[{elem1,"3"}]), ok = Test(Doc4,"//*[contains(translate(@pet,'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),'CAT')]",[{elem1,"2"},{elem1,"4"}]), io:format("Tested ~p~n",[e1078]), Doc5 = get_doc("e1077"), ok = Test(Doc5,"id('3')",[{e,"3"}]), %% Get all e elements directly under element id 3 %% ok = Test(Doc5,"id('two')/e",[{e,"3"},{e,"4"},{e,"6"}]), ok = Test(Doc5,"id('two 3 seven the fifth')",[{e,"seven"},{e,"3"},{e,"two"}]), ok = Test(Doc5,"id('100')",[]), io:format("Tested ~p~n",[e1077]), ok. get_doc(Name) -> {Doc,_} = xmerl_scan:file(Name++".xml"), Doc.