Skip to content

Commit 04f55e5

Browse files
authored
Add more lenient parsing (DM XML scraper workarounds) (#30065)
* More lenient parsing: naming and types * Even better logic * Lenient parsing updates for more type logic * Another constant * Update the test * Restyle * Merge with master with better diffing
1 parent bd8aa07 commit 04f55e5

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

scripts/py_matter_idl/matter_idl/data_model_xml/handlers/parsing.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,36 @@ def NormalizeDataType(t: str) -> str:
9090
return _TYPE_REMAP.get(t.lower(), t.replace("-", "_"))
9191

9292

93+
# Handle oddities in current data model XML schema for nicer diffs
94+
_REF_NAME_MAPPING = {
95+
"<<ref_DataTypeString>>": "char_string",
96+
"<<ref_DataTypeOctstr>>": "octet_string",
97+
"<<ref_DataTypeVendorId>>": "vendor_id",
98+
"<<ref_DataTypeEndpointNumber>>": "endpoint_no",
99+
}
100+
101+
93102
def ParseType(t: str) -> ParsedType:
94103
"""Parse a data type entry.
95104
96105
Specifically parses a name like "list[Foo Type]".
97106
"""
107+
98108
# very rough matcher ...
99109
is_list = False
100110
if t.startswith("list[") and t.endswith("]"):
101111
is_list = True
102112
t = t[5:-1]
113+
elif t.startswith("<<ref_DataTypeList>>[") and t.endswith("]"):
114+
is_list = True
115+
t = t[21:-1]
103116

104117
if t.endswith(" Type"):
105118
t = t[:-5]
106119

120+
if t in _REF_NAME_MAPPING:
121+
t = _REF_NAME_MAPPING[t]
122+
107123
return ParsedType(name=NormalizeDataType(t), is_list=is_list)
108124

109125

@@ -140,9 +156,20 @@ def NormalizeName(name: str) -> str:
140156
return name
141157

142158

143-
def FieldName(name: str) -> str:
159+
def FieldName(input_name: str) -> str:
144160
"""Normalized name with the first letter lowercase. """
145-
name = NormalizeName(name)
161+
name = NormalizeName(input_name)
162+
163+
# Some exception handling for nicer diffs
164+
if name == "ID":
165+
return "id"
166+
167+
# If the name starts with a all-uppercase thing, keep it that
168+
# way. This is typical for "NOC", "IPK", "CSR" and such
169+
if len(input_name) > 1:
170+
if input_name[0].isupper() and input_name[1].isupper():
171+
return name
172+
146173
return name[0].lower() + name[1:]
147174

148175

scripts/py_matter_idl/matter_idl/test_data_model_xml.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,70 @@ def testAttributes(self):
395395

396396
self.assertIdlEqual(xml_idl, expected_idl)
397397

398+
def testXmlNameWorkarounds(self):
399+
# Validate an attribute with a type list
400+
# This is a manually-edited copy of an attribute test (not real data)
401+
402+
xml_idl = XmlToIdl('''
403+
<cluster id="123" name="Test" revision="1">
404+
<dataTypes>
405+
<struct name="OutputInfoStruct">
406+
<field id="0" name="ID" type="&lt;&lt;ref_DataTypeString&gt;&gt;">
407+
<access read="true" write="true"/>
408+
<mandatoryConform/>
409+
</field>
410+
<field id="1" name="items" type="&lt;&lt;ref_DataTypeList&gt;&gt;[uint8]">
411+
<access read="true" write="true"/>
412+
<mandatoryConform/>
413+
</field>
414+
<field id="2" name="endpoints" type="&lt;&lt;ref_DataTypeList&gt;&gt;[&lt;&lt;ref_DataTypeEndpointNumber&gt;&gt; Type]">
415+
<access read="true" write="true"/>
416+
<mandatoryConform/>
417+
</field>
418+
</struct>
419+
</dataTypes>
420+
<attributes>
421+
<attribute id="0x0000" name="OutputList" type="list[OutputInfoStruct Type]">
422+
<access read="true" readPrivilege="view"/>
423+
<mandatoryConform/>
424+
</attribute>
425+
<attribute id="0x0001" name="TestConform" type="enum8">
426+
<access read="true" readPrivilege="view"/>
427+
<otherwiseConform>
428+
<mandatoryConform>
429+
<feature name="PRSCONST"/>
430+
</mandatoryConform>
431+
<optionalConform>
432+
<feature name="AUTO"/>
433+
</optionalConform>
434+
</otherwiseConform>
435+
</attribute>
436+
</attributes>
437+
</cluster>
438+
''')
439+
440+
expected_idl = IdlTextToIdl('''
441+
client cluster Test = 123 {
442+
struct OutputInfoStruct {
443+
char_string id = 0;
444+
int8u items[] = 1;
445+
endpoint_no endpoints[] = 2;
446+
}
447+
448+
readonly attribute OutputInfoStruct outputList[] = 0;
449+
readonly attribute optional enum8 testConform = 1;
450+
451+
readonly attribute attrib_id attributeList[] = 65531;
452+
readonly attribute event_id eventList[] = 65530;
453+
readonly attribute command_id acceptedCommandList[] = 65529;
454+
readonly attribute command_id generatedCommandList[] = 65528;
455+
readonly attribute bitmap32 featureMap = 65532;
456+
readonly attribute int16u clusterRevision = 65533;
457+
}
458+
''')
459+
460+
self.assertIdlEqual(xml_idl, expected_idl)
461+
398462
def testComplexInput(self):
399463
# This parses a known copy of Switch.xml which happens to be fully
400464
# spec-conformant (so assuming it as a good input)

0 commit comments

Comments
 (0)