JSON Binding

All binding modules rely on a XmlContext instance to cache marshalling information.

It’s recommended to either reuse the same parser/serializer instance or reuse the context instance.

from xsdata.formats.dataclass.context import XmlContext
from xsdata.formats.dataclass.parsers import JsonParser
from xsdata.formats.dataclass.serializers import JsonSerializer

context = XmlContext()
parser = JsonParser(context=context)
serializer = JsonSerializer(context=context)

Parsing JSON

From json filename

>>> from pathlib import Path
>>> from xsdata.formats.dataclass.context import XmlContext
>>> from xsdata.formats.dataclass.parsers import JsonParser
>>> from tests.fixtures.books.books import Books
>>> from tests import fixtures_dir # pathlib.Path
...
>>> filename = str(fixtures_dir.joinpath("books/books.json"))
>>> parser = JsonParser(context=XmlContext())
>>> books = parser.parse(filename, Books)
>>> books.book[0]
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

From json file object

>>> json_path = fixtures_dir.joinpath("books/books.json")
>>> with json_path.open("rb") as fp:
...     order = parser.parse(fp, Books)
>>> books.book[0]
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

From json stream

>>> import io
>>> order = parser.parse(io.BytesIO(json_path.read_bytes()), Books)
>>> books.book[0]
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

From json string

>>> order = parser.from_string(json_path.read_text(), Books)
>>> books.book[0]
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

From json bytes

>>> order = parser.from_bytes(json_path.read_bytes(), Books)
>>> books.book[0]
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

From json path

>>> order = parser.from_path(json_path, Books)
>>> books.book[0]
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

Ignore unknown properties

>>> from tests.fixtures.books import *  # Import all classes
>>> from xsdata.formats.dataclass.parsers.config import ParserConfig
...
>>> config = ParserConfig(
...     fail_on_unknown_properties=False,
... )
>>> json_string = """{
...   "author": "Hightower, Kim",
...   "unknown_property": "I will fail"
... }"""
>>> parser = JsonParser(config=config)
>>> parser.from_string(json_string, BookForm)
BookForm(author='Hightower, Kim', title=None, genre=None, price=None, pub_date=None, review=None, id=None, lang='en')

API Reference.

Unknown json 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.

>>> from tests.fixtures.books import *  # Import all classes
>>> json_string = """{
...   "author": "Hightower, Kim",
...   "title": "The First Book",
...   "genre": "Fiction",
...   "price": 44.95,
...   "pub_date": "2000-10-01",
...   "review": "An amazing story of nothing.",
...   "id": "bk001"
... }"""
>>> parser = JsonParser()
>>> parser.from_string(json_string)
BookForm(author='Hightower, Kim', title='The First Book', genre='Fiction', price=44.95, pub_date=XmlDate(2000, 10, 1), review='An amazing story of nothing.', id='bk001', lang='en')

Warning

The class locator searches for a dataclass that includes all the input object properties. This process doesn’t work for documents with unknown properties even if the configuration option is disabled!

List of Objects

Specify the target binding type to List[ModelName]

>>> from typing import List
>>>
>>> json_string = """[
...     {
...       "author": "Hightower, Kim",
...       "title": "The First Book",
...       "genre": "Fiction",
...       "price": 44.95,
...       "pub_date": "2000-10-01",
...       "review": "An amazing story of nothing.",
...       "id": "bk001"
...     },
...     {
...       "author": "Nagata, Suanne",
...       "title": "Becoming Somebody",
...       "genre": "Biography",
...       "price": null,
...       "pub_date": null,
...       "review": "A masterpiece of the fine art of gossiping.",
...       "id": "bk002"
...     }
...   ]"""
>>> parser = JsonParser()
>>> books = parser.from_string(json_string, List[BookForm])
>>> books[1].author
'Nagata, Suanne'

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 json string

>>> from xsdata.formats.dataclass.context import XmlContext
>>> from xsdata.formats.dataclass.serializers import JsonSerializer
>>> from xsdata.models.datatype import XmlDate
>>> books = Books(
...    book=[
...        BookForm(
...            id="bk001",
...            author="Hightower, Kim",
...            title="The First Book",
...            genre="Fiction",
...            price=44.95,
...            review="An amazing story of nothing.",
...        ),
...        BookForm(
...            id="bk002",
...            author="Nagata, Suanne",
...            title="Becoming Somebody",
...            price=33.95,
...            pub_date=XmlDate(2001, 1, 10),
...            review="A masterpiece of the fine art of gossiping.",
...        ),
...    ]
... )
>>> serializer = JsonSerializer(context=XmlContext(), indent=2)
>>> print(serializer.render(books))
{
  "book": [
    {
      "author": "Hightower, Kim",
      "title": "The First Book",
      "genre": "Fiction",
      "price": 44.95,
      "pub_date": null,
      "review": "An amazing story of nothing.",
      "id": "bk001",
      "lang": "en"
    },
    {
      "author": "Nagata, Suanne",
      "title": "Becoming Somebody",
      "genre": null,
      "price": 33.95,
      "pub_date": "2001-01-10",
      "review": "A masterpiece of the fine art of gossiping.",
      "id": "bk002",
      "lang": "en"
    }
  ]
}

Write to json stream

>>> from pathlib import Path
...
>>> path = Path("output.json")
>>> with path.open("w") as fp:
...     serializer.write(fp, order)
...
>>> print(path.read_text())
{
  "book": [
    {
      "author": "Hightower, Kim",
      "title": "The First Book",
      "genre": "Fiction",
      "price": 44.95,
      "pub_date": "2000-10-01",
      "review": "An amazing story of nothing.",
      "id": "bk001",
      "lang": "en"
    },
    {
      "author": "Nagata, Suanne",
      "title": "Becoming Somebody",
      "genre": "Biography",
      "price": null,
      "pub_date": null,
      "review": "A masterpiece of the fine art of gossiping.",
      "id": "bk002",
      "lang": "en"
    }
  ]
}
>>> 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}
>>>
>>> books.book[0].genre = None
>>> serializer = JsonSerializer(dict_factory=filter_none, indent=2)
>>> print(serializer.render(books.book[0]))
{
  "author": "Hightower, Kim",
  "title": "The First Book",
  "price": 44.95,
  "review": "An amazing story of nothing.",
  "id": "bk001",
  "lang": "en"
}

or conveniently

>>> from xsdata.formats.dataclass.serializers.json import DictFactory
>>>
>>> serializer = JsonSerializer(dict_factory=DictFactory.FILTER_NONE)
>>> print(serializer.render(books.book[1]))
{"author": "Nagata, Suanne", "title": "Becoming Somebody", "price": 33.95, "pub_date": "2001-01-10", "review": "A masterpiece of the fine art of gossiping.", "id": "bk002", "lang": "en"}

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)