madpah / madpah/serializable

XML serialize helpers should also support iterables of elements

Open
#170 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
7
Forks
6
PR merge metrics
No merged PRs in 30d

Description

py-serializable version: 2.0.0
python version: 3.13.3
os: linux

## What is the problem?
I try to implement the missing identity element of [componentEvidenceType](https://cyclonedx.org/docs/1.6/xml/#type_componentEvidenceType) into [cyclonedx-python-lib](https://github.com/CycloneDX/cyclonedx-python-lib). Since version 1.6 of the schema the identity has `maxOccurs="unbounded"` that means something like this is possible in 1.6:

~~~xml


purl


name

~~~

I am developing now a helper with a custom `xml_normalize` function. The problem I have now is that only:

- None
- a single Element
- a string which is used as value

are supported:

https://github.com/madpah/serializable/blob/bb035d25f6efabb959c1250af10d49c8c19d0ff1/py_serializable/__init__.py#L508-L515

## How to improve this?
It would be great to support also `List[Element]`. Maybe something like that:

~~~python
elif isinstance(ver_ser, List):
for element in ver_ser:
this_e.append(element)
~~~

With this simple approach something like this is possible:

~~~python
988 @classmethod
989 def xml_normalize(
990 cls, o: SortedSet[Identity], *,
991 element_name: str,
992 view: Optional[type['ViewType']],
993 xmlns: Optional[str],
994 **__: Any
~ 995 ) -> Optional[list[Element]]:
~ 996 if view is not None:
+ 997 schema_version: BaseSchemaVersion = cast(BaseSchemaVersion, view())
+ 998 if schema_version.schema_version_enum < SchemaVersion.V1_6 and len(o) > 1:
+ 999 raise SerializationOfUnexpectedValueException(
+ 1000 "The schema version 1.5 only supports a single identity object"
+ 1001 )
+ 1002 else:
+ 1003 return [
E 1004 identity.as_xml(
+ 1005 view_=view,
+ 1006 as_string=False,
+ 1007 element_name=element_name,
+ 1008 xmlns=xmlns,
+ 1009 )
+ 1010 for identity in o
+ 1011 ]
+ 1012 return None
~~~

~~~python
>>> from cyclonedx.schema.schema import SchemaVersion1Dot4, SchemaVersion1Dot5, SchemaVersion1Dot6
>>> from cyclonedx.model.component import ComponentEvidence, Identity, IdentityField
>>> foo = ComponentEvidence(identity=Identity(field=IdentityField.PURL))
>>> foo.as_xml(view_=SchemaVersion1Dot6)
'purl'
>>> foo.as_xml(view_=SchemaVersion1Dot5)
'purl'
>>> bar = ComponentEvidence(identity=[Identity(field=IdentityField.PURL), Identity(field=IdentityField.NAME)])
>>> bar.as_xml(view_=SchemaVersion1Dot6)
'namepurl'
>>> bar.as_xml(view_=SchemaVersion1Dot5)
Traceback (most recent call last):
File "", line 1, in
bar.as_xml(view_=SchemaVersion1Dot5)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jloehel/projects/github.com/jloehel/cyclonedx-python-lib/.venv/lib64/python3.13/site-packages/py_serializable/__init__.py", line 508, in as_xml
v_ser = prop_info.custom_type.xml_normalize(
v, view=view_, element_name=new_key, xmlns=xmlns, prop_info=prop_info, ctx=self.__class__)
File "/home/jloehel/projects/github.com/jloehel/cyclonedx-python-lib/cyclonedx/model/component.py", line 999, in xml_normalize
raise SerializationOfUnexpectedValueException(
"The schema version 1.5 only supports a single identity object"
)
cyclonedx.exception.serialization.SerializationOfUnexpectedValueException: The schema version 1.5 only supports a single identity object
~~~

edit: Maybe it's better to consider the helper for prop_info.is_array because
~~~python
@serializable.xml_array(serializable.XmlArraySerializationType.FLAT, child_name='identity')
~~~
is doing the right thing. I just wanna raise an exception in a special case.

Contributor guide

Open the contributing guide

Research direction

Start with py_serializable/__init__.py around the as_xml logic at lines 508-515, then inspect the xml_array decorator behavior mentioned in the issue. Reproduce serialization with a single Element and a list or other iterable, and verify that supported iterable values produce flat child elements while the existing scalar behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.