JSON Binding¶
Binding JSON lacks a bit in features and for edge cases with wildcards and derived types doing roundtrip conversions is not always possible.
Parsing JSON¶
From filename¶
>>> from pathlib import Path
>>> from xsdata.formats.dataclass.context import XmlContext
>>> from xsdata.formats.dataclass.parsers import JsonParser
>>> from tests import fixtures_dir # pathlib.Path
>>> from tests.fixtures.defxmlschema.chapter05 import Order
...
>>> filename = str(fixtures_dir.joinpath("defxmlschema/chapter05.json"))
>>> parser = JsonParser(context=XmlContext())
>>> order = parser.parse(filename, Order)
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
From file object¶
>>> json_path = fixtures_dir.joinpath("defxmlschema/chapter05.json")
>>> with json_path.open("rb") as fp:
... order = parser.parse(fp, Order)
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
From stream¶
>>> import io
>>> order = parser.parse(io.BytesIO(json_path.read_bytes()), Order)
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
From String¶
>>> order = parser.from_string(json_path.read_text(), Order)
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
From Bytes¶
>>> order = parser.from_bytes(json_path.read_bytes(), Order)
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
From path¶
>>> order = parser.from_path(json_path, Order)
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
Unknown target type¶
It’s optimal to provide the target model but completely optional. The parser can scan all the imported modules to find a matching dataclass.
>>> order = parser.from_bytes(json_path.read_bytes())
>>> order.items.product[0]
Product(number=557, name='Short-Sleeved Linen Blouse', size=SizeType(value=None, system=None))
Custom json load factory¶
The default factory is python’s builtin json.load()
but you can use any
other implementation as long as it’s has a compatible signature.
import ujson
parser = JsonParser(load_factory=ujson.load)
Serializing JSON¶
Render to string¶
>>> from xsdata.formats.dataclass.context import XmlContext
>>> from xsdata.formats.dataclass.serializers import JsonSerializer
>>> from tests.fixtures.defxmlschema.chapter05 import Order, ItemsType
>>> from tests.fixtures.defxmlschema.chapter05prod import Product, SizeType
>>> order = Order(
... items=ItemsType(
... product=[
... Product(
... number=557,
... name='Short-Sleeved Linen Blouse',
... size=SizeType(value=None, system=None)
... )
... ]
... )
... )
>>> serializer = JsonSerializer(context=XmlContext(), indent=2)
>>> print(serializer.render(order))
{
"items": {
"product": [
{
"number": 557,
"name": "Short-Sleeved Linen Blouse",
"size": {
"value": null,
"system": null
}
}
]
}
}
Write to stream¶
>>> from pathlib import Path
...
>>> path = Path("output.json")
>>> with path.open("w") as fp:
... serializer.write(fp, order)
...
>>> print(path.read_text())
{
"items": {
"product": [
{
"number": 557,
"name": "Short-Sleeved Linen Blouse",
"size": {
"value": null,
"system": null
}
}
]
}
}
>>> path.unlink()
Custom Dict factory¶
By using a custom dict factory you can change the output behaviour, like filter out
None
values.
>>> from typing import Dict, Tuple
>>>
>>> def filter_none(x: Tuple) -> Dict:
... return {k: v for k, v in x if v is not None}
>>>
>>> order.items.product[0].size = None
>>> serializer = JsonSerializer(dict_factory=filter_none, indent=2)
>>> print(serializer.render(order))
{
"items": {
"product": [
{
"number": 557,
"name": "Short-Sleeved Linen Blouse"
}
]
}
}
or conveniently
>>> from xsdata.formats.dataclass.serializers.json import DictFactory
>>>
>>> serializer = JsonSerializer(dict_factory=DictFactory.FILTER_NONE)
>>> print(serializer.render(order))
{"items": {"product": [{"number": 557, "name": "Short-Sleeved Linen Blouse"}]}}
Custom json dump factory¶
The default factory is python’s builtin json.dump()
but you can use any
other implementation as long as it’s has a compatible signature.
import ujson
serializer = JsonSerializer(dump_factory=ujson.dump, indent=0)