tefra / xsdata

Naive XML & JSON Bindings for python
https://xsdata.readthedocs.io
MIT License
334 stars 61 forks source link

Render snake_case -> kebab-case #381

Closed Przemek625 closed 3 years ago

Przemek625 commented 3 years ago

Is it posible to easily set global rendering option that would change all field names from snake_case to kebab-case in generated xml? Now it required to set it manually with code like this:

from dataclasses import dataclass, field
@dataclass
class ContactPerson:
    given_names: str = field(metadata=dict(name="given-names"))

I dont see in method XmlSerializer.render any option that would allow me to achieve this goal.

It is very inconvenient at the moment when I have like 100 other fields of this kind...

tefra commented 3 years ago

It's not really documented because it was added in a hurry for something I needed but it's there.

The parser/serializer depend on XmlContext to provide binding information about the models. The XmlContext has an entry point to set a custom callable for element and attribute names if an implicit one is missing.

import sys
from dataclasses import dataclass, field
from datetime import date

from xsdata.formats.dataclass.context import XmlContext
from xsdata.formats.dataclass.parsers import XmlParser
from xsdata.formats.dataclass.serializers import XmlSerializer
from xsdata.formats.dataclass.serializers.config import SerializerConfig
from xsdata.utils.text import split_words, camel_case

def kebab_case(name: str) -> str:
    return "-".join(split_words(name))

@dataclass
class ContactPerson:
    first_name: str  # element
    last_name: str  # element
    birth_date: date = field(
        metadata=dict(
            type="Attribute",
            format="%Y-%m-%d"
        )
    )
    user_name: str = field(metadata=dict(name="avatar"))  # implicit field name

obj = ContactPerson(
    first_name="Chris",
    last_name="Tsoulloftas",
    birth_date=date(1986, 9, 25),
    user_name="Tefra",
)

# The context must now be passed to the xml parser/serializer
context = XmlContext(
    element_name=kebab_case,
    attribute_name=camel_case
)

config = SerializerConfig(pretty_print=True)
serializer = XmlSerializer(context=context, config=config)
parser = XmlParser(context=context)
serializer.write(sys.stdout, obj)
<Contact-Person birthDate="1986-09-25">
  <first-name>Chris</first-name>
  <last-name>Tsoulloftas</last-name>
  <avatar>Tefra</avatar>
</Contact-Person>
Przemek625 commented 3 years ago

@tefra thank you very much!

tefra commented 3 years ago

@Przemek625

The params to the XmlContext class will be renamed in the next version

context = XmlContext(
    element_name_generator=kebab_case,
    attribute_name_generator=camel_case
)

I also added those properties per model

https://xsdata.readthedocs.io/en/latest/models.html#customize-element-and-attribute-names