⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmerl_xsd.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 5 页
字号:
%%% 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 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): ______________________________________.%%%%%%-------------------------------------------------------------------%%% File    : xmerl_xsd.erl%%% Author  : Bertil Karlsson <bertil.karlsson@ericsson.com>%%% Description : %%%%%%%%%-------------------------------------------------------------------%% @author Bertil Karlsson%% @doc Interface module for XML Schema vlidation. %% It handles the W3.org %% <a href="http://www.w3.org/XML/Schema#dev">specifications</a>%% of XML Schema second edition 28 october 2004. For an introduction to%% XML Schema study <a href="http://www.w3.org/TR/xmlschema-0/">part 0.</a>%% An XML structure is validated by xmerl_xsd:validate/[2,3].%% @type global_state(). <p>The global state of the validator. It is %% representated by the <code>#xmerl_xsd{}</code> record.%% </p>%% @type option_list(). <p>Options allow to customize the behaviour of the %% validation.%% </p>%% Possible options are :%% <dl>%%   <dt><code>{tab2file,boolean()}</code></dt>%%      <dd>Enables saving of abstract structure on file for debugging%%         purpose.</dd>%%   <dt><code>{xsdbase,filename()}</code></dt>%%      <dd>XSD Base directory.</dd>%%   <dt><code>{fetch_fun,FetchFun}</code></dt>%%      <dd>Call back function to fetch an external resource.</dd>%%   <dt><code>{fetch_path,PathList}</code></dt>%%      <dd>PathList is a list of directories to search when fetching files.%%          If the file in question is not in the fetch_path, the URI will%%          be used as a file name.</dd>%%   <dt><code>{state,State}</code></dt>%%      <dd>It is possible by this option to provide a state with process%%          information from an earlier validation.</dd> %% </dl>-module(xmerl_xsd).-export([validate/2,validate/3,process_validate/2,process_validate/3,	 process_schema/1,process_schema/2,	 process_schemas/1,process_schemas/2,	 state2file/1,state2file/2,file2state/1,format_error/1]).-export([print_table/1]).%%-export([whitespace/1]).-include("xmerl.hrl").-include("xmerl_xsd.hrl").-include_lib("kernel/include/file.hrl").-import(xmerl_lib,[is_facet/1, is_builtin_simple_type/1]).-import(xmerl_xsd_type,[facet_fun/2]).-import(lists,[reverse/1,reverse/2,foldl/3,member/2,filter/2,flatten/1,map/2,	       splitwith/2,mapfoldl/3,keysearch/3,keymember/3,	       keyreplace/4,keydelete/3]).%% @spec validate(Element,State) -> Result%% @equiv validate(Element,State,[])validate(Xml,State) ->    validate(Xml,State,[]).%% @spec validate(Element,State,Options) -> Result%%       Element      = XmlElement%%       Options      = option_list() %%       Result       = {ValidElement,global_state()} | {error,Reasons}%%       ValidElement = XmlElement%%       State        = global_state()%%       Reasons      = [ErrorReason] | ErrorReason%% @doc Validates a parsed well-formed XML element (Element).%% <p>A call to validate/2 or validate/3 must provide a well formed %% parsed XML element <code>#xmlElement{}</code> and a State,%% <code>global_state()</code>, which holds necessary information from%% an already processed schema.%% Thus validate enables reuse of the schema information and%% therefore if one shall validate several times towards the same%% schema it reduces time consumption.</p>%% <p>The result, ValidElement, is the valid element that conforms to the %% post-schema-validation infoset. When the validator finds an error it%% tries to continue and reports a list of all errors found. In those cases%% an unexpected error is found it may cause a single error reason.%% </p>%% <p> Usage example:</p>%% <p>%% <code>1>{E,_} = xmerl_scan:file("my_XML_document.xml").</code><br/>%% <code>2>{ok,S} = xmerl_xsd:process_schema("my_XML_Schema.xsd").</code><br/>%% <code>3>{E2,_} = xmerl_xsd:validate(E,S).</code>%% </p>%% <p> Observe that E2 may differ from E if for instance there are default%% values defined in <code>my_XML_Schema.xsd</code>.</p>validate(Xml,State,Opts) when is_record(State,xsd_state) ->    S2 = initiate_state2(State,Opts),    S3 = validation_options(S2,Opts),    validate3(S3#xsd_state.schema_name,Xml,S3).%% @spec state2file(State) -> ok | {error,Reason}%% @doc Same as state2file(State,SchemaName)%%%% The name of the saved file is the same as the name of the%% schema, but with <code>.xss</code> extension.state2file(S=#xsd_state{schema_name=SN}) ->    state2file(S,filename:rootname(SN)).%% @spec state2file(State,FileName) -> ok | {error,Reason}%%       State = global_state()%%       FileName = filename()%% @doc Saves the schema state with all information of the processed%% schema in a file. You can provide the file name for the saved%% state. FileName is saved with the <code>.xss</code> extension%% added.state2file(S,FileName) ->    save_xsd_state(S),    case catch ets:tab2file(S#xsd_state.table,lists:append(FileName,".xss")) of	{'EXIT',Reason} ->	    {error,{[],?MODULE,Reason}};	Ret -> Ret    end.%% @spec file2state(FileName) -> {ok,State} | {error,Reason}%%       State = global_state()%%       FileName = filename()%% @doc Reads the schema state with all information of the processed%% schema from a file created with <code>state2file/[1,2]</code>.  The%% format of this file is internal. The state can then be used%% validating an XML document.file2state(FileName) ->    case catch ets:file2tab(FileName) of	{ok,Tab} ->	    case load_xsd_state(Tab) of		[{state,S}] when is_record(S,xsd_state) ->		    xmerl_xsd_vsn_check(S);%%		    {ok,S};		Other ->		    {error,{[],?MODULE,{incomplete_file,FileName,Other}}}	    end;	{error,Reason} ->	    {error,{[],?MODULE,Reason}};	Other ->	    {error,{[],?MODULE,Other}}    end.save_xsd_state(S) ->    catch ets:insert(S#xsd_state.table,{state,S}).load_xsd_state(Table) ->    catch ets:lookup(Table,state).   xmerl_xsd_vsn() ->    case lists:keysearch(vsn,1,xmerl_xsd:module_info(attributes)) of	{value,{_,MD5_VSN}} ->	    MD5_VSN;	_ ->	    undefined    end.xmerl_xsd_vsn_check(S=#xsd_state{vsn=MD5_VSN}) ->    case [V||{vsn,V}<-xmerl_xsd:module_info(attributes)] of	[MD5_VSN] ->	    {ok,S};	_ ->	    {error,{[],?MODULE,{different_version_of_xmerl_xsd_module_used,		    state_not_reliable}}}    end.    	%% @spec process_validate(Schema,Element) -> Result%% @equiv process_validate(Schema,Xml,[])process_validate(Schema,Xml) ->    process_validate(Schema,Xml,[]).%% @spec process_validate(Schema,Element,Options) -> Result%%       Schema   = filename()%%       Element  = XmlElement%%       Options  = option_list()%%       Result   = {ValidXmlElement,State} | {error,Reason}%%       Reason   = [ErrorReason] | ErrorReason%% @doc Validates a parsed well-formed XML element towards an XML%% schema.  <p> Validates in two steps. First it processes the schema,%% saves the type and structure info in an ets table and then%% validates the element towards the schema.</p>%% <p> Usage example:</p>%% <p>%% <code>1>{E,_} = xmerl_scan:file("my_XML_document.xml").</code><br/>%% <code>2>{E2,_} = xmerl_xsd:validate("my_XML_Schema.xsd",E).</code>%% </p>%% <p> Observe that E2 may differ from E if for instance there are default%% values defined in <code>my_XML_Schema.xsd</code>.</p>process_validate(Schema,Xml,Opts) ->    TargetNamespace = target_namespace(Xml),    case Schema of	[H|_] when is_list(H); is_tuple(H) ->	    case process_schemas(Schema,				 [{target_namespace,TargetNamespace}|Opts]) of		{ok,S} ->		    S2 = validation_options(S,Opts),		    validate3(S2#xsd_state.schema_name,Xml,S2);		Err ->		    Err	    end;	_ ->	    process_validate2(xmerl_scan:file(Schema),Schema,Xml,Opts)    end.process_validate2(Err={error,_},_,_,_) ->    Err;process_validate2({SE,_},Schema,Xml,Opts) ->    S = initiate_state(Opts,Schema),    S1 = validate_schema(SE,S),    S2 = validate_schema_ph2(S1),    S3 = schema_concistence_checks(S2),    S4 = validation_options(S3,Opts),    validate3(Schema,Xml,S4).validate3(Schema,Xml,S=#xsd_state{errors=[]}) ->     Ret = {_,S2} = 	case catch validate_xml(Xml,S) of	    {[XML2],[],Sx}  ->		{XML2,Sx};	    {XML2,[],Sx} ->		{XML2,Sx};	    {_,UnValidated,Sx} ->		{Xml,acc_errs(Sx,{error_path(UnValidated,Xml#xmlElement.name),?MODULE,{unvalidated_rest,UnValidated}})};	    _Err = {error,Reason} ->		{Xml,acc_errs(S,Reason)};	    {'EXIT',Reason} ->		{Xml,acc_errs(S,{error_path(Xml,Xml#xmlElement.name),?MODULE,{undefined,{internal_error,Reason}}})}	end,    save_to_file(S2,filename:rootname(Schema)++".tab2"),    case S2#xsd_state.errors of	[] ->	    Ret;	L ->	    delete_table(S2),	    return_error(L)    end;validate3(_,_,S) ->    return_schema_error(S#xsd_state.errors).%% @spec process_schema(Schema) -> Result%% @equiv process_schema(Schema,[])process_schema(Schema) ->    process_schema(Schema,[]).%% @spec process_schema(Schema,Options) -> Result%%       Schema  = filename()%%       Result  = {ok,State} | {error,Reason}%%       State   = global_state()%%       Reason  = [ErrorReason] | ErrorReason%%       Options = option_list()%% @doc Reads the referenced XML schema and controls it is valid.%% Returns the <code>global_state()</code> with schema info or an %% error reason. The error reason may be a list of several errors%% or a single error encountered during the processing.process_schema(Schema,Options) when is_list(Options) ->    S = initiate_state(Options,Schema),    process_schema2(xmerl_scan:file(Schema),S,Schema);process_schema(Schema,State) when is_record(State,xsd_state) ->    process_schema2(xmerl_scan:file(Schema),State,Schema).process_schema2(Err={error,_},_,_) ->    Err;process_schema2({SE,_},State,_Schema) ->    S1 = validate_schema(SE,State),    S2 = validate_schema_ph2(S1),    case schema_concistence_checks(S2) of	S3 = #xsd_state{errors=[]} ->	    {ok,S3};	S3 ->	    delete_table(S3),	    return_error(S3#xsd_state.errors)    end.%% @spec process_schemas(Schemas) -> Result%% @equiv process_schema(Schemas,[])process_schemas(Schemas) ->    process_schemas(Schemas,[]).%% @spec process_schemas(Schemas,Options) -> Result%%       Schemas  = [{NameSpace,filename()}|Schemas] | []%%       Result   = {ok,State} | {error,Reason}%%       Reason   = [ErrorReason] | ErrorReason%%       Options  = option_list()%% @doc Reads the referenced XML schemas and controls they are valid.%% Returns the <code>global_state()</code> with schema info or an %% error reason. The error reason may be a list of several errors%% or a single error encountered during the processing.process_schemas(Schemas=[{_,Schema}|_],Options) when is_list(Options) ->    process_schemas(Schemas,initiate_state(Options,Schema));process_schemas([{_NS,Schema}|Rest],State=#xsd_state{fetch_fun=Fetch}) ->%%      case process_external_schema_once(Schema,if_list_to_atom(NS),State) of%%   	S when is_record(S,xsd_state) ->%%     case process_schema(filename:join([State#xsd_state.xsd_base,Schema]),State) of%% 	{ok,S} ->    Res=    case Fetch(Schema,State) of	{ok,{file,File},_} ->	    process_schema2(xmerl_scan:file(File),State,Schema);	{ok,{string,Str},_} ->	    process_schema2(xmerl_scan:string(Str),State,Schema);	{ok,[],_} ->	    {ok,State};	Err ->	    Err    end,    case Res of	{ok,S2} ->	    process_schemas(Rest,S2);	_ ->	    Res    end;process_schemas([],S) when is_record(S,xsd_state) ->    {ok,S}.initiate_state(Opts,Schema) ->    XSDBase = filename:dirname(Schema),    {{state,S},RestOpts}=new_state(Opts),    S2 = create_tables(S),    initiate_state2(S2#xsd_state{schema_name = Schema,				xsd_base = XSDBase,				fetch_fun = fun fetch/2},RestOpts).initiate_state2(S,[]) ->    S;initiate_state2(S,[{tab2file,Bool}|T]) ->    initiate_state2(S#xsd_state{tab2file=Bool},T);initiate_state2(S,[{xsdbase,XSDBase}|T]) ->    initiate_state2(S#xsd_state{xsd_base=XSDBase},T);initiate_state2(S,[{fetch_fun,FetchFun}|T]) ->    initiate_state2(S#xsd_state{fetch_fun=FetchFun},T);initiate_state2(S,[{fetch_path,FetchPath}|T]) ->    initiate_state2(S#xsd_state{fetch_path=FetchPath},T);initiate_state2(S,[{schema_preprocessed,Bool}|T]) ->    initiate_state2(S#xsd_state{schema_preprocessed=Bool},T);initiate_state2(S,[{target_namespace,_NS}|T]) ->%%    initiate_state2(S#xsd_state{targetNamespace=if_list_to_atom(NS)},T);    initiate_state2(S,T); %% used in validation phaseinitiate_state2(S,[H|T]) ->    error_msg("Invalid option: ~p~n",[H]),    initiate_state2(S,T).validation_options(S,[{target_namespace,NS}|T]) ->    validation_options(S#xsd_state{targetNamespace=if_list_to_atom(NS)},T);validation_options(S,[_H|T]) ->    validation_options(S,T);validation_options(S,[]) ->    S.new_state(Opts) ->    XSD_VSN = xmerl_xsd_vsn(),    keysearch_delete(state,1,Opts,{state,#xsd_state{vsn=XSD_VSN}}).%% validate_schema/2 traverses the shema element to save necessary%% information as defined elements and types.validate_schema(E=#xmlElement{},		    S) ->    %% namespace is always a xmlNamespace record, attributs a list of    %% #xmlAttributes and content a list of #xmlElements|#xmlText|...    %% Have to save namespace nodes. Use of namespace in paths for    %% unique,key and keyref are used after the schema is processed.    S1 = S#xsd_state{targetNamespace=target_namespace(E)},    case is_already_processed(S1#xsd_state.targetNamespace,S1) of	true ->	    save_namespace_definition(S1#xsd_state.targetNamespace,S1);	_ ->	    S2 = S1,%save_namespace_definition(S1#xsd_state.targetNamespace,S1),	    {CM,S3} = traverse_content(E,S2),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -