Skip to content

Commit

Permalink
fix: Don't duplicate #text elements.
Browse files Browse the repository at this point in the history
The duplicate #text elements were generated in the case,
when xsd:extension was used for xsd:simpleContent. That was
causing the generated records being invalid. We solve this by
filter the duplicate elements.
  • Loading branch information
kape1395 committed Sep 23, 2022
1 parent ec6cadd commit c1a3049
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ include.mk
.rebar
.eunit
.test
_build/
erlsom.plt
rebar.lock
5 changes: 5 additions & 0 deletions priv/extension/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all: validate

validate:
@xmllint --noout --schema extension.xsd extension.xml
@xmllint --noout --schema simpleContentExtension.xsd simpleContentExtension.xml
2 changes: 2 additions & 0 deletions priv/extension/simpleContentExtension.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://my.uri" a="aaa" b="bbb">myuri</test>
34 changes: 34 additions & 0 deletions priv/extension/simpleContentExtension.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://my.uri"
xmlns="http://my.uri"
xmlns:tns="http://my.uri"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
blockDefault="#all"
version="0.2">
<xsd:complexType name="AttributedString">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="a" type="xsd:string"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="EncodedString">
<xsd:simpleContent>
<xsd:extension base="tns:AttributedString">
<xsd:attribute name="b" type="xsd:string"/>
<xsd:attribute name="EncodingType" type="xsd:anyURI"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="KeyIdentifierType">
<xsd:simpleContent>
<xsd:extension base="tns:EncodedString">
<xsd:attribute name="ValueType" type="xsd:anyURI"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:element name="test" type="KeyIdentifierType"/>
</xsd:schema>
10 changes: 9 additions & 1 deletion src/erlsom_pass2.erl
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,16 @@ translateType(Type = #typeInfo{elements=Elemts, attributes=Attrs, extends = Base
%% debug(BaseEls),
%% debug(Attrs),
%% debug(BaseAttrs),
% In the case of extensions with xsd:simpleContent the '#text' element is duplicated causing
% generated type records failing to compile. Here we filter the duplicates out.
DropDupText = fun
DropDupText([#elementInfo{alternatives = [#alternative{tag = "#text"}]} = Head | Tail], false) -> [Head | DropDupText(Tail, true)];
DropDupText([#elementInfo{alternatives = [#alternative{tag = "#text"}]} | Tail], true) -> DropDupText(Tail, true);
DropDupText([#elementInfo{} = Head | Tail], Found) -> [Head | DropDupText(Tail, Found)];
DropDupText([], _Found) -> []
end,
NewAnyAttr = if BaseAnyAttr == undefined -> AnyAttr; true -> BaseAnyAttr end,
translateType(Type#typeInfo{elements = BaseEls ++ Elemts, %% TODO: will never be 'undefined'?
translateType(Type#typeInfo{elements = DropDupText(BaseEls ++ Elemts, false), %% TODO: will never be 'undefined'?
attributes = mergeAttrs(BaseAttrs, Attrs),
anyAttr = NewAnyAttr,
mixed = case Mixed of undefined -> Mixed2; _ -> Mixed end,
Expand Down
29 changes: 24 additions & 5 deletions test/erlsom_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
%% ------------------------------------------------------------------

-include_lib("eunit/include/eunit.hrl").

-include("src/erlsom_parse.hrl").
-compile([nowarn_export_all, export_all]).

gexf_test_() ->
Expand All @@ -18,10 +18,29 @@ all_test_() ->
[])}.

extension_test_() ->
{"Test XSD type extensions.",
verify_stability_(["extension", "extension.xsd"],
["extension", "extension.xml"],
[])}.
[{"Test XSD type extensions.",
verify_stability_(["extension", "extension.xsd"],
["extension", "extension.xml"],
[])},
{"Test simpleContent extension stable",
verify_stability_(["extension", "simpleContentExtension.xsd"],
["extension", "simpleContentExtension.xml"],
[])},
{"Test simpleContent #text not duplicated", fun () ->
{ok, #model{tps = Types}} = compile_xsd(["extension", "simpleContentExtension.xsd"], []),
ok = lists:foreach(fun (Type = #type{els = Els}) ->
IsTextEl = fun
(#el{alts = [#alt{tag = '#text'}]}) -> true;
(_) -> false
end,
% No duplicate entries for the #text.
% Type bellow is only used to get more informative failure.
case {Type, lists:filter(IsTextEl, Els)} of
{_, []} -> ok;
{_, [_]} -> ok
end
end, Types)
end}].

%% @doc
%% compile the XSD schema file with the given relative path, example:
Expand Down

0 comments on commit c1a3049

Please sign in to comment.