Created
March 6, 2014 17:15
-
-
Save tdx/9394644 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
-mode(compile). | |
%% | |
main([]) -> parse(); | |
main(["help"]) -> usage(); | |
main(["--help"]) -> usage(); | |
main(["-h"]) -> usage(); | |
main([Profile|Rest]) -> parse(Profile, Rest); | |
main(_) -> usage(). | |
-record(tr_model, { | |
root = <<>>, | |
profiles = [], | |
cur_profile = "", | |
cur_object = "", | |
cur_parameter = "", | |
param_idx = 0 | |
}). | |
-record(syntax, { | |
type = <<>> :: binary(), | |
sub_type = <<>> :: binary(), % for list type | |
default :: term(), | |
size = 0 :: non_neg_integer(), | |
range :: term(), | |
enum = [] :: list() | |
}). | |
-record(tr_parameter, { | |
id = 0 :: non_neg_integer(), | |
ref = {<<>>,<<>>} :: {Obj::binary(),Param::binary()}, | |
profile = <<>> :: binary(), | |
access = <<>> :: binary(), | |
forcedInform = false :: boolean(), | |
activeNotify = <<>> :: binary(), | |
status = <<>> :: binary(), | |
syntax = undefined :: undefined | #syntax{} | |
}). | |
-record(stp, { | |
cur_object = <<"">> :: binary() , % object name | |
cur_param = undefined :: undefined | #tr_parameter{}, | |
cur_syntax = undefined :: undefined | #syntax{} | |
}). | |
usage() -> | |
io:format( | |
<<"~n tr_model TrWithProfile TrWithOtherVsn1 ... TrWithOtherVsnN~n~n">>, | |
[]). | |
parse() -> | |
parse( | |
"apps/cpe/xslt/tr-098-1-0-0.xml", % с профилями InternetGatewayDevice:1.1 | |
["apps/cpe/xslt/tr-069-1-0-0.xml"]). % InternetGatewayDevice:1.0 | |
parse(FileWithProfiles, AdditionalFiles) -> | |
mk_store(), | |
{ok,TrWithProfiles} = file:read_file(FileWithProfiles), | |
Opts = [ | |
{event_fun, fun event/3}, | |
{event_state, {#tr_model{},""}} | |
], | |
% 1. Ищем профили и параметры | |
{ok, {Model,_}, _} = xmerl_sax_parser:stream(TrWithProfiles, Opts), | |
#tr_model{ | |
root = Root, | |
profiles = Profiles} = Model, | |
io:format("model: ~n RootObject: ~p~n profiles: ~p~n", [Root, Profiles]), | |
% 2. По найденным параметрам профилей заполняем свойства параметров | |
Opts2 = [ | |
{event_fun, fun ev/3}, | |
{event_state, {#stp{},""}} | |
], | |
xmerl_sax_parser:stream(TrWithProfiles, Opts2), | |
% 2.2 файлы с предыдущими версиями | |
% TODO: проверять что для того же RootObject ? | |
[ | |
begin | |
{ok,TrBin} = file:read_file(TrFile), | |
xmerl_sax_parser:stream(TrBin, Opts2) | |
end || TrFile <- AdditionalFiles | |
], | |
% 3. dump tr_model ets to file | |
FSort = fun(A,B) -> A < B end, | |
L = lists:sort(FSort, ets:tab2list(tr_model)), | |
FName = "tr_model.txt", | |
file:write_file(FName, io_lib:format("~p.~n", [L])), | |
io:format(<<" Parameters: ~p~n Output: ~s~n">>, | |
[Model#tr_model.param_idx, FName]), | |
ok. | |
% Профили, объекты и параметры | |
event({startElement,_Uri,"model",_QName, Attrs}, _Location, {St,Chars}) -> | |
{get_model_name(St, Attrs),Chars}; | |
event({startElement,_Uri,"profile",_QName, Attrs}, _Location, {St,Chars}) -> | |
{get_profile_name(St, Attrs),Chars}; | |
event({startElement,_Uri,"object",_QName, Attrs}, _Location, {St,Chars}) | |
when St#tr_model.cur_profile /= "" -> | |
{get_object_name(St, Attrs),Chars}; | |
event({startElement,_Uri,"parameter",_QName, Attrs}, _Location, {St,Chars}) | |
when St#tr_model.cur_object /= "" -> | |
{get_parameter_name(St, Attrs),Chars}; | |
event({endElement,_Uri,"parameter",_QName}, _Location, {St,Chars}) | |
when St#tr_model.cur_parameter /= "" -> | |
{St#tr_model{cur_parameter=""},Chars}; | |
event({endElement,_Uri,"object",_QName}, _Location, {St,Chars}) | |
when St#tr_model.cur_object /= "" -> | |
{St#tr_model{cur_object=""},Chars}; | |
event({endElement,_Uri,"profile",_QName}, _Location, {St,Chars}) -> | |
{add_profile_to_root(St),Chars}; | |
event(_What, _Location, St) -> | |
% io:format(<<"~p~n">>, [What]), | |
St. | |
% Свойства параметров | |
ev({startElement,_Uri,"object",_QName, Attrs}, _Location, {St,Chars}) | |
when St#stp.cur_object == <<"">> -> | |
{get_object_name2(St, Attrs),Chars}; | |
ev({startElement,_Uri,"parameter",_QName, Attrs}, _Location, {St,Chars}) | |
when St#stp.cur_param == undefined -> | |
{get_parameter_name2(St, Attrs),Chars}; | |
ev({startElement,_Uri,"syntax",_QName,_Attrs}, _Location, {St,Chars}) | |
when St#stp.cur_syntax == undefined -> | |
{St#stp{cur_syntax = #syntax{}}, Chars}; | |
ev({startElement,_Uri,LName,_QName,Attrs}, _Location, {St,Chars}) | |
when St#stp.cur_param /= undefined, | |
St#stp.cur_syntax /= undefined -> | |
{handle_syntax_data(St, tb(LName), Attrs), Chars}; | |
ev({endElement,_Uri,"syntax",_QName}, _Location, {St,Chars}) | |
when St#stp.cur_param /= undefined, | |
St#stp.cur_syntax /= undefined -> | |
TrP = St#stp.cur_param, | |
NewTrP = TrP#tr_parameter{syntax = St#stp.cur_syntax}, | |
store_parameter(NewTrP), | |
NewSt = St#stp{cur_syntax = undefined, | |
cur_param = NewTrP}, | |
{NewSt,Chars}; | |
ev({endElement,_Uri,"parameter",_QName}, _Location, {St,Chars}) | |
when St#stp.cur_param /= undefined -> | |
store_parameter(St#stp.cur_param), | |
NewSt = St#stp{cur_syntax = undefined, | |
cur_param = undefined}, | |
{NewSt,Chars}; | |
ev({endElement,_Uri,"object",_QName}, _Location, {St,Chars}) | |
when St#stp.cur_object /= <<"">> -> | |
{St#stp{cur_object= <<"">>},Chars}; | |
% ev(What, _Location, {St,Chars}) when St#stp.cur_syntax /= undefined -> | |
% io:format(<<"~p~n">>, [What]), | |
% {St,Chars}; | |
ev(_What, _Location, St) -> | |
St. | |
%%% --------------------------------------------------------------------------- | |
mk_store() -> | |
Tab = tr_model, | |
case ets:info(Tab) of | |
undefined -> ets:new(Tab, [set,public,named_table,{keypos,3}]); | |
_ -> ets:delete_all_objects(Tab) | |
end. | |
store_parameter(#tr_parameter{}=P) -> | |
true = ets:insert(tr_model, P). | |
get_parameter(Key) -> | |
case ets:lookup(tr_model, Key) of | |
[Val] -> {ok,Val}; | |
[] -> false | |
end. | |
%%% --------------------------------------------------------------------------- | |
get_model_name(St, Attrs) -> | |
case attr_find("name", Attrs) of | |
{ok,Value} -> St#tr_model{root = Value}; | |
false -> St | |
end. | |
get_profile_name(#tr_model{}=St, Attrs) -> | |
case attr_find("name", Attrs) of | |
{ok,Value} -> | |
% Profile = #tr_profile{name=Value}, | |
St#tr_model{cur_profile = Value}; | |
false -> St | |
end. | |
get_object_name(St, Attrs) -> | |
case attr_find("ref", Attrs) of | |
{ok,Value} -> St#tr_model{cur_object=Value}; | |
false -> St | |
end. | |
get_parameter_name(#tr_model{cur_profile=Profile, cur_object=Obj}=St, Attrs) -> | |
case attr_find("ref", Attrs) of | |
{ok,Param} -> | |
Id = St#tr_model.param_idx, | |
add_parameter_to_profile(Profile,Obj,Param,Id), | |
St#tr_model{cur_parameter=Param,param_idx=Id+1}; | |
false -> St | |
end. | |
%%% --------------------------------------------------------------------------- | |
get_object_name2(St, Attrs) -> | |
case attr_find_name_or_base(Attrs) of | |
{ok,Value} -> St#stp{cur_object=tb(Value)}; | |
false -> St | |
end. | |
get_parameter_name2(#stp{cur_object=Obj}=St, Attrs) -> | |
case attr_find_name_or_base(Attrs) of | |
{ok,Param} -> | |
Key = {Obj,tb(Param)}, | |
TrParam = get_parameter_attributes(Key, Attrs), | |
St#stp{cur_param=TrParam}; | |
false -> St | |
end. | |
get_parameter_attributes(Key, Attrs) -> | |
case get_parameter(Key) of | |
{ok,TrP} -> | |
NewTrP = get_parameter_attributes2(TrP, Attrs), | |
store_parameter(NewTrP), | |
NewTrP; | |
false -> undefined | |
end. | |
get_parameter_attributes2(TrP, Attrs) -> | |
Access = attr_find("access" , Attrs, "readOnly"), | |
ActiveNotify = attr_find("activeNotify", Attrs, ""), | |
ForcedInform = case attr_find("forcedInform", Attrs, "0") of | |
"true" -> true; | |
_ -> false | |
end, | |
Status = attr_find("status", Attrs, ""), | |
TrP#tr_parameter{ | |
status = Status, | |
access = Access, | |
activeNotify = ActiveNotify, | |
forcedInform = ForcedInform}. | |
attr_find_name_or_base(Attrs) -> | |
case attr_find("name", Attrs) of | |
{ok,Value} -> {ok,Value}; | |
false -> | |
case attr_find("base", Attrs) of | |
{ok,Value} -> {ok,Value}; | |
false -> false | |
end | |
end. | |
%%% --------------------------------------------------------------------------- | |
%%% Syntax | |
%%% --------------------------------------------------------------------------- | |
handle_syntax_data(St, <<"boolean">>=Type, _Attrs) -> | |
set_syntax_type(Type, St); | |
handle_syntax_data(St, <<"string">>=Type, _Attrs) -> | |
set_syntax_type(Type, St); | |
handle_syntax_data(St, <<"unsignedInt">>=Type, _Attrs) -> | |
set_syntax_type(Type, St); | |
handle_syntax_data(St, <<"int">>=Type, _Attrs) -> | |
set_syntax_type(Type, St); | |
handle_syntax_data(St, <<"list">>=Type, _Attrs) -> | |
set_syntax_type(Type, St); | |
handle_syntax_data(St, <<"dateTime">>=Type, _Attrs) -> | |
set_syntax_type(Type, St); | |
handle_syntax_data(St, <<"dataType">>, Attrs) -> | |
set_syntax_datatype(Attrs, St); | |
handle_syntax_data(St, <<"size">>, Attrs) -> | |
set_syntax_size(Attrs, St); | |
handle_syntax_data(St, <<"range">>, Attrs) -> | |
set_syntax_range(Attrs, St); | |
handle_syntax_data(St, <<"enumeration">>, Attrs) -> | |
add_enumeration(Attrs, St); | |
handle_syntax_data(St, <<"pattern">>, Attrs) -> | |
add_enumeration(Attrs, St); | |
handle_syntax_data(St, <<"default">>, Attrs) -> | |
set_syntax_default(Attrs, St); | |
% unknown | |
handle_syntax_data(St, LName, _Attrs) when LName /= <<"description">>, | |
LName /= <<"syntax">> -> | |
io:format("syntax_data: ~p~n", [LName]), | |
St; | |
handle_syntax_data(St, _LName, _Attrs) -> | |
St. | |
set_syntax_type(Type, #stp{cur_syntax=#syntax{type=Old}=Syn}=St) | |
when Old /= <<>> -> | |
NewSyn = Syn#syntax{sub_type = Type}, | |
St#stp{cur_syntax = NewSyn}; | |
set_syntax_type(Type, #stp{cur_syntax=#syntax{}=Syn}=St) -> | |
NewSyn = Syn#syntax{type = Type}, | |
St#stp{cur_syntax = NewSyn}. | |
set_syntax_datatype(Attrs, #stp{cur_syntax=#syntax{}=Syn}=St) -> | |
DataType = attr_find("ref", Attrs, <<"">>), | |
NewSyn = Syn#syntax{type = DataType}, | |
St#stp{cur_syntax = NewSyn}. | |
set_syntax_range(Attrs, #stp{cur_syntax=#syntax{}=Syn}=St) -> | |
MinInclusive = attr_find("minInclusive", Attrs, 0), | |
MaxInclusive = attr_find("maxInclusive", Attrs, <<"unbounded">>), | |
NewSyn = Syn#syntax{range = {MinInclusive, MaxInclusive}}, | |
St#stp{cur_syntax = NewSyn}. | |
add_enumeration(Attrs, #stp{cur_syntax=#syntax{enum=Old}=Syn}=St) -> | |
Value = attr_find("value", Attrs, ""), | |
NewSyn = Syn#syntax{enum = Old ++ [Value]}, | |
St#stp{cur_syntax = NewSyn}. | |
set_syntax_default(Attrs, #stp{cur_syntax=#syntax{type=Type}=Syn}=St) -> | |
Default = attr_find("value", Attrs, <<"unbounded">>), | |
TypeDefault = case catch default_to_type(Type,Default) of | |
{'EXIT', _} -> | |
TrP = St#stp.cur_param, | |
io:format("error type: ~p: ~p, value: ~p~n", | |
[TrP#tr_parameter.ref,Type,Default]), | |
Default; | |
Val -> Val | |
end, | |
NewSyn = Syn#syntax{default = TypeDefault}, | |
St#stp{cur_syntax = NewSyn}. | |
set_syntax_size(Attrs, #stp{cur_syntax=#syntax{}=Syn}=St) -> | |
Size = attr_find("maxLength", Attrs, "0"), | |
NewSyn = Syn#syntax{size = list_to_integer(Size)}, | |
St#stp{cur_syntax = NewSyn}. | |
default_to_type(<<"boolean">> , "true") -> true; | |
default_to_type(<<"boolean">> , "false") -> false; | |
default_to_type(<<"unsignedInt">>, "") -> ""; % wrong file ? | |
default_to_type(<<"unsignedInt">>, V) -> list_to_integer(V); | |
default_to_type(<<"int">> , V) -> list_to_integer(V); | |
default_to_type(_, V) -> V. | |
%%% --------------------------------------------------------------------------- | |
attr_find(AttrName, Attrs) -> | |
case lists:keyfind(AttrName, 3, Attrs) of | |
{_Uri,_Prefix,AttrName,Val} -> {ok,Val}; | |
false -> false | |
end. | |
attr_find(AttrName, Attrs, Default) -> | |
case lists:keyfind(AttrName, 3, Attrs) of | |
{_Uri,_Prefix,AttrName,Val} -> Val; | |
false -> Default | |
end. | |
add_parameter_to_profile(ProfileName, Obj, ParamName, Id) -> | |
Param = #tr_parameter{ id = Id, | |
ref = {tb(Obj),tb(ParamName)}, | |
profile = tb(ProfileName)}, | |
store_parameter(Param). | |
add_profile_to_root(#tr_model{profiles=Old, cur_profile=Profile}=St) -> | |
St#tr_model{profiles=Old++[Profile], cur_profile=""}. | |
tb(L) when is_list(L) -> list_to_binary(L). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment