Skip to content

Commit f6b9a85

Browse files
Copilotclemensv
andcommitted
Add enum, const, and custom properties support to increase feature coverage
Co-authored-by: clemensv <542030+clemensv@users.noreply.github.com>
1 parent 755ad3b commit f6b9a85

5 files changed

Lines changed: 149 additions & 9 deletions

File tree

avrotize/structuretoxsd.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,32 @@ def create_complex_type(self, parent: Element, **attributes) -> Element:
123123
"""Create an XML complexType element."""
124124
return self.create_element(parent, "complexType", **attributes)
125125

126+
def add_custom_properties_as_appinfo(self, element: Element, type_def: Dict) -> None:
127+
"""Add custom JSON Structure properties as xs:appinfo annotations."""
128+
custom_props = {}
129+
130+
# Collect custom properties that should be preserved
131+
for key in ['altnames', 'unit', 'currency', 'symbol', 'contentEncoding',
132+
'contentMediaType', 'multipleOf']:
133+
if key in type_def:
134+
custom_props[key] = type_def[key]
135+
136+
if custom_props:
137+
# Find or create annotation element
138+
annotation = element.find(f"{{{self.xmlns['xs']}}}annotation")
139+
if annotation is None:
140+
# Insert annotation as first child
141+
annotation = Element(f"{{{self.xmlns['xs']}}}annotation")
142+
element.insert(0, annotation)
143+
144+
# Add appinfo with custom properties
145+
appinfo = self.create_element(annotation, "appinfo")
146+
appinfo.set("source", "json-structure-extensions")
147+
148+
# Add custom properties as text content (JSON format)
149+
import json
150+
appinfo.text = json.dumps(custom_props, indent=2)
151+
126152
def create_simple_type_with_restriction(self, parent: Element, name: str, base_type: str, facets: Dict[str, Any]) -> Element:
127153
"""Create a simple type with restrictions (facets)."""
128154
simple_type = self.create_element(parent, "simpleType", name=name)
@@ -369,12 +395,29 @@ def set_element_type(self, schema_root: Element, record_name: str, element: Elem
369395
if key in type_def:
370396
facets[key] = type_def[key]
371397

372-
if facets:
398+
# Check for enum or const constraints
399+
has_enum = 'enum' in type_def
400+
has_const = 'const' in type_def
401+
402+
if facets or has_enum or has_const:
373403
# Create an anonymous simple type with restriction
374404
simple_type = self.create_element(element, "simpleType")
375405
restriction = self.create_element(simple_type, "restriction", base=xsd_type)
376406
element.attrib.pop('type', None) # Remove type attribute
377407

408+
# Handle enum constraint
409+
if has_enum:
410+
enum_values = type_def['enum']
411+
if isinstance(enum_values, list):
412+
for enum_value in enum_values:
413+
self.create_element(restriction, "enumeration", value=str(enum_value))
414+
415+
# Handle const constraint (single enumeration value)
416+
elif has_const:
417+
const_value = type_def['const']
418+
self.create_element(restriction, "enumeration", value=str(const_value))
419+
420+
# Handle other facets
378421
for facet_name, facet_value in facets.items():
379422
if facet_name == 'minLength':
380423
self.create_element(restriction, "minLength", value=str(facet_value))
@@ -436,6 +479,10 @@ def convert_object_properties(self, schema_root: Element, type_name: str, parent
436479
documentation = self.create_element(annotation, "documentation")
437480
documentation.text = prop_def['description']
438481

482+
# Add custom properties as appinfo
483+
if isinstance(prop_def, dict):
484+
self.add_custom_properties_as_appinfo(prop_element, prop_def)
485+
439486
self.set_element_type(schema_root, type_name, prop_element, prop_def)
440487

441488
def process_type_definition(self, schema_root: Element, type_name: str, type_def: Dict):

test/struct/complex-scenario-ref.xsd

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,19 @@
6565
<xs:element name="value">
6666
<xs:complexType>
6767
<xs:sequence>
68-
<xs:element name="type" minOccurs="1" maxOccurs="1" type="xs:string"/>
68+
<xs:element name="type" minOccurs="1" maxOccurs="1">
69+
<xs:simpleType>
70+
<xs:restriction base="xs:string">
71+
<xs:enumeration value="measurement"/>
72+
</xs:restriction>
73+
</xs:simpleType>
74+
</xs:element>
6975
<xs:element name="value" minOccurs="1" maxOccurs="1">
76+
<xs:annotation>
77+
<xs:appinfo source="json-structure-extensions">{
78+
&quot;unit&quot;: &quot;m/s\u00b2&quot;
79+
}</xs:appinfo>
80+
</xs:annotation>
7081
<xs:simpleType>
7182
<xs:restriction base="xs:decimal">
7283
<xs:totalDigits value="15"/>
@@ -110,9 +121,33 @@
110121
<xs:element name="value">
111122
<xs:complexType>
112123
<xs:sequence>
113-
<xs:element name="type" minOccurs="1" maxOccurs="1" type="xs:string"/>
114-
<xs:element name="name" minOccurs="1" maxOccurs="1" type="xs:string"/>
115-
<xs:element name="severity" minOccurs="1" maxOccurs="1" type="xs:string"/>
124+
<xs:element name="type" minOccurs="1" maxOccurs="1">
125+
<xs:simpleType>
126+
<xs:restriction base="xs:string">
127+
<xs:enumeration value="event"/>
128+
</xs:restriction>
129+
</xs:simpleType>
130+
</xs:element>
131+
<xs:element name="name" minOccurs="1" maxOccurs="1" type="xs:string">
132+
<xs:annotation>
133+
<xs:appinfo source="json-structure-extensions">{
134+
&quot;altnames&quot;: {
135+
&quot;json&quot;: &quot;event_name&quot;,
136+
&quot;lang:en&quot;: &quot;Event Name&quot;
137+
}
138+
}</xs:appinfo>
139+
</xs:annotation>
140+
</xs:element>
141+
<xs:element name="severity" minOccurs="1" maxOccurs="1">
142+
<xs:simpleType>
143+
<xs:restriction base="xs:string">
144+
<xs:enumeration value="low"/>
145+
<xs:enumeration value="medium"/>
146+
<xs:enumeration value="high"/>
147+
<xs:enumeration value="critical"/>
148+
</xs:restriction>
149+
</xs:simpleType>
150+
</xs:element>
116151
<xs:element name="details" minOccurs="0" maxOccurs="1">
117152
<xs:complexType>
118153
<xs:sequence>

test/struct/extensions-ref.xsd

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
<xs:element name="productName" minOccurs="1" maxOccurs="1">
1313
<xs:annotation>
1414
<xs:documentation>Product name with alternate names</xs:documentation>
15+
<xs:appinfo source="json-structure-extensions">{
16+
&quot;altnames&quot;: {
17+
&quot;json&quot;: &quot;product_name&quot;,
18+
&quot;lang:en&quot;: &quot;Product Name&quot;,
19+
&quot;lang:de&quot;: &quot;Produktname&quot;,
20+
&quot;lang:fr&quot;: &quot;Nom du Produit&quot;
21+
}
22+
}</xs:appinfo>
1523
</xs:annotation>
1624
<xs:simpleType>
1725
<xs:restriction base="xs:string">
@@ -20,6 +28,11 @@
2028
</xs:simpleType>
2129
</xs:element>
2230
<xs:element name="price" minOccurs="1" maxOccurs="1">
31+
<xs:annotation>
32+
<xs:appinfo source="json-structure-extensions">{
33+
&quot;currency&quot;: &quot;USD&quot;
34+
}</xs:appinfo>
35+
</xs:annotation>
2336
<xs:simpleType>
2437
<xs:restriction base="xs:decimal">
2538
<xs:minInclusive value="0"/>
@@ -29,14 +42,31 @@
2942
</xs:simpleType>
3043
</xs:element>
3144
<xs:element name="weight" minOccurs="0" maxOccurs="1">
45+
<xs:annotation>
46+
<xs:appinfo source="json-structure-extensions">{
47+
&quot;unit&quot;: &quot;kg&quot;
48+
}</xs:appinfo>
49+
</xs:annotation>
3250
<xs:simpleType>
3351
<xs:restriction base="xs:double">
3452
<xs:minInclusive value="0.0"/>
3553
</xs:restriction>
3654
</xs:simpleType>
3755
</xs:element>
38-
<xs:element name="temperature" minOccurs="0" maxOccurs="1" type="xs:double"/>
56+
<xs:element name="temperature" minOccurs="0" maxOccurs="1" type="xs:double">
57+
<xs:annotation>
58+
<xs:appinfo source="json-structure-extensions">{
59+
&quot;unit&quot;: &quot;\u00b0C&quot;,
60+
&quot;symbol&quot;: &quot;T&quot;
61+
}</xs:appinfo>
62+
</xs:annotation>
63+
</xs:element>
3964
<xs:element name="stockSymbol" minOccurs="0" maxOccurs="1">
65+
<xs:annotation>
66+
<xs:appinfo source="json-structure-extensions">{
67+
&quot;symbol&quot;: &quot;STOCK&quot;
68+
}</xs:appinfo>
69+
</xs:annotation>
4070
<xs:simpleType>
4171
<xs:restriction base="xs:string">
4272
<xs:maxLength value="10"/>

test/struct/nested-objects-ref.xsd

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@
8181
<xs:element name="item" minOccurs="0" maxOccurs="unbounded">
8282
<xs:complexType>
8383
<xs:sequence>
84-
<xs:element name="type" minOccurs="1" maxOccurs="1" type="xs:string"/>
84+
<xs:element name="type" minOccurs="1" maxOccurs="1">
85+
<xs:simpleType>
86+
<xs:restriction base="xs:string">
87+
<xs:enumeration value="home"/>
88+
<xs:enumeration value="work"/>
89+
<xs:enumeration value="mobile"/>
90+
</xs:restriction>
91+
</xs:simpleType>
92+
</xs:element>
8593
<xs:element name="number" minOccurs="1" maxOccurs="1">
8694
<xs:simpleType>
8795
<xs:restriction base="xs:string">

test/struct/validation-constraints-ref.xsd

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,29 @@
1818
</xs:restriction>
1919
</xs:simpleType>
2020
</xs:element>
21-
<xs:element name="enumField" minOccurs="1" maxOccurs="1" type="xs:string"/>
22-
<xs:element name="constField" minOccurs="0" maxOccurs="1" type="xs:string"/>
21+
<xs:element name="enumField" minOccurs="1" maxOccurs="1">
22+
<xs:simpleType>
23+
<xs:restriction base="xs:string">
24+
<xs:enumeration value="red"/>
25+
<xs:enumeration value="green"/>
26+
<xs:enumeration value="blue"/>
27+
<xs:enumeration value="yellow"/>
28+
</xs:restriction>
29+
</xs:simpleType>
30+
</xs:element>
31+
<xs:element name="constField" minOccurs="0" maxOccurs="1">
32+
<xs:simpleType>
33+
<xs:restriction base="xs:string">
34+
<xs:enumeration value="fixed-value"/>
35+
</xs:restriction>
36+
</xs:simpleType>
37+
</xs:element>
2338
<xs:element name="numberWithConstraints" minOccurs="0" maxOccurs="1">
39+
<xs:annotation>
40+
<xs:appinfo source="json-structure-extensions">{
41+
&quot;multipleOf&quot;: 5
42+
}</xs:appinfo>
43+
</xs:annotation>
2444
<xs:simpleType>
2545
<xs:restriction base="xs:int">
2646
<xs:minInclusive value="0"/>

0 commit comments

Comments
 (0)