📄 xmerl_xsd_type.erl
字号:
T==nonPositiveInteger;T==long;T==unsignedLong;T==int;T==unsignedInt; T==short;T==unsignedShort;T==byte;T==unsignedByte;T==decimal -> fun(Val) -> Len = case string:tokens(Val,".") of [_I,Frc] when T==decimal -> Pred = fun($0)-> true; (_) -> false end, length(lists:dropwhile(Pred,lists:reverse(Frc))); _ -> 0 end, if Len =< V -> {ok,Val}; true -> {error,{fractionDigits,Len,to_many_digits_in,Val}} end end;fractionDigits_fun(T,_V) -> fun(_) -> {error,{fractionDigits,not_applicable,T}} end. %% The relation between F1 and F2 may be eq,lt or gt.%% lt: F1 < F2%% gt: F1 > F2compare_floats(F1,F2) when F1=="NaN";F2=="NaN" -> {error,{not_comparable}};compare_floats(F1,F1) -> eq;compare_floats(F1,F2) when F1=="INF";F2=="-INF" -> gt;compare_floats(F1,F2) when F1=="-INF";F2=="INF" -> lt;compare_floats(Str1,Str2) -> F1={S1,_B1,_D1,_E1} = str_to_float(Str1), F2={S2,_B2,_D2,_E2} = str_to_float(Str2),% io:format("F1: ~p~nF2: ~p~n",[F1,F2]), if S1=='-',S2=='+' -> lt; S1=='+',S2=='-' -> gt;% B1<0 -> compare_floats2(F2,F1); true -> compare_floats2(F1,F2) end.compare_floats2({S1,B1,D1,E1},{_S2,B2,D2,E2}) when B1==0;B2==0 -> I1 = pow(B1,D1,E1), I2 = pow(B2,D2,E2), if I1 > I2 -> sign(S1,gt); I1 < I2 -> sign(S1,lt); true -> eq end;compare_floats2({S1,B1,D1,E1},{_S2,B2,D2,E2}) -> %% S1 and S2 have same sign. I1 = pow(B1,E1),% B1 * round(math:pow(10,E1)), I2 = pow(B2,E2),%B2 * round(math:pow(10,E2)), if I1 > I2 -> sign(S1,gt); I1 < I2 -> sign(S1,lt); true -> %% fractions are compared in lexicographic order if D1 == D2 -> eq; D1 < D2 -> sign(S1,lt); D1 > D2 -> sign(S1,gt) end end. str_to_float(String) -> {Sign,Str} = case String of "-"++Str1 -> {'-',Str1}; _ -> {'+',String} end, case string:tokens(Str,".") of [B,DE] -> case string:tokens(DE,"Ee") of [D,E] -> %% round(math:pow(10,list_to_integer(E))) {Sign,list_to_integer(B), remove_trailing_zeros(D), list_to_integer(E)}; [D] -> {Sign,list_to_integer(B), remove_trailing_zeros(D),0} end; [B] -> %% could also be 1E4, but no fraction case string:tokens(Str,"Ee") of [I,E] -> {Sign,list_to_integer(I),"0",list_to_integer(E)}; _ -> {Sign,list_to_integer(B),"0",0} end end.pow(Mantissa,Exponent) -> case (Mantissa * math:pow(10,Exponent)) of I when I<1 -> I; I -> round(I) end.pow(Mantissa,Fraction,Exponent) -> (Mantissa * math:pow(10,Exponent)) + (list_to_integer(Fraction) * math:pow(10,Exponent-length(Fraction))).sign('-',gt) -> lt;sign('-',lt) -> gt;sign(_,Rel) -> Rel.remove_trailing_zeros(Str) -> Pred = fun($0) ->true;(_) ->false end, case lists:reverse(lists:dropwhile(Pred,lists:reverse(Str))) of [] -> "0"; Fr -> Fr end.%% when T==duration;T==dateTime;T==date;T==time;T==gYear;T==gYearMonth;%% T==gMonth;T==gMonthDay;T==gDay ->%% compare_duration(V1,V2) compares V1 to V2%% returns gt | lt | eq | indefinite %% ex: V1 > V2 -> gt%%%% V1, V2 on format PnYnMnDTnHnMnS%% P is always present%% T is absent iff all time items are absent%% compare_duration(V1,V2) ->%% {Y1,M1,D1,H1,M1,S1} = duration_atoms(V1),%% {Y2,M2,D2,H2,M2,S2} = duration_atoms(V2),%% YearDiff = Y1 - Y2,%% MonthsDiff = M1 - M2,%% DaysDiff = D1 - D2,compare_durations(V1,V2) -> %% Four reference dateTimes are used, see XMLSchema part 2, %% 3.2.6.2. %% "The order-relation of two duration values x and y is x < y iff %% s+x < s+y for each qualified dateTime s in the list below." Ref1_dateTime = {1696,9,1,0,0,0,{pos,0,0}},%1696-09-01T00:00:00Z Ref2_dateTime = {1697,2,1,0,0,0,{pos,0,0}},%1697-02-01T00:00:00Z Ref3_dateTime = {1903,3,1,0,0,0,{pos,0,0}},%1903-03-01T00:00:00Z Ref4_dateTime = {1903,7,1,0,0,0,{pos,0,0}},%1903-07-01T00:00:00Z CmpRes1=compare_dateTime(normalize_dateTime(add_duration2dateTime(Ref1_dateTime,V1)), normalize_dateTime(add_duration2dateTime(Ref1_dateTime,V2))), CmpRes2=compare_dateTime(normalize_dateTime(add_duration2dateTime(Ref2_dateTime,V1)), normalize_dateTime(add_duration2dateTime(Ref2_dateTime,V2))), CmpRes3=compare_dateTime(normalize_dateTime(add_duration2dateTime(Ref3_dateTime,V1)), normalize_dateTime(add_duration2dateTime(Ref3_dateTime,V2))), CmpRes4=compare_dateTime(normalize_dateTime(add_duration2dateTime(Ref4_dateTime,V1)), normalize_dateTime(add_duration2dateTime(Ref4_dateTime,V2))), if CmpRes1==CmpRes2, CmpRes1==CmpRes3, CmpRes1==CmpRes4 -> CmpRes1; true -> indefinite end.compare_dateTime(DT1={_,_,_,_,_,_,Z},DT2={_,_,_,_,_,_,Z}) -> case DT1<DT2 of true -> lt; _ -> case DT1>DT2 of true -> gt; _ -> eq end end;%% If P contains a time zone and Q does not, compare as follows:%% 1. P < Q if P < (Q with time zone +14:00)%% 2. P > Q if P > (Q with time zone -14:00)%% 3. P <> Q otherwise, that is, if (Q with time zone +14:00) < P <%% (Q with time zone -14:00)compare_dateTime(P={_,_,_,_,_,_,{_,_,_}},_Q={Y,M,D,H,Min,S,none}) -> case compare_dateTime(P,normalize_dateTime({Y,M,D,H,Min,S,{pos,14,0}})) of lt -> lt; _ -> case compare_dateTime(P,normalize_dateTime({Y,M,D,H,Min,S,{neg,14,0}})) of gt -> gt; _ -> indefinite end end;%% If P does not contain a time zone and Q does, compare as follows:%% 1. P < Q if (P with time zone -14:00) < Q.%% 2. P > Q if (P with time zone +14:00) > Q.%% 3. P <> Q otherwise, that is, if (P with time zone +14:00) < Q <%% (P with time zone -14:00)compare_dateTime(_P={Y,M,D,H,Min,S,none},Q={_,_,_,_,_,_,{_,_,_}}) -> case compare_dateTime(normalize_dateTime({Y,M,D,H,Min,S,{neg,14,0}}),Q) of lt -> lt; _ -> case compare_dateTime(normalize_dateTime({Y,M,D,H,Min,S,{pos,14,0}}),Q) of gt -> gt; _ -> indefinite end end;compare_dateTime(P,Q) when is_list(P) -> compare_dateTime(normalize_dateTime(dateTime_atoms(P)),Q);compare_dateTime(P,Q) when is_list(Q) -> compare_dateTime(P,normalize_dateTime(dateTime_atoms(Q)));compare_dateTime(_P,_Q) -> indefinite. fQuotient(A,B) when is_float(A) -> fQuotient(floor(A),B);fQuotient(A,B) when is_float(B) -> fQuotient(A,floor(B));fQuotient(A,B) when A >= 0, B >= 0 -> A div B;fQuotient(A,B) when A < 0, B < 0 -> A div B;fQuotient(A,B) -> case A rem B of 0 -> A div B; _ -> (A div B) -1 end.fQuotient(A, Low, High) -> fQuotient(A - Low, High - Low).floor(A) -> case round(A) of I when I > A -> I - 1; I -> I end.modulo(A,B) -> A - (fQuotient(A,B) * B).modulo(A, Low, High) -> modulo(A - Low, High - Low) + Low. maximumDayInMonthFor(YearValue, MonthValue) -> M = modulo(MonthValue, 1, 13), Y = YearValue + fQuotient(MonthValue, 1, 13), monthValue(M,Y).monthValue(M,_Y) when M==1;M==3;M==5;M==7;M==8;M==10;M==12 -> 31;monthValue(M,_Y) when M==4;M==6;M==9;M==11 -> 30;monthValue(_M,Y) -> case modulo(Y,400) of 0 -> 29; _ -> case {modulo(Y,100) /= 0,modulo(Y,4)} of {true,0} -> 29; _ -> 28 end end. %% S dateTime, D duration%% result is E dateTime, end of time period with start S and duration%% D. E = S + D.add_duration2dateTime(S,D) when is_list(S),is_list(D) -> Satoms = dateTime_atoms(S), case duration_atoms(D) of Datoms = {_,_,_,_,_,_} -> add_duration2dateTime2(Satoms,Datoms); Err -> {error,Err} end;add_duration2dateTime(S={_,_,_,_,_,_,_},D) -> case duration_atoms(D) of Datoms = {_,_,_,_,_,_} -> add_duration2dateTime2(S,Datoms); Err -> {error,Err} end.add_duration2dateTime2({Syear,Smonth,Sday,Shour,Sminute,Ssec,Szone}, {Dyears,Dmonths,Ddays,Dhours,Dminutes,Dsecs}) -> %% months Temp1 = Smonth + Dmonths, Emonth = modulo(Temp1,1,13), Carry1 = fQuotient(Temp1,1,13), %% years Eyear = Syear + Dyears + Carry1, %% seconds Temp2 = Ssec + Dsecs, Esecs = modulo(Temp2,60), Carry2 = fQuotient(Temp2,60), %% minutes Temp3 = Sminute + Dminutes + Carry2, Eminute = modulo(Temp3,60), Carry3 = fQuotient(Temp3,60), %% hours Temp4 = Shour + Dhours + Carry3, Ehour = modulo(Temp4,24), Carry4 = fQuotient(Temp4,24), %% days TempDays = case maximumDayInMonthFor(Eyear,Emonth) of MaxDay when Sday > MaxDay -> MaxDay; _ -> case Sday < 1 of true -> 1; _ -> Sday end end, {Eyear2,Emonth2,Eday} = carry_loop(TempDays+Ddays+Carry4,Emonth,Eyear), {Eyear2,Emonth2,Eday,Ehour,Eminute,Esecs,Szone}.carry_loop(Eday,Emonth,Eyear) when Eday < 1 -> carry_loop(Eday + maximumDayInMonthFor(Eyear,Emonth - 1), modulo(Emonth - 1,1,13), Eyear + fQuotient(Emonth - 1,1,13));carry_loop(Eday,Emonth,Eyear) -> case maximumDayInMonthFor(Eyear,Emonth) of MaxD when Eday > MaxD -> carry_loop(Eday - maximumDayInMonthFor(Eyear,Emonth), modulo(Emonth + 1,1,13), Eyear + fQuotient(Emonth+1,1,13)); _ -> {Eyear,Emonth,Eday} end.%% Format: '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?dateTime_atoms("-" ++ DT) -> dateTime_atoms(DT,neg);dateTime_atoms(DT) -> dateTime_atoms(DT,pos).dateTime_atoms(S,Sign) -> [Date,TimeZone] = string:tokens(S,"T"), [YY,MM,DD] = string:tokens(Date,"-"), {Zone,ZoneSign,[Hour,Min,Sec]} = case lists:reverse(TimeZone) of "Z"++_ -> {"Z",pos,string:tokens(TimeZone,"Z:")}; _ -> ZS = zone_sign(TimeZone), case string:tokens(TimeZone,"-+") of [Time,Z] -> {Z,ZS,string:tokens(Time,":")}; [Time] -> {none,ZS,string:tokens(Time,":")} end end, {set_sign(Sign,YY),list_to_integer(MM),list_to_integer(DD), list_to_integer(Hour),list_to_integer(Min),sign_sec(pos,Sec), zone_atoms(ZoneSign,Zone)}.zone_sign(TimeZone) -> case lists:member($-,TimeZone) of true -> neg; _ -> pos end.zone_atoms(_Sign,"Z") -> {pos,0,0};zone_atoms(Sign,Zone) when is_list(Zone) -> case string:tokens(Zone,":") of [H,M] -> {Sign,list_to_integer(H),list_to_integer(M)}; _ -> none end;zone_atoms(_Sign,Zone) -> Zone. %% Format: '-'? PnYnMnDTnHnMnSduration_atoms("-P"++Dur) -> duration_atoms2(Dur,neg);duration_atoms("P"++Dur) -> duration_atoms2(Dur,pos);duration_atoms(Dur) -> {illegal_duration,Dur}.duration_atoms2(Dur,Sign) -> case lists:member($T,Dur) of true -> %% time atoms exists case string:tokens(Dur,"T") of [Date,Time] -> case duration_atoms_date(Date) of {Y,M,D} -> case duration_atoms_time(Time) of {Hour,Min,Sec} -> {set_sign(Sign,Y),set_sign(Sign,M), set_sign(Sign,D),set_sign(Sign,Hour), set_sign(Sign,Min),sign_sec(Sign,Sec)}; Err -> Err end; Err -> Err end; [Time] -> case duration_atoms_time(Time) of {Hour,Min,Sec} -> {0,0,0,set_sign(Sign,Hour),set_sign(Sign,Min), sign_sec(Sign,Sec)}; Err -> Err end; Err -> {illegal_duration,Err} end; _ -> %% only date coomponents {Y,M,D} = duration_atoms_date(Dur), {set_sign(Sign,Y),set_sign(Sign,M),set_sign(Sign,D),0,0,0} end.duration_atoms_date(Date) -> {Y,Date2} = get_digit(Date,$Y), {M,Date3} = get_digit(Date2,$M), {D,Rest} = get_digit(Date3,$D), case Rest of "" -> {Y,M,D}; Err -> {illegal_duration,Err} end.duration_atoms_time(Time) -> {H,Time2} = get_digit(Time,$H), {M,Time3} = get_digit(Time2,$M), {S,Rest} = get_sec(Time3), case Rest of "" -> {H,M,S}; Err -> {illegal_duration,Err} end.get_digit(Str,Delim) -> get_digit(Str,Delim,[],Str).get_digit([Delim|T],Delim,Acc,_Str) -> {lists:reverse(Acc),T};get_digit([H|T],Delim,Acc,Str) when H>=$0,H=<$9 -> get_digit(T,Delim,[H|Acc],Str);get_digit([],_,[],_Str) -> {"0",[]};get_digit([],_,_,Str) -> {"0",Str};get_digit(_,_,_,Str) -> %% this matches both the case when reaching another delimeter and %% when the string already are emptied. {"0",Str}.get_sec([]) -> {"0",[]};get_sec(Str) -> get_sec(Str,[],Str).get_sec([H|T],Acc,Str) when H>=$0,H=<$9 -> get_sec(T,[H|Acc],Str);get_sec([$.|T],Acc,Str) -> get_sec(T,[$.|Acc],Str);get_sec([$S|T],Acc,_) -> {lists:reverse(Acc),T};get_sec(_,_,Str) -> {"0",Str}. set_sign(pos,Istr) -> list_to_integer(Istr);set_sign(_,Istr) -> list_to_integer("-"++Istr).sign_sec(pos,Sec) -> case lists:member($.,Sec) of true -> list_to_float(Sec); _ -> list_to_integer(Sec) end;sign_sec(_,Sec) -> sign_sec(pos,"-"++Sec).invert_sign(pos) -> neg;invert_sign(neg) -> pos;invert_sign(S) -> S.normalize_dateTime({Y,M,D,Hour,Min,Sec,{Sign,ZH,ZM}}) -> %% minutes TmpMin = Min + set_sign(invert_sign(Sign),integer_to_list(ZM)), NMin = modulo(TmpMin,60), Carry1 = fQuotient(TmpMin,60), %% hours TmpHour = Hour + set_sign(invert_sign(Sign),integer_to_list(ZH)) + Carry1, NHour = modulo(TmpHour,24), Carry2 = fQuotient(TmpHour,24), {NY,NM,ND} = carry_loop(D+Carry2,M,Y), {NY,NM,ND,NHour,NMin,Sec,{pos,0,0}};normalize_dateTime(DT) -> DT.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -