xmerl_validate.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 659 行 · 第 1/2 页
ERL
659 行
%%% 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.%%%%%%%%%----------------------------------------------------------------------%%% #0. BASIC INFORMATION%%%----------------------------------------------------------------------%%% @private%%% File: xmerl_validate.erl%%% Author : Sebastien Becuwe <sebastien.becuwe@cellicium.com>%%% Description : XML validation hooks for xmerl%%% %%% Modules used : lists, ets, xmerl_lib%%% %%%-----------------------------------------------------------------------module(xmerl_validate).-vsn('0.1').-date('27-11-02').-author('sebastien.becuwe@cellicium.com').-export([validate/2]).%%%%%%%%%%%%% TODOO%%%% Atributes data type id , idrefs, FIXED, ...-include("xmerl.hrl"). % record def, macros%% +type validate(xmerl_scanner(),xmlElement())->%% xmlElment() | {error,tuple()}.validate(#xmerl_scanner{doctype_name=DTName,doctype_DTD=OpProv}, #xmlElement{name=Name}) when DTName=/=Name,OpProv=/=option_provided-> {error, {mismatched_root_element,Name,DTName}};validate(#xmerl_scanner{rules=Rules}=S, XML=#xmlElement{name=Name})-> catch do_validation(read_rules(Rules,Name),XML,Rules,S);validate(_, XML) -> {error, {no_xml_element, XML}}.%% +type validate(rules(),xmlElement())->%% {ok,xmlElement()} | {error,tuple()}.do_validation(undefined,#xmlElement{name=Name}, _Rules,_S) -> {error,{unknown_element,Name}};do_validation(El_Rule,XML,Rules,S)-> case catch valid_attributes(El_Rule#xmlElement.attributes, XML#xmlElement.attributes,S) of {'EXIT',Reason} -> {error,Reason}; {error,Reason} -> {error,Reason}; Attr_2->% XML_=XML#xmlElement{attributes=Attr_2}, El_Rule_Cont = El_Rule#xmlElement.content, WSActionMode = ws_action_mode(El_Rule#xmlElement.elementdef, El_Rule_Cont,S), XML_Cont = XML#xmlElement.content, check_direct_ws_SDD(XML_Cont,WSActionMode), case valid_contents(El_Rule_Cont, XML_Cont,Rules,S,WSActionMode) of {error,Reason}-> {error,Reason}; {error,Reason,N}-> {error,Reason,N}; XMLS -> XML#xmlElement{attributes=Attr_2,content=XMLS} end end.check_direct_ws_SDD(XML,always_preserve) -> case XML of [#xmlText{}|_Rest] -> exit({error,{illegal_whitespace_standalone_doc,XML}}); _ -> ok end, case lists:reverse(XML) of [#xmlText{}|_Rest2] -> exit({error,{illegal_whitespace_standalone_doc,XML}}); _ -> ok end;check_direct_ws_SDD(_,_) -> ok.ws_action_mode({external,_},Content,#xmerl_scanner{standalone=yes}) -> case element_content(Content) of children -> always_preserve; _ -> preserve end;ws_action_mode(_,_,_) -> preserve.element_content(A) when atom(A),A /= any, A /= empty -> children;element_content({choice,L}) when list(L) -> element_content(L);element_content({seq,L}) when list(L) -> element_content(L);element_content(['#PCDATA'|_T]) -> mixed;element_content('#PCDATA') -> mixed;element_content({'*',Rest}) -> element_content(Rest);element_content(_) -> children.%% +type read_rules(DTD::atom(),Element_Name::atom())->%% undefined | xmlElement().read_rules(_, pcdata) -> pcdata;read_rules(T, Name) -> case ets:lookup(T, {elem_def, Name}) of [] -> undefined; [{_K, V}] -> V end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Attributes Validation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +deftype attribute_rule() = {Attr_Name::atom(),attribute_type(),%% attribute_priority()}.%% +type valid_attributes([attribute_rule()],[xmlAttribute()])->%% [xmlAttribute()] | {error,attribute_unknow}.valid_attributes(All_Attr,[#xmlAttribute{}|_T]=Attr,S)-> single_ID_definition(All_Attr), vc_Name_Token_IDREFS(All_Attr,Attr), lists:foreach(fun(#xmlAttribute{name=Name})-> case is_attribute_exist(Name,All_Attr) of true -> ok; false -> exit({error,{attribute_unknown,Name}}) end end, Attr), lists:flatten(lists:foldl(fun({Name,DataType,IF,DefDecl,Env},Attr_2)-> Attr_2++ [valid_attribute(Name,DataType,IF, DefDecl,Attr,Env,S)] end,[],All_Attr));valid_attributes([],[],_) -> [];valid_attributes(All_Attr,[],S) -> single_ID_definition(All_Attr), lists:flatten(lists:foldl(fun({Name,DataType,IF,DefDecl,Env},Attr_2)-> Attr_2++[valid_attribute(Name, DataType,IF, DefDecl, [], Env,S)] end,[],All_Attr)).%%%% [60] DefaultDecl::= %%%% '#REQUIRED' | '#IMPLIED' %%%% | (('#FIXED' S)? AttValue)%% +deftype attribute_priority = '#REQUIRED'|'#FIXED'|'#IMPLIED'.%% +type valid_attribute(Name::atom(),DataType::attribute_value(),%% IF::attribute_priority(),[xmlAttribute()])->%% [xmlAttribute()] | exit().valid_attribute(Name,DataType,IF,DefaultDecl,List_of_Attributes,Env,S)-> SA = S#xmerl_scanner.standalone, Attr=search_attr(Name,List_of_Attributes), check_SDD_validity(SA,Env,Attr,IF), case {DefaultDecl,IF,Attr} of {'#REQUIRED',_,no_attribute}-> exit({error,{Name,is_required}}); {'#IMPLIED',_,no_attribute}-> []; %% and no default value {'#FIXED',DefVal,#xmlAttribute{value=DefVal}=Attr} -> Attr; {'#FIXED',A,no_attribute} -> #xmlAttribute{name=Name,value=A}; % FIXED declare value becomes default. {'#FIXED',A,B} -> exit({error,{fixed_default_value_missmatch,A,B}}); {_,Value,no_attribute} when list(Value)-> #xmlAttribute{name=Name,value=Value}; {_,_,#xmlAttribute{}=Attr}-> %% do test data value, and default_value test_attribute_value(DataType,Attr,IF,S); {DefDecl,Else,XML} -> exit({error,{unknow_attribute_type,DefDecl,Else,XML}}) end.vc_Name_Token_IDREFS([{Name,Type,_,_,_}|Rest],Attrs) when Type=='NMTOKEN';Type=='NMTOKENS'-> case lists:keysearch(Name,#xmlAttribute.name,Attrs) of {value,A} -> valid_nmtoken_value(A#xmlAttribute.value,Type); _ -> ok end, vc_Name_Token_IDREFS(Rest,Attrs);vc_Name_Token_IDREFS([{Name,Type,_,_,_}|Rest],Attrs) when Type=='IDREFS'-> case lists:keysearch(Name,#xmlAttribute.name,Attrs) of {value,A} -> valid_IDREFS(A#xmlAttribute.value,Type); _ -> ok end, vc_Name_Token_IDREFS(Rest,Attrs);vc_Name_Token_IDREFS([_H|Rest],Attrs) -> vc_Name_Token_IDREFS(Rest,Attrs);vc_Name_Token_IDREFS([],_) -> ok.valid_nmtoken_value([],'NMTOKENS') -> exit({error,{at_least_one_Nmtoken_required}});% valid_nmtoken_value([H|_T] = L,'NMTOKENS') when list(H) ->% ValidChar =% fun(X) ->% case xmerl_lib:is_namechar(X) of% false ->% exit({error,{invalid_character_in_Nmtoken,X}});% _ -> ok% end% end,% ValidCharList =% fun([Nmtok|T],F) -> % lists:foreach(ValidChar,Nmtok),% F(T,F);% ([],_) -> ok% end,% ValidCharList(L,ValidChar);valid_nmtoken_value(Nmtok,_) -> ValidChar = fun(X) when ?whitespace(X),Nmtok=='NMTOKENS' -> ok; (X) -> case xmerl_lib:is_namechar(X) of false -> exit({error,{invalid_character_in_Nmtoken,X}}); _ -> ok end end, lists:foreach(ValidChar,Nmtok).valid_IDREFS([],'IDREFS') -> exit({error,{at_least_one_IDREF_Name_required}});valid_IDREFS(_Str,'IDREFS') -> ok. single_ID_definition([{_,'ID',_,_,_}=Att1|Rest]) -> case lists:keysearch('ID',2,Rest) of {value,Att2} -> exit({error,{just_one_ID_definition_allowed,Att1,Att2}}); _ -> ok end;single_ID_definition([_H|T]) -> single_ID_definition(T);single_ID_definition([]) -> ok. check_SDD_validity(yes,{external,_},#xmlAttribute{name=Name,normalized=true},_) -> exit({error,{externally_defed_attribute_normalized_in_standalone_doc,Name}});check_SDD_validity(yes,{external,_},no_attribute,V) when V /= no_value-> exit({error,{externally_defed_attribute_with_default_value_missing_in_standalone_doc}});check_SDD_validity(_,_,_,_) -> ok. search_attr(Name,[#xmlAttribute{name=Name}=H|_T])-> H;search_attr(Name,[#xmlAttribute{}|T])-> search_attr(Name,T);search_attr(_Name,_T) -> no_attribute.is_attribute_exist(Name,[{Name,_,_,_,_}|_T])-> true;is_attribute_exist(Name,[{_Attr,_,_,_,_}|T]) -> is_attribute_exist(Name,T);is_attribute_exist(_Name,[]) -> false.%%%%[54] AttType::= StringType | TokenizedType | EnumeratedType %%%%[55] StringType::= 'CDATA'%%%%[56] TokenizedType::= 'ID'|'IDREF'| 'IDREFS'|'ENTITY'| 'ENTITIES'%%%% | 'NMTOKEN'| 'NMTOKENS'%%%%[57] EnumeratedType::= NotationType | Enumeration %%%%[58] NotationType::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' %%%%[59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'%% +deftype attribute_type()-> 'CDATA' | 'ID'|'IDREF'| 'IDREFS'|'ENTITY'| %% 'ENTITIES'| 'NMTOKEN'| 'NMTOKENS'%% {enumeration,[List_of_value::atom()]}.%% +type test_attribute_value(attribute_type(),xmlAttribute())->%% xmlAttribute()| exit.%%%% test the constraint validity of Attribute value.test_attribute_value('CDATA',#xmlAttribute{}=Attr,_,_) -> Attr;test_attribute_value('NMTOKEN',#xmlAttribute{name=Name,value=V}=Attr, Default,_S) -> Fun = fun (X)-> case xmerl_lib:is_namechar(X) of true-> ok; false-> %%io:format("Warning*** nmtoken,value_incorrect: ~p~n",[V]), exit({error,{invalid_value_nmtoken,Name,V}}) end end, lists:foreach(Fun,V), if list(Default) -> lists:foreach(Fun,Default); true -> ok end, Attr;test_attribute_value('NMTOKENS',#xmlAttribute{name=Name,value=V}=Attr,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?