Skip to content

Commit

Permalink
fix: Allow short closed elements
Browse files Browse the repository at this point in the history
  • Loading branch information
tefra committed Apr 28, 2024
1 parent eab6bb7 commit 2a9eb1c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 13 deletions.
4 changes: 2 additions & 2 deletions tests/formats/dataclass/serializers/tree/test_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_build_with_unknown_event(self, mock_generate):
self.assertEqual("Unhandled event: `foobar`.", str(cm.exception))

def test_encode_data(self):
self.assertEqual("", TreeSerializer.encode_data(None))
self.assertEqual("", TreeSerializer.encode_data([]))
self.assertEqual(None, TreeSerializer.encode_data(None))
self.assertEqual(None, TreeSerializer.encode_data([]))
self.assertEqual("", TreeSerializer.encode_data(""))
self.assertEqual("1 2 3", TreeSerializer.encode_data([1, 2, 3]))
37 changes: 26 additions & 11 deletions xsdata/formats/dataclass/serializers/tree/mixins.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import abc
from dataclasses import dataclass
from typing import Any, Dict, Protocol
from typing import Any, Dict, Optional, Protocol

from xsdata.exceptions import XmlHandlerError
from xsdata.formats.converter import converter
from xsdata.formats.dataclass.serializers.mixins import EventGenerator, XmlWriterEvent
from xsdata.formats.dataclass.serializers.mixins import (
XSI_NIL,
EventGenerator,
XmlWriterEvent,
)
from xsdata.formats.types import T


Expand Down Expand Up @@ -38,29 +42,40 @@ def build(self, obj: T, builder: TreeBuilder):
"""
pending_tag = None
pending_attrs: Dict[str, Any] = {}
flush_events = (XmlWriterEvent.START, XmlWriterEvent.END, XmlWriterEvent.DATA)
for event, *element in self.generate(obj):
if pending_tag is not None and event in flush_events:

def flush_start(is_nil: bool):
nonlocal pending_tag
nonlocal pending_attrs

if pending_tag:
if not is_nil:
pending_attrs.pop(XSI_NIL, None)

builder.start(pending_tag, pending_attrs)
pending_tag = None
pending_attrs = {}

for event, *element in self.generate(obj):
if event == XmlWriterEvent.START:
flush_start(False)
pending_tag = element[0]
pending_attrs = {}
elif event == XmlWriterEvent.ATTR:
key, value = element
pending_attrs[key] = self.encode_data(value)
elif event == XmlWriterEvent.END:
flush_start(False)
builder.end(*element)
elif event == XmlWriterEvent.DATA:
data = self.encode_data(element[0])
builder.data(data)
flush_start(is_nil=data is None)
if data:
builder.data(data)
else:
raise XmlHandlerError(f"Unhandled event: `{event}`.")

@classmethod
def encode_data(cls, data: Any) -> str:
def encode_data(cls, data: Any) -> Optional[str]:
"""Encode data for xml rendering.
Args:
Expand All @@ -69,10 +84,10 @@ def encode_data(cls, data: Any) -> str:
Returns:
The xml encoded data
"""
if data is None or isinstance(data, list) and not data:
return ""

if isinstance(data, str):
if data is None or isinstance(data, str):
return data

if isinstance(data, list) and not data:
return None

return converter.serialize(data)

0 comments on commit 2a9eb1c

Please sign in to comment.