### Install pydantic-xml using pip Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/installation.md Use this command to install the base pydantic-xml library. ```bash pip install pydantic-xml ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/contribute.md Run this command to install all development dependencies for the project, excluding the root package itself. ```console $ poetry install --no-root ``` -------------------------------- ### Install Documentation Dependencies Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/contribute.md Install the necessary dependencies to build the project's documentation. The '-E docs' flag enables the 'docs' extra. ```console $ poetry install -E docs ``` -------------------------------- ### Install Pre-commit Hooks Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/contribute.md Install pre-commit hooks to automatically check code style before each commit. This ensures adherence to project coding conventions. ```console $ pre-commit install ``` -------------------------------- ### Example XML Document Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md This XML document serves as the expected output for the `Request` model with computed fields. ```xml 150.172.238.178 150.172.230.21 ********** ``` -------------------------------- ### Example HTML Document with DTD Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md An example of an HTML document generated with a Document Type Declaration, showcasing the structure and content. ```xml This is a title Hello world! ``` -------------------------------- ### Install pydantic-xml with lxml support Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/installation.md Install pydantic-xml with the optional lxml dependency for enhanced XML serialization. This is recommended if you need to use lxml as your XML backend. ```bash pip install pydantic-xml[lxml] ``` -------------------------------- ### Build Documentation Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/contribute.md Navigate to the docs directory and run 'make html' to build the HTML version of the documentation. Ensure documentation dependencies are installed first. ```console cd docs make html ``` -------------------------------- ### XML Representation of Model Unions Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/unions.md Example XML structure showing a log containing different types of events (mouse and keyboard). ```xml CTRL C ``` -------------------------------- ### Input XML for Raw Fields Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/raw.md Example XML demonstrating different ways raw contact elements can be structured, including attributes, nested links, and direct text content. ```xml https://twitter.com/spacex https://www.youtube.com/spacex ``` -------------------------------- ### Ordered Search Mode Example Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Employ 'ordered' mode when element order is important, but unexpected elements may appear. This mode skips unknown elements during the sequential search. ```python class Company( BaseXmlModel, tag='Company', search_mode='ordered', ): founded: str = element(tag='Founded') website: str = element(tag='WebSite') ``` -------------------------------- ### XML for Sub-element Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/mappings.md Example XML where a Company element contains a 'Founder' sub-element with 'name' and 'surname' attributes. ```xml ``` -------------------------------- ### Ordered Search Mode Warning Example Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Demonstrates a potential pitfall with 'ordered' search mode where duplicate tags can lead to unexpected binding results due to look-ahead behavior. ```python class Model(BaseXmlModel, search_mode='ordered'): field1: Optional[str] = element(tag='element1') field2: str = element(tag='element2') field3: str = element(tag='element1') ``` ```xml value value ``` -------------------------------- ### Unordered Search Mode Example Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Utilize 'unordered' mode when the order of elements does not matter. This mode searches for fields among all sub-elements regardless of their position. ```python class Company( BaseXmlModel, tag='Company', search_mode='unordered', ): founded: str = element(tag='Founded') website: str = element(tag='WebSite') ``` -------------------------------- ### XML for TypedDict Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/mappings.md Example XML where a Company element has attributes like 'founded', 'employees', and 'website' directly bound from a TypedDict. ```xml ``` -------------------------------- ### XML Representation of Discriminated Union Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/unions.md Example XML showing a 'hardware' element containing a 'device' with a 'type' attribute that discriminates between CPU and GPU. ```xml 4096 ``` -------------------------------- ### Example XML Document Structure Source: https://github.com/dapper91/pydantic-xml/blob/master/README.rst This XML structure corresponds to the `Company` model defined above, demonstrating how attributes and nested elements are represented. ```xml https://www.spacex.com Several launch vehicles Starlink Starship ``` -------------------------------- ### XML Representation of Primitive Unions Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/unions.md Example XML structure demonstrating how messages with float or datetime timestamps are represented. ```xml hello world ``` -------------------------------- ### JSON Representation of Model Unions Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/unions.md Example JSON structure corresponding to the XML log with mixed event types. ```json { "events": [ { "timestamp": 1674999183.5486422, "position": {"x": 234, "y": 345} }, { "timestamp": 1674999184.227246, "type": "KEYDOWN", "key": "CTRL" }, { "timestamp": 1674999185.6342669, "type": "KEYDOWN", "key": "C" }, { "timestamp": 1674999186.270716, "position": {"x": 236, "y": 211} } ] } ``` -------------------------------- ### XML for Local Element Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/mappings.md Example XML structure where a Company element has 'trade-name' and 'type' as local attributes. ```xml ``` -------------------------------- ### XML Document Example Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/quickstart.md This XML document demonstrates various pydantic-xml features including attributes, elements, nested structures, namespaces, and wrapped fields. ```xml 2002-03-14 12000 https://www.spacex.com space communications US California Hawthorne https://www.linkedin.com/company/spacex https://twitter.com/spacex https://www.youtube.com/spacex Several launch vehicles Starlink Starship ``` -------------------------------- ### Example XML Structure for Company and Products Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/index.md This XML snippet illustrates the structure of a 'Company' document, including its 'trade-name' attribute, 'website' element, and a list of 'product' elements, each with its own attributes and text content. This structure corresponds to the pydantic models defined previously. ```xml https://www.spacex.com Several launch vehicles Starlink Starship ``` -------------------------------- ### Strict Search Mode Example Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Use 'strict' mode for precise document validation where element order and presence are critical. This mode is efficient for large documents as it avoids look-ahead operations. ```python class Company( BaseXmlModel, tag='Company', search_mode='strict', ): founded: str = element(tag='Founded') website: str = element(tag='WebSite') ``` -------------------------------- ### JSON Example of Homogeneous Data Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/homogeneous.md This JSON structure represents a list of launch vehicles, where each inner list contains an object with vehicle details and a year. It demonstrates a common pattern for homogeneous data representation. ```json [ [ { "title": "Several launch vehicles", "status": "running" }, 2013 ], [ { "title": "Starlink", "status": "running" }, 2019 ], [ { "title": "Starship", "status": "development" }, null ] ] ``` -------------------------------- ### JSON Representation of Primitive Unions Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/unions.md Example JSON structure corresponding to the XML representation of messages with union types. ```json { "messages": [ { "timestamp": 1674995230.295639, "text": "hello world" }, { "timestamp": "2023-01-29T17:30:38.762166" } ] } ``` -------------------------------- ### JSON Representation of Discriminated Union Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/unions.md Example JSON corresponding to the XML discriminated union, showing the resolved sub-model type and its fields. ```json { "accelerator": { "type": "GPU", "cores": 4096, "cuda": false } } ``` -------------------------------- ### Custom None Encoding with PlainSerializer Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Define a custom encoding for `None` values in XML using `PlainSerializer` and `BeforeValidator`. This example encodes `None` as the string 'null' and decodes 'null' back to `None`. ```python from typing import Annotated, Optional, TypeVar from xml.etree.ElementTree import canonicalize from pydantic import BeforeValidator, PlainSerializer from pydantic_xml import BaseXmlModel, element InnerType = TypeVar('InnerType') XmlOptional = Annotated[ Optional[InnerType], PlainSerializer(lambda val: val if val is not None else 'null'), BeforeValidator(lambda val: val if val != 'null' else None), ] class Company(BaseXmlModel): title: XmlOptional[str] = element(default=None) xml_doc = ''' null ''' company = Company.from_xml(xml_doc) assert company.title is None assert canonicalize(company.to_xml(), strip_text=True) == canonicalize(xml_doc, strip_text=True) ``` -------------------------------- ### Serialize xs:list with xml_field_serializer Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Use the `xml_field_serializer` decorator to define custom serialization logic for fields, such as space-separated lists. This example demonstrates serializing lists of floats into a space-separated string within an XML element. ```python import pathlib from typing import List from xml.etree.ElementTree import canonicalize from pydantic_xml import BaseXmlModel, element, xml_field_serializer, xml_field_validator from pydantic_xml.element import XmlElementReader, XmlElementWriter class Plot(BaseXmlModel): x: List[float] = element() y: List[float] = element() @xml_field_validator('x', 'y') @classmethod def validate_space_separated_list(cls, element: XmlElementReader, field_name: str) -> List[float]: if (sub_element := element.pop_element(field_name, search_mode=cls.__xml_search_mode__)) and ( text := sub_element.pop_text() ): return list(map(float, text.split())) return [] @xml_field_serializer('x', 'y') def serialize_space_separated_list(self, element: XmlElementWriter, value: List[float], field_name: str) -> None: sub_element = element.make_element(tag=field_name, nsmap=None) sub_element.set_text(' '.join(map(str, value))) element.append_element(sub_element) xml_doc = pathlib.Path('./doc.xml').read_text() plot = Plot.from_xml(xml_doc) assert canonicalize(plot.to_xml(), strip_text=True) == canonicalize(xml_doc, strip_text=True) ``` ```xml 0.0 1.0 2.0 3.0 4.0 5.0 0.0 3.2 5.4 4.1 2.0 -1.2 ``` -------------------------------- ### Pydantic-XML Model Definition Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/quickstart.md This Python code defines Pydantic models for parsing the example XML. It includes various field types like attributes, elements, wrapped fields, enums, and custom validators, along with namespace handling. ```python import pathlib from datetime import date from enum import Enum from typing import Dict, List, Literal, Optional, Set, Tuple import pydantic as pd from pydantic import HttpUrl, conint from pydantic_xml import BaseXmlModel, RootXmlModel, attr, element, wrapped NSMAP = { 'co': 'http://www.company.com/contact', 'hq': 'http://www.company.com/hq', 'pd': 'http://www.company.com/prod', } class Headquarters(BaseXmlModel, ns='hq', nsmap=NSMAP): country: str = element() state: str = element() city: str = element() @pd.field_validator('country') def validate_country(cls, value: str) -> str: if len(value) > 2: raise ValueError('country must be of 2 characters') return value class Industries(RootXmlModel): root: Set[str] = element(tag='Industry') class Social(BaseXmlModel, ns_attrs=True, ns='co', nsmap=NSMAP): type: str = attr() url: HttpUrl class Product(BaseXmlModel, ns_attrs=True, ns='pd', nsmap=NSMAP): status: Literal['running', 'development'] = attr() launched: Optional[int] = attr(default=None) title: str class Person(BaseXmlModel): name: str = attr() class CEO(Person): position: Literal['CEO'] = attr() class CTO(Person): position: Literal['CTO'] = attr() class COO(Person): position: Literal['COO'] = attr() class Company(BaseXmlModel, tag='Company', nsmap=NSMAP): class CompanyType(str, Enum): PRIVATE = 'Private' PUBLIC = 'Public' trade_name: str = attr(name='trade-name') type: CompanyType = attr() founder: Dict[str, str] = element(tag='Founder') founded: Optional[date] = element(tag='Founded') employees: conint(gt=0) = element(tag='Employees') website: HttpUrl = element(tag='WebSite') industries: Industries = element(tag='Industries') key_people: Tuple[CEO, CTO, COO] = wrapped('key-people', element(tag='person')) headquarters: Headquarters socials: List[Social] = wrapped( 'contacts/socials', element(tag='social', default_factory=list), ns='co', nsmap=NSMAP, ) products: Tuple[Product, ...] = element(tag='product', ns='pd') xml_doc = pathlib.Path('./doc.xml').read_text() company = Company.from_xml(xml_doc) json_doc = pathlib.Path('./doc.json').read_text() assert company == Company.model_validate_json(json_doc) ``` -------------------------------- ### XML Serialization with Custom Parameters Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Customize XML serialization using parameters like pretty_print and encoding. Pass these as extra arguments to the to_xml() method. ```python xml = obj.to_xml( pretty_print=True, encoding='UTF-8', standalone=True ) print(xml) ``` -------------------------------- ### Dynamic Model Creation Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Create Pydantic models on the fly using runtime information for field definitions. The field specification syntax is similar to Pydantic's. ```python Company = create_model( 'Company', trade_name=(str, attr(name='trade-name')), type=(str, attr()), ) ``` -------------------------------- ### XML with Default Namespaces Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md This XML structure illustrates how default namespaces are applied to elements and their sub-elements, and how nested default namespaces can override parent namespaces. ```xml https://www.linkedin.com/company/spacex https://twitter.com/spacex https://www.youtube.com/spacex ``` -------------------------------- ### Enable Mypy Plugin in pyproject.toml Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Add this configuration to your pyproject.toml file to enable the pydantic-xml mypy plugin. ```toml [tool.mypy] plugins = [ "pydantic_xml.mypy" ] ``` -------------------------------- ### Enable Mypy Plugin in mypy.ini Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Add this configuration to your mypy.ini file to enable the pydantic-xml mypy plugin. ```ini [mypy] plugins = pydantic_xml.mypy ``` -------------------------------- ### Output XML from Raw Fields Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/raw.md The resulting XML after processing the raw fields, showing how different input formats are normalized into a consistent structure. ```xml https://www.linkedin.com/company/spacex https://twitter.com/spacex https://www.youtube.com/spacex ``` -------------------------------- ### Define Product Model with XML Attributes and Elements Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/index.md This Python code defines a Product model using pydantic-xml, specifying how its fields map to XML attributes ('status', 'launched') and element text. It demonstrates the use of `attr()` for attributes and basic type hints for element text. ```python class Product(BaseXmlModel): status: Literal['running', 'development'] = attr() # extracted from the 'status' attribute launched: Optional[int] = attr(default=None) # extracted from the 'launched' attribute title: str # extracted from the element text ``` -------------------------------- ### Define Base XML Model Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/quickstart.md Inherit from `BaseXmlModel` to create models that can be serialized to and deserialized from XML. Use `.to_xml()` for serialization and `.from_xml()` for deserialization. ```python from pydantic_xml import BaseXmlModel class Company(BaseXmlModel): description: constr(strip_whitespace=True) ``` -------------------------------- ### Declare Wrapped Fields Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/wrapper.md Use `pydantic_xml.wrapped()` to bind a field to a sub-element's text, attribute, or element. Provide the sub-element path and the entity type. This example shows binding to a string field using a direct path and an explicit `element` tag. ```python class Company(BaseXmlModel): city: str = wrapped( 'Info/Headquarters/Location', element(tag='City'), ) country: str = wrapped( 'Info/Headquarters/Location/Country', ) ``` -------------------------------- ### Document Type Declaration (DTD) Implementation Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Implement document type declarations for XML models using the lxml backend. This involves subclassing BaseXmlModel and defining DOC_PUBLIC_ID and DOC_SYSTEM_URL. ```python from typing import Any, ClassVar, Union import pydantic_xml as pxml import lxml.etree class DTDXmlModel(pxml.BaseXmlModel): DOC_PUBLIC_ID: ClassVar[str] DOC_SYSTEM_URL: ClassVar[str] def to_xml( self, *, skip_empty: bool = False, exclude_none: bool = False, exclude_unset: bool = False, **kwargs: Any, ) -> Union[str, bytes]: root = self.to_xml_tree(skip_empty=skip_empty, exclude_none=exclude_none, exclude_unset=exclude_unset) tree = lxml.etree.ElementTree(root) tree.docinfo.public_id = self.DOC_PUBLIC_ID tree.docinfo.system_url = self.DOC_SYSTEM_URL return lxml.etree.tostring(tree, **kwargs) class Html(DTDXmlModel, tag='html'): DOC_PUBLIC_ID: ClassVar[str] = '-//W3C//DTD HTML 4.01//EN' DOC_SYSTEM_URL: ClassVar[str] = 'http://www.w3.org/TR/html4/strict.dtd' title: str = pxml.wrapped('head', pxml.element()) body: str = pxml.element() html_doc = Html(title="This is a title", body="Hello world!") xml = html_doc.to_xml(pretty_print=True) print(xml.decode()) ``` -------------------------------- ### Ordered Mode XML and JSON Representation Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Shows the XML input and JSON output for a model using the 'ordered' search mode, including an intervening element. ```xml 2002-03-14 https://www.spacex.com ``` ```json { "founded": "2002-03-14", "website": "https://www.spacex.com" } ``` -------------------------------- ### Declare Element Namespace with `element()` Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Declare the namespace for a sub-element by passing `ns` and `nsmap` parameters to `pydantic_xml.element()`. `ns` is the alias, and `nsmap` is the mapping dictionary. ```python class Company(BaseXmlModel, tag='company'): founded: dt.date = element( ns='co', nsmap={'co': 'http://www.company.com/co'}, ) website: HttpUrl = element(tag='web-site') ``` -------------------------------- ### XML Output of Template Models Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/aliases.md This XML demonstrates how the `alias_generator` in the template models correctly maps fields to their aliased names in the XML output. ```xml Coyote V8 General Electric Passport V8 ``` -------------------------------- ### Strict Mode XML and JSON Representation Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Illustrates the XML input and JSON output for a model configured with the 'strict' search mode. ```xml https://www.spacex.com 2002-03-14 ``` ```json {} ``` -------------------------------- ### Grouping Heterogeneous Sub-elements with Explicit Models Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/homogeneous.md To group sub-elements with different tags, declare a separate Pydantic-XML model for each tag. Then, use a List of Tuples where each tuple element corresponds to one of these models. ```python class Product(BaseXmlModel, tag='product'): status: str = attr() title: str class Launch(RootXmlModel[int], tag='launched'): pass class Products(RootXmlModel): root: List[Tuple[Product, Optional[Launch]]] ``` -------------------------------- ### XML Representation of TokenAuth Request Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/generics.md This XML snippet demonstrates a `request` with a `TokenAuth` structure. The `auth` tag contains a nested `token` element, representing token-based authentication. ```xml 7de9e375-84c1-441f-a628-dbaf5017e94f ``` -------------------------------- ### Map Dictionary to Local Element Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/mappings.md Use a Dict field to bind to local element attributes. The keys of the dictionary correspond to attribute names. ```python class Company(BaseXmlModel): properties: Dict[str, str] ``` -------------------------------- ### Define a Root XML Model Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/models.md Define a root model that binds to the root XML element. The tag name can be specified or inferred from the class name. Parsing errors occur if the element is not found. ```python class Company(BaseXmlModel, tag='company'): title: str ``` -------------------------------- ### Explicitly Define Namespace for Sub-Models Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md When a sub-model shares a namespace with its parent, define the `ns` and `nsmap` explicitly on the sub-model class, as they are not inherited. ```python from pydantic_xml import BaseXmlModel, element NSMAP = { 'co': 'http://www.company.com/co', } class SubModel(BaseXmlModel, ns='co', nsmap=NSMAP): # define ns and nsmap explicitly field2: str = element(tag='element1') class Model(BaseXmlModel, ns='co', nsmap=NSMAP): field1: str = element(tag='element1') # ns "co" is inherited by the element sub: SubModel # ns and nsmap are not inherited by the SubModel model = Model(field1="value1", sub=SubModel(field2="value2")) print(model.to_xml(pretty_print=True).decode()) ``` -------------------------------- ### Template Model with Alias Generator Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/aliases.md Define a base template model and use `model_config` with `alias_generator` to map fields to different names for specific inherited models. ```python class VehicleTemplate(BaseXmlModel): drivers: int = attr() title: str = attr() engine: str = element() class Car(VehicleTemplate, tag='car'): model_config = pd.ConfigDict( alias_generator=lambda field: {'title': 'make', 'engine': 'motor'}.get(field, field), ) class Airplane(VehicleTemplate, tag='airplane'): model_config = pd.ConfigDict( alias_generator=lambda field: {'drivers': 'pilots', 'title': 'model'}.get(field, field), ) class Vehicles(BaseXmlModel, tag='vehicles'): items: List[Union[Car, Airplane]] ``` -------------------------------- ### Apply Namespace to Model Fields via `element()` Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Namespaces and mappings can be applied to model types using `pydantic_xml.element()`. If omitted, the model's own namespace and mapping are used. ```python class Headquarters( BaseXmlModel, tag='headquarters', ns='hq', nsmap={'hq': 'http://www.company.com/hq'}, ): country: str = element(ns='hq') state: str = element(ns='hq') city: str = element(ns='hq') class Company(BaseXmlModel, tag='company'): headquarters: Headquarters ``` -------------------------------- ### Inherit Model Namespace for Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/attributes.md Enable attributes to inherit the model's namespace by setting `ns_attrs=True` and defining the model-level namespace and namespace map. ```python class Company( BaseXmlModel, ns_attrs=True, ns='co', nsmap={'co': 'http://company.org/co'}, ): trade_name: str = attr(name='trade-name') type: str = attr() ``` -------------------------------- ### Exclude Empty Entities with skip_empty=True Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Pass `skip_empty=True` to `pydantic_xml.BaseXmlModel.to_xml()` to exclude all empty entities from the resulting XML. This parameter applies to the root model and its sub-models by default but can be adjusted per model. ```python class Product(BaseXmlModel, tag='Product', skip_empty=True): status: Optional[Literal['running', 'development']] = attr(default=None) launched: Optional[int] = attr(default=None) title: Optional[str] = element(tag='Title', default=None) class Company(BaseXmlModel, tag='Company'): trade_name: str = attr(name='trade-name') website: str = element(tag='WebSite', default='') products: Tuple[Product, ...] = element() company = Company( trade_name="SpaceX", products=[ Product(status="running", launched=2013, title="Several launch vehicles"), Product(status="running", title="Starlink"), Product(status="development"), Product(), ], ) ``` ```xml Several launch vehicles Starlink ``` -------------------------------- ### Pydantic Models for Default Namespaces Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Define pydantic models that correspond to the XML structure with default namespaces. The `nsmap` parameter with an empty key ('') is used to set the default namespace for a model and its children. ```python from typing import List from pydantic_xml import BaseXmlModel, element class Socials( BaseXmlModel, tag='socials', nsmap={'': 'http://www.company.com/soc'}, ): urls: List[str] = element(tag='social') class Contacts( BaseXmlModel, tag='contacts', nsmap={'': 'http://www.company.com/cnt'}, ): socials: Socials = element() class Company( BaseXmlModel, tag='company', nsmap={'': 'http://www.company.com/co'}, ): contacts: Contacts = element() ``` -------------------------------- ### Parse XML and Validate with JSON Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/models.md Read an XML document into a Pydantic model and then validate it against a JSON representation. This showcases bidirectional data handling. ```python xml_doc = pathlib.Path('./doc.xml').read_text() directory = Directory.from_xml(xml_doc) json_doc = pathlib.Path('./doc.json').read_text() assert directory == Directory.model_validate_json(json_doc) ``` -------------------------------- ### Parse XML to Pydantic Model and Serialize to JSON Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/quickstart.md Use `from_xml` to parse an XML document into a Pydantic model, then use the model's `.json()` method to serialize it to a JSON string. This demonstrates pydantic-xml's capability as an XML-to-JSON transcoder. ```python xml_doc = pathlib.Path('./doc.xml').read_text() company = Company.from_xml(xml_doc) json_doc = pathlib.Path('./doc.json') json_doc.write_text(company.json(indent=4)) ``` -------------------------------- ### Unordered Mode XML and JSON Representation Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Presents the XML input and JSON output for a model configured with the 'unordered' search mode. ```xml https://www.spacex.com 2002-03-14 ``` ```json { "founded": "2002-03-14", "website": "https://www.spacex.com" } ``` -------------------------------- ### Base64 Encoding for Bytes Fields in XML Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Illustrates encoding bytes typed fields as Base64 strings during XML serialization and decoding them back using `@field_validator`. This is useful for embedding binary data within XML. ```python import base64 import pathlib from typing import List, Optional, Union from xml.etree.ElementTree import canonicalize from pydantic import field_serializer, field_validator from pydantic_xml import BaseXmlModel, RootXmlModel, attr, element class File(BaseXmlModel): name: str = attr() content: bytes = element() @field_serializer('content') def encode_content(self, value: bytes) -> str: return base64.b64encode(value).decode() @field_validator('content', mode='before') def decode_content(cls, value: Optional[Union[str, bytes]]) -> Optional[bytes]: if isinstance(value, str): return base64.b64decode(value) return value class Files(RootXmlModel, tag='files'): root: List[File] = element(tag='file', default=[]) files = Files() for filename in ['./file1.txt', './file2.txt']: with open(filename, 'rb') as f: content = f.read() files.root.append(File(name=filename, content=content)) expected_xml_doc = pathlib.Path('./doc.xml').read_bytes() assert canonicalize(files.to_xml(), strip_text=True) == canonicalize(expected_xml_doc, strip_text=True) ``` -------------------------------- ### Nested Wrappers with Namespaces Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/wrapper.md Demonstrates how to use nested `pydantic_xml.wrapped()` calls to extract data from sub-elements across different namespaces. Each `wrapped` call can specify its own namespace and namespace map. ```python class Company( BaseXmlModel, ns='co', nsmap={'co': 'http://company.org/co'}, ): city: constr(strip_whitespace=True) = wrapped( 'Info', ns='co', entity=wrapped( 'Headquarters/Location', ns='hq', nsmap={'hq': 'http://company.org/hq'}, entity=element( tag='City', ns='loc', nsmap={'loc': 'http://company.org/loc'}, ), ), ) ``` -------------------------------- ### Inherit Namespace for Model Fields Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/elements.md Declare namespace and mapping for a model to inherit them for all primitive fields. Sub-models do not inherit namespaces automatically and must define them explicitly. ```python class Company( BaseXmlModel, tag='company', ns='co', nsmap={'co': 'http://www.company.com/co'}, ): founded: dt.date = element() website: HttpUrl = element(tag='web-site', ns='co') ``` -------------------------------- ### XML Document for SOAP Request Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/generics.md This XML document represents a SOAP envelope containing a `BasicAuth` in the header and a `CreateCompanyMethod` in the body. It includes namespace declarations for SOAP, authentication, and company-specific elements. ```xml admin secret SpaceX 2002-03-14 https://www.spacex.com ``` -------------------------------- ### Drop Empty Elements with skip_empty=True Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Inherit from `BaseXmlModel` with `skip_empty=True` to automatically drop fields with empty values (including `None`) during XML serialization. This results in a more concise XML output. ```python from typing import Optional from pydantic_xml import BaseXmlModel, element class Company(BaseXmlModel, skip_empty=True): title: Optional[str] = element(default=None) company = Company() assert company.to_xml() == b'' ``` -------------------------------- ### JSON for TypedDict Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/mappings.md Corresponding JSON representation for the XML with TypedDict attributes, mapping to the 'info' dictionary. ```json { "info": { "founded": "2002-03-14", "employees": 12000, "website": "https://www.spacex.com" } } ``` -------------------------------- ### Defining Generic XML Models Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/generics.md Define a generic `Request` model that accepts a type variable `AuthType`. This allows for different authentication structures within the same request model. Specialized request types like `BasicRequest` and `TokenRequest` are created by providing concrete types for `AuthType`. ```python from typing import TypeVar from uuid import UUID from pydantic import SecretStr from pydantic_xml import BaseXmlModel, attr, element AuthType = TypeVar('AuthType') class Request(BaseXmlModel, Generic[AuthType], tag='request'): request_id: UUID = attr(name='id') timestamp: float = attr() auth: AuthType class BasicAuth(BaseXmlModel): user: str = attr() password: SecretStr = attr() class TokenAuth(BaseXmlModel): token: UUID = element() BasicRequest = Request[BasicAuth] TokenRequest = Request[TokenAuth] ``` -------------------------------- ### Exclude Unset Values with exclude_unset=True Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Employ `exclude_unset=True` in `to_xml()` to omit fields that have not been explicitly set, even if they have a default value. This differs from `exclude_none` by considering fields that were never assigned a value. ```python class Product(BaseXmlModel, tag='Product'): title: Optional[str] = element(tag='Title', default=None) status: Optional[Literal['running', 'development']] = element(tag='Status', default=None) launched: Optional[int] = element(tag='Launched', default=None) product = Product(title="Starlink", status=None) xml = product.to_xml(exclude_unset=True) ``` ```xml Starlink ``` -------------------------------- ### Annotated typing for custom XML serialization Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Utilize the `Annotated` typing form to attach metadata, including custom validators and serializers, directly to type hints. This approach offers a cleaner way to define reusable serialization and validation logic for fields. ```python import pathlib from typing import Annotated, List, Type from xml.etree.ElementTree import canonicalize import pydantic_xml as pxml from pydantic_xml.element import XmlElementReader, XmlElementWriter def validate_space_separated_list( cls: Type[pxml.BaseXmlModel], element: XmlElementReader, field_name: str, ) -> List[float]: if element := element.pop_element(field_name, search_mode=cls.__xml_search_mode__): return list(map(float, element.pop_text().split())) return [] def serialize_space_separated_list( model: pxml.BaseXmlModel, element: XmlElementWriter, value: List[float], field_name: str, ) -> None: sub_element = element.make_element(tag=field_name, nsmap=None) sub_element.set_text(' '.join(map(str, value))) element.append_element(sub_element) SpaceSeparatedValueList = Annotated[ List[float], pxml.XmlFieldValidator(validate_space_separated_list), pxml.XmlFieldSerializer(serialize_space_separated_list), ] class Plot(pxml.BaseXmlModel): x: SpaceSeparatedValueList = pxml.element() y: SpaceSeparatedValueList = pxml.element() xml_doc = pathlib.Path('./doc.xml').read_text() plot = Plot.from_xml(xml_doc) assert canonicalize(plot.to_xml(), strip_text=True) == canonicalize(xml_doc, strip_text=True) ``` -------------------------------- ### Exclude None Values with exclude_none=True Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Use the `exclude_none=True` parameter in `to_xml()` to exclude fields with `None` values from the generated XML. This is useful for cleaning up output when optional fields are not set. ```python class Product(BaseXmlModel, tag='Product'): title: Optional[str] = element(tag='Title', default=None) status: Optional[Literal['running', 'development']] = element(tag='Status', default=None) launched: Optional[int] = element(tag='Launched', default=None) product = Product(title="Starlink", status=None) xml = product.to_xml(exclude_none=True) ``` ```xml Starlink ``` -------------------------------- ### Define Raw Element Typed Fields Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/raw.md Annotate fields with `Element` and set `arbitrary_types_allowed=True` to handle raw XML elements. This is useful when the schema is unknown or complex. ```python class Contact(BaseXmlModel, tag='contact'): url: HttpUrl class Contacts( BaseXmlModel, tag='contacts', arbitrary_types_allowed=True, ): contacts_raw: List[Element] = element(tag='contact', exclude=True) @computed_element def parse_raw_contacts(self) -> List[Contact]: contacts: List[Contact] = [] for contact_raw in self.contacts_raw: if url := contact_raw.attrib.get('url'): contact = Contact(url=url) elif (link := contact_raw.find('link')) is not None: contact = Contact(url=link.text) else: contact = Contact(url=contact_raw.text.strip()) contacts.append(contact) return contacts ``` -------------------------------- ### Custom Datetime Encoding for XML Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/misc.md Demonstrates how to use `@field_serializer` to customize the XML encoding of a datetime field to a float timestamp. This is useful for specific serialization requirements. ```python class File(BaseXmlModel): created: datetime = element() @field_serializer('created') def encode_created(self, value: datetime) -> float: return value.timestamp() ``` -------------------------------- ### JSON for Local Element Attributes Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/mappings.md Corresponding JSON representation for the XML with local attributes, mapping to the 'properties' dictionary. ```json { "properties": { "trade-name": "SpaceX", "type": "Private" } } ``` -------------------------------- ### XML Representation of BasicAuth Request Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/generics.md This XML snippet shows a `request` element with a `BasicAuth` nested within its `auth` tag. It includes attributes for `id`, `timestamp`, and `user`/`password` for authentication. ```xml ``` -------------------------------- ### Defaulting to Empty String for Element Text Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/text.md To deserialize empty element text as an empty string (`""`), provide `""` as the default value for the field. ```python class Company(BaseXmlModel): description: str = "" ``` -------------------------------- ### Custom Root Type for Model List Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/models.md Implement a custom root type for a list of model types. This enables the model to represent a collection of structured items, where each item conforms to a specified model. ```python class Socials(RootXmlModel, tag='socials'): root: List[HttpUrl] = element(tag='social') class Contacts(RootXmlModel[Socials], tag='contacts'): pass ``` -------------------------------- ### Define XML Models for Hierarchical Data Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/models.md Define Pydantic models for XML elements, including nested structures and attributes. Use `attr` for attributes and `element` for nested elements. ```python import pathlib from typing import List, Optional from pydantic_xml import BaseXmlModel, attr, element class File(BaseXmlModel, tag="File"): name: str = attr(name='Name') mode: str = attr(name='Mode') class Directory(BaseXmlModel, tag="Directory"): name: str = attr(name='Name') mode: str = attr(name='Mode') dirs: Optional[List['Directory']] = element(tag='Directory', default=None) files: Optional[List[File]] = element(tag='File', default_factory=list) ``` -------------------------------- ### Define Company Model with XML Attributes, Elements, and Nested Lists Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/index.md This Python code defines a Company model using pydantic-xml. It showcases mapping XML attributes ('trade-name'), element text ('website'), and nested elements ('product') using `attr()`, `element()`, and `List` with a specified tag. It also includes default values for optional fields. ```python class Company(BaseXmlModel): trade_name: str = attr(name='trade-name') # extracted from the 'trade-name' attribute website: HttpUrl = element() # extracted from the 'element' text products: List[Product] = element(tag='product', default=[]) # extracted from the 'Company' element's children ``` -------------------------------- ### JSON Document for SOAP Request Source: https://github.com/dapper91/pydantic-xml/blob/master/docs/source/pages/data-binding/generics.md This JSON document represents the parsed SOAP request. It shows the nested structure of the header (containing `auth` with `user` and `password`) and the body (containing `call` with `trade_name`, `founded`, and `website`). ```json { "header": { "auth": { "user": "admin", "password": "secret" } }, "body": { "call": { "trade_name": "SpaceX", "founded": "2002-03-14", "website": "https://www.spacex.com" } } } ```