diff --git a/docs/source/pages/data-binding/elements.rst b/docs/source/pages/data-binding/elements.rst index 4418bbf..20cf482 100644 --- a/docs/source/pages/data-binding/elements.rst +++ b/docs/source/pages/data-binding/elements.rst @@ -195,9 +195,9 @@ A model supports several element search strategies (modes). Each strategy has it Strict (default) ................ -An element to which a field will be bound is searched sequentially one by one (without skipping unknown elements). +The element to which a field will be bound is searched sequentially one by one (without skipping unknown elements). If the tag of a next element doesn't match the field tag that field is considered unbound. -This mode is used when strong document validation is required. If you parse a very large document it is the best +This mode is used when strong document validation is required. If you parse a large document it is the best choice because it works in predictable time since it doesn't require any look-ahead operations. .. grid:: 2 @@ -237,9 +237,9 @@ choice because it works in predictable time since it doesn't require any look-ah Ordered ....... -An element to which a field will be bound is searched sequentially skipping unknown elements. +The element to which a field will be bound is searched sequentially skipping unknown elements. If the tag of a next element doesn't match the field tag that element is skipped and the search continues. -This mode is used when element order matters but unexpected (or irrelevant) elements could appear in a document. +This mode is used when the elements order matters but unexpected (or irrelevant) elements could appear in a document. .. grid:: 2 :gutter: 2 @@ -276,7 +276,7 @@ This mode is used when element order matters but unexpected (or irrelevant) elem .. code-block:: python - class Model(BaseXmlModel): + class Model(BaseXmlModel, search_mode='ordered'): field1: Optional[str] = element(tag='element1') field2: str = element(tag='element2') field3: str = element(tag='element1') @@ -297,10 +297,11 @@ This mode is used when element order matters but unexpected (or irrelevant) elem Unordered ......... -An element to which a field will be bound is searched in random order. -This mode is used when element order doesn't matter. -The time complexity of this strategy is worst case is -``O(F*E)`` where ``F`` - is the number of fields, ``E`` - the number of sub-elements. +The element to which a field will be bound is searched among all sub-elements in any order. +This mode is used when the elements order doesn't matter. +The time complexity of this strategy in worst case is +``O(F*E)`` where ``F`` - is the number of fields, ``E`` - the number of sub-elements so that it is not suitable +for large documents. .. grid:: 2 :gutter: 2 diff --git a/docs/source/pages/misc.rst b/docs/source/pages/misc.rst index ded7861..0ca3899 100644 --- a/docs/source/pages/misc.rst +++ b/docs/source/pages/misc.rst @@ -1,8 +1,12 @@ .. _misc: +Encoding +~~~~~~~~ + + Custom type encoding -~~~~~~~~~~~~~~~~~~~~ +____________________ ``pydantic-xml`` uses ``pydantic`` default encoder to encode fields data during xml serialization. To alter the default behaviour ``pydantic`` provides a mechanism to `customize `_ @@ -11,7 +15,7 @@ The api is similar to the json one: .. code-block:: python - class Model: + class Model(BaseXmlModel): class Config: xml_encoders = { bytes: base64.b64encode, @@ -40,6 +44,51 @@ The following example illustrate how to encode :py:class:`bytes` typed fields as :language: xml +None type encoding +__________________ + +Since xml format doesn't support ``null`` type natively it is not obvious how to encode ``None`` fields +(ignore it, encode it as an empty string or mark it as ``xsi:nil``) the library doesn't implement +``None`` type encoding by default. + +You can define your own encoding format for the model: + +.. code-block:: python + + from typing import Optional + from pydantic_xml import BaseXmlModel, element + + + class Company(BaseXmlModel): + class Config: + xml_encoders = { + type(None): lambda o: '', # encodes None field as an empty string + } + + title: Optional[str] = element() + + + company = Company() + assert company.to_xml() == b'</Company>' + + +or drop ``None`` fields at all: + +.. code-block:: python + + from typing import Optional + from pydantic_xml import BaseXmlModel, element + + + class Company(BaseXmlModel): + title: Optional[str] = element() + + + company = Company() + assert company.to_xml(skip_empty=True) == b'<Company />' + + + Default namespace ~~~~~~~~~~~~~~~~~ diff --git a/examples/snippets/model_mode_ordered.py b/examples/snippets/model_mode_ordered.py index 3d47399..4c58788 100644 --- a/examples/snippets/model_mode_ordered.py +++ b/examples/snippets/model_mode_ordered.py @@ -2,7 +2,11 @@ # [model-start] -class Company(BaseXmlModel, tag='Company', search_mode='ordered'): +class Company( + BaseXmlModel, + tag='Company', + search_mode='ordered', +): founded: str = element(tag='Founded') website: str = element(tag='WebSite') # [model-end] diff --git a/examples/snippets/model_mode_strict.py b/examples/snippets/model_mode_strict.py index 35dd5e2..c964416 100644 --- a/examples/snippets/model_mode_strict.py +++ b/examples/snippets/model_mode_strict.py @@ -4,7 +4,11 @@ # [model-start] -class Company(BaseXmlModel, tag='Company', search_mode='strict'): +class Company( + BaseXmlModel, + tag='Company', + search_mode='strict', +): founded: str = element(tag='Founded') website: str = element(tag='WebSite') # [model-end] diff --git a/examples/snippets/model_mode_unordered.py b/examples/snippets/model_mode_unordered.py index e737af0..5ac23f8 100644 --- a/examples/snippets/model_mode_unordered.py +++ b/examples/snippets/model_mode_unordered.py @@ -2,7 +2,11 @@ # [model-start] -class Company(BaseXmlModel, tag='Company', search_mode='unordered'): +class Company( + BaseXmlModel, + tag='Company', + search_mode='unordered', +): founded: str = element(tag='Founded') website: str = element(tag='WebSite') # [model-end] diff --git a/pydantic_xml/model.py b/pydantic_xml/model.py index 3512752..d76a025 100644 --- a/pydantic_xml/model.py +++ b/pydantic_xml/model.py @@ -144,7 +144,8 @@ def nsmap(self) -> Optional[NsMap]: def attr(**kwargs: Any) -> Any: """ Marks a pydantic field as an xml attribute. - Method parameters are identical to :py:class:`pydantic_xml.XmlAttributeInfo`. + + :param kwargs: see :py:class:`pydantic_xml.XmlAttributeInfo` """ return XmlAttributeInfo(**kwargs) @@ -153,7 +154,8 @@ def attr(**kwargs: Any) -> Any: def element(**kwargs: Any) -> Any: """ Marks a pydantic field as an xml element. - Method parameters are identical to :py:class:`pydantic_xml.XmlElementInfo`. + + :param kwargs: see :py:class:`pydantic_xml.XmlElementInfo` """ return XmlElementInfo(**kwargs) @@ -162,7 +164,9 @@ def element(**kwargs: Any) -> Any: def wrapped(*args: Any, **kwargs: Any) -> Any: """ Marks a pydantic field as a wrapped xml entity. - Method parameters are identical to :py:class:`pydantic_xml.XmlWrapperInfo`. + + :param args: see :py:class:`pydantic_xml.XmlWrapperInfo` + :param kwargs: see :py:class:`pydantic_xml.XmlWrapperInfo` """ return XmlWrapperInfo(*args, **kwargs)