diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e7de14c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +CHANGELOG +========= + +1.4.0 +----- + + * New option `strict` to enforce additional type conversion and checking. + + * Several modifications to allow better embedding of the parser (not + documented). + + * :warning: `models` that were compiled with earlier versions are no + longer supported. If you have stored a `model` and you want to upgrade + to the new version, the model must be recompiled. + +1.3.1 +----- + + * First tagged version. diff --git a/doc/reference.md b/doc/reference.md index da8b8ce..f263d31 100644 --- a/doc/reference.md +++ b/doc/reference.md @@ -41,6 +41,7 @@ Option = {prefix, Prefix} | {include_fun, Include_fun} | {include_dirs, Include_dirs} | {include_files, Include_files} | + {strict, boolean()} | {include_any_attribs, boolean()} Model = the internal representation of the XSD @@ -74,7 +75,7 @@ XSD can be an encoded binary (see section on character encoding) or a decoded li definitions in the XSD. It should be a string. See the explanation provided above for the TypePrefix option for the background of this option. -- `Include\_fun` is a function that finds the files that are included or +- `Include_fun` is a function that finds the files that are included or imported in the XSD. It should be a function that takes 4 arguments: - Namespace (from the XSD). This is a string or 'undefined' @@ -109,6 +110,19 @@ XSD can be an encoded binary (see section on character encoding) or a decoded li the file will be searched for in the include_dirs (based on the 'location' attribute). No prefix will be used. +- If `strict` == `false` (this is the default), then only the XML Schema + data types `integer`, `int`, `boolean` and `qname` are mapped to the + corresponding Erlang data type. All other data types are mapped to + `string()`. + + If `strict` == `true`, also the XML Schema data types `float` and `double` + as well as all data types derived from integer (nonPositiveInteger, + negativeInteger, long, short, byte, nonNegativeInteger, unsignedLong, + unsignedInt, unsignedShort, unsignedByte, positiveInteger) are mapped to + erlang float() (for float and double) or integer(). For the integer types + it will also be checked whether they are within the range specified for + the XML Schema type. + - If `include_any_attribs` == `true` (this is the default), then the second element of each of the records that are created by `erlsom:scan(Xml, Model)` will be a list that contains any attributes in the corresponding element of XML that are not explicitly specified by the diff --git a/src/erlsom_write.erl b/src/erlsom_write.erl index 34c5ec8..9f55e5f 100644 --- a/src/erlsom_write.erl +++ b/src/erlsom_write.erl @@ -317,14 +317,14 @@ processAlternativeValue(Value, Count, case Abstract of false -> {AnyAttributesString, DeclaredNamespaces2}; _ -> - XsiType = " xsi:type=\"" ++ atom_to_list(Name) ++ "\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", + XsiType = [" xsi:type=\"", atom_to_list(Name), "\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""], {[AnyAttributesString, XsiType], DeclaredNamespaces2} end, %% deal with namespaces (that is, see if they have to be declared here) {NamespacesString, NewDeclaredNamespaces4, Extra_prefix} = processNamespaces(TagAsText, Namespaces, DeclaredNamespaces3), ResultForThisElement = struct2xml(Value, Elements, [], Model, NewDeclaredNamespaces4, Mixed), - AllAttrs = [NamespacesString, AttributesString, AnyAttrPlusXsiTypeString, + AllAttrs = [NamespacesString, AttributesString, AnyAttrPlusXsiTypeString], printTag([Extra_prefix, TagAsText], AllAttrs, ResultForThisElement); true -> struct2xml(Value, Elements, [], Model, DeclaredNamespaces, Mixed) @@ -355,7 +355,7 @@ findAlternative(RecordType, Alternatives, #model{th = TypeHierarchy} = Model, Ab %% see whether this is an '#any' type case Alternatives of [#alt{tag='#any', anyInfo = #anyInfo{ns = AltNs}}] when AltNs /= "##other" -> - AnyAlternatives = [Alternatives, erlsom_lib:documentAlternatives(Model)], + AnyAlternatives = Alternatives ++ erlsom_lib:documentAlternatives(Model), findAlternative(RecordType, AnyAlternatives, Model, Abstract); _ -> %% see whether an ancestor in the type hierarchy is among the alternatives @@ -452,7 +452,7 @@ processAttributes(Struct, ResultSoFar, [#att{nm = Name, CharValue = [] end, %% NamespacesString is "" or " xmlns...". - ResultWithThisAttribute = ResultSoFar ++ NamespacesString2 ++ " " ++ NameAsString ++ "=\"" ++ CharValue ++ "\"", + ResultWithThisAttribute = [ResultSoFar, NamespacesString2, " ", NameAsString, "=\"", CharValue, "\""], processAttributes(Struct, ResultWithThisAttribute, Rest, Namespaces, DeclaredNamespaces2) end. @@ -469,15 +469,15 @@ writeQnameAttValue(#qname{uri = Uri, localPart = LP, mappedPrefix = MP}, Namespa %% see whether the namespace has been defined. If not, then this has to be done. case lists:keysearch(Uri, 2, NamespacesList) of {value, {Prefix, _Uri}} -> %% already declared - {Prefix ++ ":" ++ LP, NamespacesString, DeclaredNamespaces}; + {[Prefix, ":", LP], NamespacesString, DeclaredNamespaces}; _ -> %% see whether a prefix was specified case lists:keysearch(Uri, #ns.uri, Namespaces) of {value, #ns{prefix = Prefix2}} -> - {Prefix2 ++ ":" ++ LP, NamespacesString ++ " xmlns:" ++ Prefix2 ++ "=\"" ++ Uri ++ "\"", + {[Prefix2, ":", LP], [NamespacesString, " xmlns:", Prefix2, "=\"", Uri, "\""], {[{Prefix2, Uri} | NamespacesList], Counter}}; _ -> - {MP ++ ":" ++ LP, NamespacesString ++ " xmlns:" ++ MP ++ "=\"" ++ Uri ++ "\"", + {[MP, ":", LP], [NamespacesString, " xmlns:", MP, "=\"", Uri, "\""], {[{MP, Uri} | NamespacesList], Counter}} end end @@ -491,7 +491,7 @@ processAnyAttributes([], Acc, _Namespaces, DeclaredNamespaces) -> processAnyAttributes([{{Name, Uri}, Value} | Tail], Acc, Namespaces, DeclaredNamespaces) -> case Uri of [] -> - processAnyAttributes(Tail, Acc ++ " " ++ Name ++ "=\"" ++ decodeIfRequired(Value) ++ "\"", + processAnyAttributes(Tail, [Acc, " ", Name, "=\"", decodeIfRequired(Value), "\""], Namespaces, DeclaredNamespaces); _Other -> %% the "xsi:nil=true" is not written, because it is inserted in another way. @@ -503,7 +503,7 @@ processAnyAttributes([{{Name, Uri}, Value} | Tail], Acc, Namespaces, DeclaredNam _ -> %% get prefix +, if relevant, NS declaration text {PrefixedName, DeclaredNamespaces2} = processAnyNamespaces(Name, Uri, Namespaces, DeclaredNamespaces), - processAnyAttributes(Tail, Acc ++ " " ++ PrefixedName ++ "=\"" ++ decodeIfRequired(Value) ++ "\"", + processAnyAttributes(Tail, [Acc, " ", PrefixedName, "=\"", decodeIfRequired(Value), "\""], Namespaces, DeclaredNamespaces2) end end. @@ -551,19 +551,19 @@ processNamespaces(Tag, Namespaces, DeclaredNamespaces = {NamespacesList, Counter {value, #ns{uri = Uri, efd = qualified}} -> Xmlns = case Prefix of undefined -> " xmlns"; - _ -> " xmlns:" ++ Prefix + _ -> [" xmlns:", Prefix] end, - {Xmlns ++ "=\"" ++ Uri ++ "\"", {[{Prefix, Uri} | NamespacesList], Counter}, ""}; + {[Xmlns, "=\"", Uri, "\""], {[{Prefix, Uri} | NamespacesList], Counter}, ""}; {value, #ns{uri = Uri, efd = unqualified}} -> case Prefix of undefined -> Xmlns = " xmlns:erlsom", Additional_pf = "erlsom:"; _ -> - Xmlns = " xmlns:" ++ Prefix, + Xmlns = [" xmlns:", Prefix], Additional_pf = "" end, - {Xmlns ++ "=\"" ++ Uri ++ "\"", {[{Prefix, Uri} | NamespacesList], Counter}, Additional_pf}; + {[Xmlns, "=\"", Uri, "\""], {[{Prefix, Uri} | NamespacesList], Counter}, Additional_pf}; _ -> case Prefix of undefined -> {[], DeclaredNamespaces, ""}; @@ -576,7 +576,7 @@ processNamespaces(Tag, Namespaces, DeclaredNamespaces = {NamespacesList, Counter processAnyNamespaces(Name, Uri, Namespaces, {NamespacesList, Counter} = DeclaredNamespaces ) -> case lists:keysearch(Uri, 2, NamespacesList) of {value, {Prefix, _}} -> %% already declared - {Prefix ++ ":" ++ Name, DeclaredNamespaces}; + {[Prefix, ":", Name], DeclaredNamespaces}; _Else -> %% find Uri in Model case lists:keysearch(Uri, #ns.uri, Namespaces) of @@ -586,7 +586,7 @@ processAnyNamespaces(Name, Uri, Namespaces, {NamespacesList, Counter} = Declared %% make up a prefix, using counter ThePrefix = "pre" ++ integer_to_list(Counter +1) end, - PrefixName = " xmlns:" ++ ThePrefix ++ "=\"" ++ Uri ++ "\" " ++ ThePrefix ++ ":" ++ Name, + PrefixName = [" xmlns:", ThePrefix, "=\"", Uri, "\" ", ThePrefix, ":", Name], {PrefixName, {[{ThePrefix, Uri} | NamespacesList], Counter + 1}} end. @@ -740,9 +740,9 @@ printPrefix(Uri, Prefix, NamespacesList, Namespaces) -> end, Xmlns = case PrintedPrefix of undefined -> " xmlns"; - _ -> " xmlns:" ++ Prefix + _ -> [" xmlns:", Prefix] end, - {PrintedPrefix, Xmlns ++ "=\"" ++ Uri ++ "\""} + {PrintedPrefix, [Xmlns, "=\"", Uri, "\""]} end. printElement(TextValue, Tag, RealElement, Namespaces, DeclaredNamespaces, QnameNs) -> diff --git a/vsn.mk b/vsn.mk index 1072a0b..7e734b2 100644 --- a/vsn.mk +++ b/vsn.mk @@ -1,4 +1,4 @@ -ERLSOM_VSN=1.3.1 +ERLSOM_VSN=1.4.0