Namespace profiles and bindings¶
The ddi_l.namespaces module centralizes the namespace bindings that appear
throughout DDI 3.x instance documents. Profiles expose curated collections of
prefix/URI pairs for common maintainable modules so downstream tooling can apply
consistent bindings regardless of whether they rely on the stdlib or lxml XML
backends. The default bindings target the bundled 3.3 release, while helpers in
ddi_l.schema_loader expose namespace maps for 3.1 and 3.2 when legacy
content needs to be processed.
Built-in profiles¶
| Profile constant | Included prefixes |
|---|---|
DDI_DEFAULT_PROFILE |
Default namespace (ddi:instance:3_3), reusable (r), XML Schema Instance (xsi) |
DDI_REUSABLE_PROFILE |
Reusable (r) |
DDI_STUDY_UNIT_PROFILE |
Study Unit (s) and Conceptual Component (c) |
DDI_DATA_COLLECTION_PROFILE |
Data Collection (d) |
DDI_LOGICAL_PRODUCT_PROFILE |
Logical Product (l) |
DDI_PHYSICAL_DATA_PROFILE |
Physical Data Product (p) |
DDI_ARCHIVE_PROFILE |
Archive (a) |
DDI_CONCEPTUAL_COMPONENT_PROFILE |
Conceptual Component (cc) |
DDI_COMPARATIVE_PROFILE |
Comparative (cmp) |
DDI_PROFILE_PROFILE |
Profile metadata (pr) |
Profiles live in the NAMESPACE_PROFILES mapping and can be retrieved with
get_namespace_profile(name) when you need to inspect the raw bindings.
Merging profiles¶
Use merge_namespace_profiles to combine named profiles with ad-hoc overrides.
Conflicting bindings raise a ValueError by default so accidental rebinding is
caught early. Pass allow_override=True or supply the overrides mapping when
you intentionally want later values to replace earlier ones.
from ddi_l.namespaces import (
DDI_DEFAULT_PROFILE,
DDI_STUDY_UNIT_PROFILE,
merge_namespace_profiles,
)
bindings = merge_namespace_profiles(
DDI_DEFAULT_PROFILE,
DDI_STUDY_UNIT_PROFILE,
overrides={"custom": "http://example.com/ns"},
)
The returned dictionary can be supplied directly to XML builders or registered with global namespace registries when using the stdlib backend.
Applying profiles to documents¶
DDIDocument.ensure_namespace_prefixes takes a single profile (or a
prefix-to-URI mapping) plus optional ad-hoc bindings passed as the keyword-only
extra_namespaces. The method normalizes the namespace declarations so the
resulting XML contains consistent prefixes whether lxml is installed or not.
import ddi_l as ddi
from ddi_l.namespaces import DDI_STUDY_UNIT_PROFILE
doc = ddi.new_study(title="Demo", agency="example.agency")
doc.inner.ensure_namespace_prefixes(
DDI_STUDY_UNIT_PROFILE,
extra_namespaces={"custom": "http://example.com/ns"},
)
To apply more than one profile, merge them first. merge_namespace_profiles
returns a mapping, which is one of the things the method accepts:
from ddi_l.namespaces import (
DDI_PROFILE_PROFILE,
DDI_STUDY_UNIT_PROFILE,
merge_namespace_profiles,
)
doc.inner.ensure_namespace_prefixes(
merge_namespace_profiles(DDI_PROFILE_PROFILE, DDI_STUDY_UNIT_PROFILE),
extra_namespaces={"custom": "http://example.com/ns"},
)
extra_namespaces is applied last, so callers can override the profile's
bindings deliberately. The conflict-detection controls (allow_override,
overrides) belong to merge_namespace_profiles, not to this method. Do the
merge, and its ValueError fires before the document is touched.
Working with lxml and stdlib¶
The namespace helpers hide the small differences between the stdlib and lxml
backends. When lxml is available, the profiles are merged into the element
nsmap and round-tripped through cleanup_namespaces. When only the stdlib is
present the same bindings are registered with xml.etree.ElementTree so the
serialized document still includes the requested declarations. The new helper
module therefore ensures consistent output across environments.