diff options
Diffstat (limited to 'lib/xmerl/src/xmerl_sax_old_dom.erl')
-rw-r--r-- | lib/xmerl/src/xmerl_sax_old_dom.erl | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/lib/xmerl/src/xmerl_sax_old_dom.erl b/lib/xmerl/src/xmerl_sax_old_dom.erl new file mode 100644 index 0000000000..c357816a1e --- /dev/null +++ b/lib/xmerl/src/xmerl_sax_old_dom.erl @@ -0,0 +1,293 @@ +%%-*-erlang-*- +%%-------------------------------------------------------------------- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%%---------------------------------------------------------------------- +%% File : xmerl_sax_old_dom.erl +%% Description : +%% +%% Created : 02 Oct 2008 +%%---------------------------------------------------------------------- +-module(xmerl_sax_old_dom). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include("xmerl_sax_old_dom.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([ + initial_state/0, + get_dom/1, + event/3 + ]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([ + ]). + +%%====================================================================== +%% Macros +%%====================================================================== +%%---------------------------------------------------------------------- +%% Error handling +%%---------------------------------------------------------------------- +-define(error(Reason), + throw({xmerl_sax_old_dom_error, Reason})). + +%%====================================================================== +%% Records +%%====================================================================== + +%%---------------------------------------------------------------------- +%% State record for the validator +%%---------------------------------------------------------------------- +-record(xmerl_sax_old_dom_state, { + tags=[], %% Tag stack + cno=[], %% Current node number + namespaces = [], %% NameSpace stack + dom=[] %% DOM structure + }). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function: initial_state() -> Result +%% Parameters: +%% Result: +%% Description: +%%---------------------------------------------------------------------- +initial_state() -> + #xmerl_sax_old_dom_state{}. + +%%---------------------------------------------------------------------- +%% Function: get_dom(State) -> Result +%% Parameters: +%% Result: +%% Description: +%%---------------------------------------------------------------------- +get_dom(#xmerl_sax_old_dom_state{dom=Dom}) -> + Dom. + +%%---------------------------------------------------------------------- +%% Function: event(Event, LineNo, State) -> Result +%% Parameters: +%% Result: +%% Description: +%%---------------------------------------------------------------------- +event(Event, _LineNo, State) -> + build_dom(Event, State). + + +%%====================================================================== +%% Internal functions +%%====================================================================== + +%%---------------------------------------------------------------------- +%% Function : build_dom(Event, State) -> Result +%% Parameters: Event = term() +%% State = #xmerl_sax_old_dom_state{} +%% Result : #xmerl_sax_old_dom_state{} | +%% Description: +%%---------------------------------------------------------------------- + +%% Document +%%---------------------------------------------------------------------- +build_dom(startDocument, State) -> + State#xmerl_sax_old_dom_state{dom=[startDocument]}; +build_dom(endDocument, + #xmerl_sax_old_dom_state{dom=[#xmlElement{content=C} = Current |D]} = State) -> + case D of + [startDocument] -> + State#xmerl_sax_old_dom_state{dom=[Current#xmlElement{ + content=lists:reverse(C) + }]}; + [#xmlDecl{} = Decl, startDocument] -> + State#xmerl_sax_old_dom_state{dom=[Decl, Current#xmlElement{ + content=lists:reverse(C) + }]}; + _ -> + io:format("~p\n", [D]), + ?error("we're not at end the document when endDocument event is encountered.") + end; + +%% Element +%%---------------------------------------------------------------------- +build_dom({startElement, Uri, LocalName, QName, Attributes}, + #xmerl_sax_old_dom_state{tags=T, cno=CN, namespaces=NS, dom=D} = State) -> + + A = parse_attributes(LocalName, Attributes), + {Num, NewCN} = + case CN of + [] -> + {1, [1]}; + [ N |CNs] -> + {N, [1, N+1 |CNs]} + end, + + NsInfo = + case QName of + {[], _} -> []; + QN -> QN + end, + NameAsAtom = convert_qname_to_atom(QName), + + State#xmerl_sax_old_dom_state{tags=[{NameAsAtom, Num} |T], + cno=NewCN, + dom=[#xmlElement{name=NameAsAtom, + expanded_name=NameAsAtom, + nsinfo=NsInfo, + namespace=#xmlNamespace{default=list_to_atom(Uri), + nodes=NS}, + pos=Num, + parents=T, + attributes=lists:reverse(A), + xmlbase="." + } | D]}; +build_dom({endElement, _Uri, LocalName, QName}, + #xmerl_sax_old_dom_state{tags=[_ |T], + cno=[_ |CN], + dom=[#xmlElement{name=CName, content=C} = Current, + #xmlElement{content=PC} = Parent | D]} = State) -> + case convert_qname_to_atom(QName) of + CName -> + State#xmerl_sax_old_dom_state{tags=T, + cno=CN, + dom=[Parent#xmlElement{ + content=[Current#xmlElement{ + content=lists:reverse(C) + } + |PC] + } | D]}; + _ -> + ?error("Got end of element: " ++ LocalName ++ " but expected: " ++ + Current#xmlElement.name) + end; + +%% Text +%%---------------------------------------------------------------------- +build_dom({characters, String}, + #xmerl_sax_old_dom_state{tags=T, + cno=[Num |CN], + dom=[#xmlElement{content=C} = Current| D]} = State) -> + State#xmerl_sax_old_dom_state{cno=[Num+1 |CN], + dom=[Current#xmlElement{content=[#xmlText{value=String, parents=T, pos=Num, type=text} + |C]} | D]}; +build_dom({ignorableWhitespace, String}, + #xmerl_sax_old_dom_state{tags=T, + cno=[Num |CN], + dom=[#xmlElement{content=C} = Current| D]} = State) -> + State#xmerl_sax_old_dom_state{cno=[Num+1 |CN], + dom=[Current#xmlElement{content=[#xmlText{value=String, + parents=T, pos=Num, + type=text} + |C]} | D]}; + +%% Comments +%%---------------------------------------------------------------------- +build_dom({comment, String}, + #xmerl_sax_old_dom_state{tags=T, + cno=[Num |CN], + dom=[#xmlElement{content=C} = Current| D]} = State) -> + State#xmerl_sax_old_dom_state{cno=[Num+1 |CN], + dom=[Current#xmlElement{content=[#xmlComment{parents=T, pos=Num, value=String}|C]} | D]}; + +%% NameSpaces +%%---------------------------------------------------------------------- +build_dom({startPrefixMapping, [], _Uri}, State) -> + State; +build_dom({startPrefixMapping, Prefix, Uri}, + #xmerl_sax_old_dom_state{namespaces=NS} = State) -> + State#xmerl_sax_old_dom_state{namespaces=[{Prefix, list_to_atom(Uri)} |NS]}; +build_dom({endPrefixMapping, Prefix}, + #xmerl_sax_old_dom_state{namespaces=[{Prefix, _} |NS]} = State) -> + State#xmerl_sax_old_dom_state{namespaces=NS}; + +%% Processing instructions +%%---------------------------------------------------------------------- +build_dom({processingInstruction,"xml", PiData}, + #xmerl_sax_old_dom_state{dom=D} = State) -> + {Vsn, PiData1} = find_and_remove_attribute("version", PiData, []), + {Enc, PiData2} = find_and_remove_attribute("encoding", PiData1, []), + {Standalone, PiData3} = find_and_remove_attribute("standalone", PiData2, yes), + State#xmerl_sax_old_dom_state{dom=[#xmlDecl{vsn=Vsn, encoding=Enc, standalone=Standalone, attributes=PiData3}| D]}; +build_dom({processingInstruction, PiTarget, PiData}, + #xmerl_sax_old_dom_state{cno=[Num |CN], + dom=[#xmlElement{content=C} = Current| D]} = State) -> + State#xmerl_sax_old_dom_state{cno=[Num+1 |CN], + dom=[Current#xmlElement{content=[#xmlPI{name=PiTarget,pos=Num, value=PiData} + |C]} | D]}; +%% Default +%%---------------------------------------------------------------------- +build_dom(_E, State) -> + State. + + +%%---------------------------------------------------------------------- +%% Function : parse_attributes(ElName, Attributes) -> Result +%% Parameters: +%% Result : +%% Description: +%%---------------------------------------------------------------------- +parse_attributes(ElName, Attributes) -> + parse_attributes(ElName, Attributes, 1, []). + +parse_attributes(_, [], _, Acc) -> + Acc; +parse_attributes(ElName, [{_Uri, Prefix, LocalName, AttrValue} |As], N, Acc) -> + Name = convert_qname_to_atom({Prefix,LocalName}), + NsInfo = + case Prefix of + [] -> []; + P -> {P,LocalName} + end, + parse_attributes(ElName, As, N+1, [#xmlAttribute{name=Name, + pos=N, + nsinfo=NsInfo, + value=AttrValue, + normalized=false} |Acc]). + +%%---------------------------------------------------------------------- +%% Function : convert_qname_to_atom(QName) -> Result +%% Parameters: +%% Result : +%% Description: +%%---------------------------------------------------------------------- +convert_qname_to_atom({[], N}) -> + list_to_atom(N); +convert_qname_to_atom({P,N}) -> + list_to_atom(P ++ ":" ++ N). + +%%---------------------------------------------------------------------- +%% Function : find_and_remove_attribute(Key, Data, Default) -> Result +%% Parameters: +%% Result : +%% Description: +%%---------------------------------------------------------------------- +find_and_remove_attribute(Key, Data, Default) -> + case lists:keysearch(Key, 1, Data) of + {value, {Key, Value}} -> + Data2 = lists:keydelete(Key, 1, Data), + {Value, Data2}; + false -> + {Default, Data} + end. |