Coverage for sbe2/xmlparser/attributes.py: 99%
133 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-29 14:12 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-29 14:12 +0200
1from lxml.etree import Element
2from .errors import SchemaParsingError
3from ..schema import Presence, ByteOrder, PrimitiveType, Composite, Type
4from .ctx import ParsingContext
7def parse_name(element: Element) -> str:
8 """
9 Parses the 'name' attribute from an XML element.
11 Args:
12 element (Element): The XML element to parse.
14 Returns:
15 str: The value of the 'name' attribute.
16 """
17 name = element.get("name", "")
18 if not name:
19 raise SchemaParsingError(f"Element {element.tag}is missing 'name' attribute")
20 return name
23def parse_description(element: Element) -> str:
24 """
25 Parses the 'description' attribute from an XML element.
27 Args:
28 element (Element): The XML element to parse.
30 Returns:
31 str: The value of the 'description' attribute, or an empty string if not present.
32 """
33 return element.get("description", "").strip()
36def parse_since_version(element: Element) -> int:
37 """
38 Parses the 'sinceVersion' attribute from an XML element.
40 Args:
41 element (Element): The XML element to parse.
43 Returns:
44 int: The value of the 'sinceVersion' attribute, or 0 if not present.
45 """
46 # TODO: must not be greater than schema version
47 return int(element.get("sinceVersion", "0"))
50def parse_deprecated(element: Element) -> int | None:
51 """
52 Parses the 'deprecated' attribute from an XML element.
54 Args:
55 element (Element): The XML element to parse.
57 Returns:
58 int | None: The value of the 'deprecated' attribute, or None if not present.
59 """
60 #TODO: must not be greater than schema version
61 #TODO: must be greater than sinceVersion
62 deprecated = element.get("deprecated")
63 try:
64 return int(deprecated) if deprecated else None
65 except (ValueError, TypeError) as e:
66 raise SchemaParsingError(
67 f"Invalid deprecated value '{deprecated}' in element {element.tag}"
68 ) from e
71def parse_offset(element: Element) -> int | None:
72 """
73 Parses the 'offset' attribute from an XML element.
75 Args:
76 element (Element): The XML element to parse.
78 Returns:
79 int | None: The value of the 'offset' attribute, or None if not present.
80 """
81 offset = element.get("offset")
82 try:
83 return int(offset) if offset else None
84 except (ValueError, TypeError) as e:
85 raise SchemaParsingError(
86 f"Invalid offset value '{offset}' in element {element.tag}"
87 ) from e
90def parse_presence(element: Element) -> Presence | None:
91 """
92 Parses the 'presence' attribute from an XML element.
94 Args:
95 element (Element): The XML element to parse.
97 Returns:
98 Presence: The presence value, defaulting to 'required' if not specified.
99 """
100 presence_str = element.get("presence")
101 if not presence_str:
102 return None
103 try:
104 return Presence(presence_str)
105 except ValueError as e:
106 raise SchemaParsingError(
107 f"Invalid presence value '{presence_str}' in element {element.tag}"
108 ) from e
111def parse_id(element: Element) -> int:
112 """
113 Parses the 'id' attribute from an XML element.
115 Args:
116 element (Element): The XML element to parse.
118 Returns:
119 int: The value of the 'id' attribute
120 """
121 id_str = element.get("id")
122 try:
123 return int(id_str)
124 except (ValueError, TypeError) as e:
125 raise SchemaParsingError(
126 f"Invalid id value '{id_str}' in element {element.tag}"
127 ) from e
130def parse_semantic_type(element: Element) -> str:
131 """
132 Parses the 'semanticType' attribute from an XML element.
134 Args:
135 element (Element): The XML element to parse.
137 Returns:
138 str: The value of the 'semanticType' attribute, or an empty string if not present.
139 """
140 return element.get("semanticType", "")
143def parse_alignment(element: Element) -> int | None:
144 """
145 Parses the 'alignment' attribute from an XML element.
147 Args:
148 element (Element): The XML element to parse.
150 Returns:
151 int | None: The value of the 'alignment' attribute, or None if not present.
152 """
153 alignment = element.get("alignment")
154 try:
155 return int(alignment) if alignment else None
156 except (ValueError, TypeError) as e:
157 raise SchemaParsingError(
158 f"Invalid alignment value '{alignment}' in element {element.tag}"
159 ) from e
162def parse_block_length(element: Element) -> int | None:
163 """
164 Parses the 'blockLength' attribute from an XML element.
166 Args:
167 element (Element): The XML element to parse.
169 Returns:
170 int | None: The value of the 'blockLength' attribute, or None if not present.
171 """
172 block_length = element.get("blockLength")
173 try:
174 return int(block_length) if block_length else None
175 except (ValueError, TypeError) as e:
176 raise SchemaParsingError(
177 f"Invalid blockLength value '{block_length}' in element {element.tag}"
178 ) from e
180def parse_encoding_type(element: Element) -> Type:
181 """
182 Parses the 'encodingType' attribute from an XML element.
184 Args:
185 element (Element): The XML element to parse.
187 Returns:
188 Type: The type associated with the 'encodingType' attribute
189 """
190 encoding_type = element.get("encodingType", '')
191 if not encoding_type:
192 raise SchemaParsingError(
193 f"Element {element.tag} is missing 'encodingType' attribute"
194 )
195 return encoding_type
198def parse_min_value(element: Element) -> int | None:
199 """
200 Parses the 'minValue' attribute from an XML element.
202 Args:
203 element (Element): The XML element to parse.
205 Returns:
206 int | None: The value of the 'minValue' attribute, or None if not present.
207 """
208 min_value = element.get("minValue")
209 try:
210 return int(min_value) if min_value else None
211 except (ValueError, TypeError) as e:
212 raise SchemaParsingError(
213 f"Invalid minValue '{min_value}' in element {element.tag}"
214 ) from e
216def parse_max_value(element: Element) -> int | None:
217 """
218 Parses the 'maxValue' attribute from an XML element.
220 Args:
221 element (Element): The XML element to parse.
223 Returns:
224 int | None: The value of the 'maxValue' attribute, or None if not present.
225 """
226 max_value = element.get("maxValue")
227 try:
228 return int(max_value) if max_value else None
229 except (ValueError, TypeError) as e:
230 raise SchemaParsingError(
231 f"Invalid maxValue '{max_value}' in element {element.tag}"
232 ) from e
235def parse_null_value(element: Element) -> int | None:
236 """
237 Parses the 'nullValue' attribute from an XML element.
239 Args:
240 element (Element): The XML element to parse.
242 Returns:
243 int | None: The value of the 'nullValue' attribute, or None if not present.
244 """
245 null_value = element.get("nullValue")
246 try:
247 return int(null_value) if null_value else None
248 except (ValueError, TypeError) as e:
249 raise SchemaParsingError(
250 f"Invalid nullValue '{null_value}' in element {element.tag}"
251 ) from e
253def parse_character_encoding(element: Element) -> str | None:
254 """
255 Parses the 'characterEncoding' attribute from an XML element.
257 Args:
258 element (Element): The XML element to parse.
260 Returns:
261 str: The value of the 'characterEncoding' attribute, or None if not present.
262 """
263 character_encoding = element.get("characterEncoding", "")
264 return character_encoding if character_encoding else None
267def parse_primitive_type(element: Element) -> PrimitiveType:
268 """
269 Parses the 'primitiveType' attribute from an XML element.
271 Args:
272 element (Element): The XML element to parse.
274 Returns:
275 str: The value of the 'primitiveType' attribute.
276 """
277 primitive_type = element.get("primitiveType", "")
278 if not primitive_type:
279 raise SchemaParsingError(
280 f"Element {element.tag} is missing 'primitiveType' attribute"
281 )
283 pt = PrimitiveType.by_name.get(primitive_type)
284 if pt is None:
285 raise SchemaParsingError(
286 f"Unknown primitive type '{primitive_type}' in element {element.tag}"
287 )
288 return pt
291def parse_value_ref(element: Element) -> str | None:
292 """
293 Parses the 'valueRef' attribute from an XML element.
295 Args:
296 element (Element): The XML element to parse.
298 Returns:
299 str | None: The value of the 'valueRef' attribute, or None if not present.
300 """
301 vr = element.get("valueRef", "")
302 return vr if vr else None
305def parse_type(element:Element) -> str:
306 """
307 Parses the 'type' attribute from an XML element.
309 Args:
310 element (Element): The XML element to parse.
312 Returns:
313 str: The value of the 'type' attribute.
314 """
315 type_value = element.get("type", "")
316 if not type_value:
317 raise SchemaParsingError(
318 f"Element {element.tag} is missing 'type' attribute"
319 )
320 return type_value
323def parse_length(element: Element) -> int:
324 """
325 Parses the 'length' attribute from an XML element.
327 Args:
328 element (Element): The XML element to parse.
330 Returns:
331 int: The value of the 'length' attribute.
332 """
333 length_str = element.get("length", "1")
334 try:
335 return int(length_str)
336 except (ValueError, TypeError) as e:
337 raise SchemaParsingError(
338 f"Invalid length value '{length_str}' in element {element.tag}"
339 ) from e
341def parse_byte_order(element: Element) -> ByteOrder:
342 """
343 Parses the 'byteOrder' attribute from an XML element.
345 Args:
346 element (Element): The XML element to parse.
348 Returns:
349 ByteOrder: The byte order value, defaulting to 'littleEndian' if not specified.
350 """
351 byte_order_str = element.get("byteOrder", "littleEndian")
352 try:
353 return ByteOrder(byte_order_str)
354 except ValueError as e:
355 raise SchemaParsingError(
356 f"Invalid byte order '{byte_order_str}' in element {element.tag}"
357 ) from e
359def parse_version(element: Element) -> int:
360 """
361 Parses the 'version' attribute from an XML element.
363 Args:
364 element (Element): The XML element to parse.
366 Returns:
367 int: The value of the 'version' attribute.
368 """
369 version_str = element.get("version")
370 try:
371 return int(version_str)
372 except (ValueError, TypeError) as e:
373 raise SchemaParsingError(
374 f"Invalid version value '{version_str}' in element {element.tag}"
375 ) from e
378def parse_header_type(element: Element) -> str:
379 """
380 Parses the 'headerType' attribute from an XML element.
382 Args:
383 element (Element): The XML element to parse.
385 Returns:
386 str: The value of the 'headerType' attribute.
387 """
388 header_type = element.get("headerType", "messageHeader")
389 if not header_type:
390 raise SchemaParsingError(
391 f"Element {element.tag} is missing 'headerType' attribute"
392 )
393 return header_type
395def parse_package(element: Element, required: bool = True) -> str | None:
396 """
397 Parses the 'package' attribute from an XML element.
399 Args:
400 element (Element): The XML element to parse.
401 required (bool): If set raises an exception on empty value.
403 Returns:
404 str | None: The value of the 'package' attribute.
405 """
406 package = element.get("package", "")
407 if not package and required:
408 raise SchemaParsingError(
409 f"Element {element.tag} is missing 'package' attribute"
410 )
411 return package or None
414def parse_semantic_version(element: Element) -> str:
415 """
416 Parses the 'semanticVersion' attribute from an XML element.
418 Args:
419 element (Element): The XML element to parse.
421 Returns:
422 str: The value of the 'semanticVersion' attribute.
423 """
424 return element.get("semanticVersion", "")
425 # TODO: Validate semantic version format if necessary
426 # TODO: is empty string valid?
429def parse_dimension_type(node, ctx: ParsingContext) -> Composite:
430 """
431 Parses the 'dimensionType' attribute from an XML element.
433 Args:
434 node (Element): The XML element to parse.
435 ctx (ParsingContext): The context of parsing.
437 Returns:
438 str: The value of the 'dimensionType' attribute.
439 """
440 dimension_type = node.get("dimensionType", "groupSizeEncoding")
441 if not dimension_type:
442 raise SchemaParsingError(
443 f"Element {node.tag} is missing 'dimensionType' attribute"
444 )
445 # TODO: validate that the composite meets requirements for a dimension type
446 try:
447 return ctx.types.get_composite(dimension_type)
448 except Exception as e:
449 raise SchemaParsingError(
450 f"Unknown or invalid dimension type '{dimension_type}' in element {node.tag}"
451 ) from e