📄 xmerl_eventp.erl
字号:
%%% The contents of this file are subject to the Erlang Public License,%%% Version 1.0, (the "License"); you may not use this file except in%%% compliance with the License. You may obtain a copy of the License at%%% http://www.erlang.org/license/EPL1_0.txt%%%%%% 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.%%%%%% The Original Code is xmerl-0.19%%%%%% The Initial Developer of the Original Code is Ericsson Telecom%%% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson%%% Telecom AB. All Rights Reserved.%%%%%% Contributor(s): ______________________________________.%%%%%%----------------------------------------------------------------------%%% #0. BASIC INFORMATION%%%----------------------------------------------------------------------%%% File: xmerl_eventp.erl%%% Author : Ulf Wiger <ulf.wiger@ericsson.com>%%% Johan Blom <Johan.Blom@mobilearts.se>%%% Description : Simple event-based processor (front-end to xmerl_scan)%%% %%% Modules used : %%% %%%----------------------------------------------------------------------%% @doc Simple event-based front-ends to xmerl_scan for processing%% of XML documents in streams and for parsing in SAX style.%% Each contain more elaborate settings of xmerl_scan that makes usage of%% the customization functions.%% -module(xmerl_eventp).-vsn('0.19').-date('03-09-17').-export([stream/2,stream_sax/4, file_sax/4, string_sax/4]).% -export([cont/3, rules_read/3,rules_write/4,fetch/2,close/1]).-include("xmerl.hrl").-include_lib("kernel/include/file.hrl").%% @spec stream(Fname::string(), Options::option_list()) -> xmlElement()%%%% @doc Parse file containing an XML document as a stream, DOM style.%% Wrapper for a call to the XML parser <code>xmerl_scan</code> with a%% <code>continuation_fun</code> for handling streams of XML data.%% Note that the <code>continuation_fun</code>, <code>acc_fun</code>,%% <code>fetch_fun</code>, <code>rules</code> and <code>close_fun</code>%% options cannot be user defined using this parser.stream(Fname, Options) -> AccF = fun(X, Acc, S) -> acc(X,Acc,S) end, case file:open(Fname, [read, raw, binary]) of {ok, Fd} -> B0 = list_to_binary([]), ContS = [{B0, Fname, Fd}], Opts=scanner_options(Options, [{continuation_fun, fun cont/3, ContS}, {acc_fun, AccF}, {fetch_fun, fun fetch/2}, {rules,fun rules_read/3,fun rules_write/4,""}, {close_fun, fun close/1}]), xmerl_scan:string([], Opts); Error -> Error end.%% @spec stream_sax(Fname,CallBackModule,UserState,Options) -> xmlElement()%% Fname = string()%% CallBackModule = atom()%% Options = option_list()%%%% @doc Parse file containing an XML document as a stream, SAX style.%% Wrapper for a call to the XML parser <code>xmerl_scan</code> with a%% <code>continuation_fun</code> for handling streams of XML data.%% Note that the <code>continuation_fun</code>, <code>acc_fun</code>,%% <code>fetch_fun</code>, <code>rules</code>, <code>hook_fun</code>,%% <code>close_fun</code> and <code>user_state</code> options cannot be user%% defined using this parser.stream_sax(Fname, CallBack, UserState,Options) -> US={xmerl:callbacks(CallBack), UserState}, AccF = fun(X, Acc, S) -> acc(X,Acc,S) end, HookF= fun(ParsedEntity, S) -> {CBs,Arg}=xmerl_scan:user_state(S),% io:format("stream_sax Arg=~p~n",[Arg]), case ParsedEntity of #xmlComment{} -> % Toss away comments... {[],S}; _ -> % Use callback module for the rest% io:format("stream_sax ParsedEntity=~p~n",[ParsedEntity]), case xmerl:export_element(ParsedEntity,CBs,Arg) of {error,Reason} -> throw({error,Reason}); Resp ->% io:format("stream_sax Resp=~p~n",[Resp]), {Resp,xmerl_scan:user_state({CBs,Resp},S)} end end end, case file:open(Fname, [read, raw, binary]) of {ok, Fd} -> B0 = list_to_binary([]), ContS = [{B0, Fname, Fd}], Opts=scanner_options(Options, [{acc_fun, AccF}, {close_fun, fun close/1}, {continuation_fun, fun cont/3, ContS}, {fetch_fun, fun fetch/2}, {hook_fun,HookF}, {rules,fun rules_read/3,fun rules_write/4,""}, {user_state,US}]), xmerl_scan:string([], Opts); Error -> Error end.%% @spec file_sax(Fname::string(), CallBackModule::atom(), UserState,%% Options::option_list()) -> NewUserState%%%% @doc Parse file containing an XML document, SAX style.%% Wrapper for a call to the XML parser <code>xmerl_scan</code> with a%% <code>hook_fun</code> for using xmerl export functionality directly after%% an entity is parsed.file_sax(Fname,CallBack, UserState, Options) -> US={xmerl:callbacks(CallBack), UserState}, AccF=fun(X,Acc,S) -> {[X|Acc], S} end, HookF= fun(ParsedEntity, S) -> {CBs,Arg}=xmerl_scan:user_state(S), case ParsedEntity of #xmlComment{} -> % Toss away comments... {[],S}; _ -> % Use callback module for the rest case xmerl:export_element(ParsedEntity,CBs,Arg) of {error,Reason} -> throw({error,Reason}); Resp -> {Resp,xmerl_scan:user_state({CBs,Resp},S)} end end end, Opts=scanner_options(Options,[{acc_fun, AccF}, {hook_fun,HookF}, {user_state,US}]), xmerl_scan:file(Fname,Opts).%% @spec string_sax(String::list(), CallBackModule::atom(), UserState,%% Options::option_list()) ->%% xmlElement()%%%% @doc Parse file containing an XML document, SAX style.%% Wrapper for a call to the XML parser <code>xmerl_scan</code> with a%% <code>hook_fun</code> for using xmerl export functionality directly after%% an entity is parsed.string_sax(String,CallBack, UserState, Options) -> US={xmerl:callbacks(CallBack), UserState}, AccF=fun(X,Acc,S) -> {[X|Acc], S} end, HookF= fun(ParsedEntity, S) -> {CBs,Arg}=xmerl_scan:user_state(S), case ParsedEntity of #xmlComment{} -> % Toss away comments... {[],S}; _ -> % Use callback module for the rest case xmerl:export_element(ParsedEntity,CBs,Arg) of {error,Reason} -> throw({error,Reason}); Resp -> {Resp,xmerl_scan:user_state({CBs,Resp},S)} end end end, Opts=scanner_options(Options,[{acc_fun, AccF}, {hook_fun,HookF}, {user_state,US}]), xmerl_scan:string(String,Opts).%%% ----------------------------------------------------------------------------%%% Streaming support functions%%% Continuation callback function for xmerl_scancont(F, Exception, S) -> case xmerl_scan:cont_state(S) of [{_Fname, eof}|_] -> Exception(S); [{Sofar, Fname, Fd}|T] -> cont2(F, Exception, Sofar, Fd, Fname, T, S) end.cont2(F, Exception, Sofar, Fd, Fname, T, S) -> case catch read_chunk(Fd, Fname, Sofar) of {ok, Bin} -> find_good_split(list_to_binary([Sofar,Bin]), F,Exception,Fd,Fname,T,S); eof -> file:close(Fd), NewS = xmerl_scan:cont_state([{Fname, eof}|T], S), F(binary_to_list(Sofar), NewS); Error -> exit(Error) end. read_chunk(Fd, _Fname, _Sofar) -> file:read(Fd, 8192).-ifndef(no_bitsyntax).find_good_split(Bin, F, Exception, Fd, Fname, T, S) -> find_good_split(size(Bin)-1, Bin, F, Exception, Fd, Fname, T, S).find_good_split(0, B, F, Exception, Fd, Fname, T, S) -> cont2(F, Exception, B, Fd, Fname, T, S);find_good_split(Size, B, F, Exception, Fd, Fname, T, S) -> case B of <<_Bytes:Size/binary, H/integer, Tail/binary>> when ?whitespace(H) -> {SubB,_} = split_binary(B, Size+1), NewS = xmerl_scan:cont_state([{Tail, Fname, Fd}|T], S), F(binary_to_list(SubB), NewS); _ -> find_good_split(Size-1, B, F, Exception, Fd, Fname, T, S) end.-else.find_good_split(Bin, F, Exception, Fd, Fname, T, S) -> find_good_split(size(Bin), Bin, F, Exception, Fd, Fname, T, S).find_good_split(0, B, F, Exception, Fd, Fname, T, S) -> cont2(F, Exception, B, Fd, Fname, T, S);find_good_split(Size, B, F, Exception, Fd, Fname, T, S) -> case binary_to_list(B, Size, Size) of [H] when ?whitespace(H) -> {SubB,Tail} = split_binary(B, Size), NewS = xmerl_scan:cont_state([{Tail, Fname, Fd}|T], S), F(binary_to_list(SubB), NewS); _ -> find_good_split(Size-1, B, F, Exception, Fd, Fname, T, S) end.-endif.%%% Accumulator callback function for xmerl_scanacc(X = #xmlText{value = Text}, Acc, S) -> case detect_nul_text(Text) of ok-> {[X#xmlText{value = lists:flatten(Text)}|Acc], S}; nok-> {Acc,S} end;acc(X, Acc, S) -> {[X|Acc], S}.%%% don't acc xmlText when text contains only " " , "\n" and "\t".detect_nul_text([H|T]) when H==10; H==32; H==9-> detect_nul_text(T);detect_nul_text([]) -> nok;detect_nul_text(_)-> ok.%%% Fetch callback function for xmerl_scanfetch({system, URI}, S) -> fetch_URI(URI, S);fetch({public, _PublicID, URI}, S) -> fetch_URI(URI, S).fetch_URI(URI, S) -> %% assume URI is a filename Split = filename:split(URI), Filename = lists:last(Split), Fullname = case Split of ["/", _|_] -> %% absolute path name URI; ["file:",Name]-> %% file:/dtd_name filename:join(S#xmerl_scanner.xmlbase, Name); _ -> filename:join(S#xmerl_scanner.xmlbase, URI) end, File = path_locate(S#xmerl_scanner.fetch_path, Filename, Fullname), ?dbg("fetch(~p) -> {file, ~p}.~n", [URI, File]), case file:open(File, [read, raw, binary]) of {ok, Fd} -> ContS=xmerl_scan:cont_state(S), NewS=xmerl_scan:cont_state([{list_to_binary([]),File,Fd}|ContS],S), {ok, {string, []}, NewS}; _Error -> ?dbg("ERROR fetch(~p) -> ~p~n", [URI, _Error]), {ok, not_fetched, S} end.path_locate([Dir|Dirs], FN, FullName) -> F = filename:join(Dir, FN), case file:read_file_info(F) of {ok, #file_info{type = regular}} -> F; _ -> path_locate(Dirs, FN, FullName) end;path_locate([], _FN, FullName) -> FullName.%%% Close callback function for xmerl_scanclose(S) -> ContS = xmerl_scan:cont_state(S), case ContS of [{_Fname, eof}|T] -> xmerl_scan:cont_state(T, S); [{_Sofar, _Fname, Fd}|T] -> file:close(Fd), xmerl_scan:cont_state(T, S) end.%%% Rules callback functions for xmerl_scanrules_write(Context, Name, Value, #xmerl_scanner{rules = undefined}=S) -> Tab = ets:new(rules, [set, public]), rules_write(Context, Name, Value, S#xmerl_scanner{rules = Tab});rules_write(Context, Name, Value, #xmerl_scanner{rules = T} = S) -> ets:insert(T, {{Context, Name}, Value}), S.rules_read(_Context, _Name, #xmerl_scanner{rules = undefined}) -> undefined;rules_read(Context, Name, #xmerl_scanner{rules = T}) -> case ets:lookup(T, {Context, Name}) of [] -> undefined; [{_K, V}] -> V end.%%% ----------------------------------------------------------------------------%%% Generic helper functionsscanner_options([H|T], Opts) -> case catch keyreplace(H, 1, Opts) of false -> scanner_options(T, [H|Opts]); NewOpts -> scanner_options(T, NewOpts) end;scanner_options([], Opts) -> Opts.keyreplace(X, Pos, [H|T]) when element(Pos, X) == element(Pos, H) -> [X|T];keyreplace(X, Pos, [H|T]) -> [H|keyreplace(X, Pos, T)];keyreplace(_, _Pos, []) -> throw(false).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -