Introduction
XML namespaces help avoid element name conflicts and organize elements from different schemas. This tutorial introduces namespace basics in Lutaml::Model.
What are XML namespaces?
An XML namespace is a URI that uniquely identifies a set of element and attribute names. Namespaces prevent naming conflicts when combining XML from different sources.
<ceramic xmlns="http://example.com/ceramic">
<type>Porcelain</type>
</ceramic>The xmlns declares the default namespace for this element and its children.
Creating a namespace class
In Lutaml::Model, define namespaces using XmlNamespace classes:
Syntax:
class MyNamespace < Lutaml::Model::XmlNamespace
uri 'namespace-uri'
prefix_default 'prefix'
endclass CeramicNamespace < Lutaml::Model::XmlNamespace
uri 'https://example.com/schemas/ceramic/v1'
prefix_default 'cer'
endUsing namespaces in models
Assign namespaces to your models using the namespace method:
class CeramicNamespace < Lutaml::Model::XmlNamespace
uri 'http://example.com/ceramic'
prefix_default 'cer'
end
class Ceramic < Lutaml::Model::Serializable
attribute :type, :string
attribute :glaze, :string
xml do
element "Ceramic"
namespace CeramicNamespace
map_element 'Type', to: :type
map_element 'Glaze', to: :glaze
end
end
ceramic = Ceramic.new(type: "Porcelain", glaze: "Clear")
puts ceramic.to_xmlOutput (default namespace):
<Ceramic xmlns='http://example.com/ceramic'>
<Type>Porcelain</Type>
<Glaze>Clear</Glaze>
</Ceramic>Using prefixed namespaces
To use a prefix instead of default namespace, use prefix: true:
puts ceramic.to_xml(prefix: true)Output:
<cer:Ceramic xmlns:cer='http://example.com/ceramic'>
<cer:Type>Porcelain</cer:Type>
<cer:Glaze>Clear</cer:Glaze>
</cer:Ceramic>Multiple namespaces
Real-world XML often uses multiple namespaces:
class CeramicNamespace < Lutaml::Model::XmlNamespace
uri 'https://example.com/ceramic'
prefix_default 'cer'
end
class GlazeNamespace < Lutaml::Model::XmlNamespace
uri 'https://example.com/glaze'
prefix_default 'glz'
end
class Ceramic < Lutaml::Model::Serializable
attribute :type, :string
attribute :glaze, :string
xml do
element 'ceramic'
namespace CeramicNamespace
map_element 'type', to: :type
map_element 'glaze', to: :glaze # Uses Glaze's type namespace
end
end
puts Ceramic.new(type: "Porcelain", glaze: "Celadon").to_xml(prefix: true)Output:
<cer:ceramic xmlns:cer="https://example.com/ceramic"
xmlns:glz="https://example.com/glaze">
<cer:type>Porcelain</cer:type>
<glz:glaze>Celadon</glz:glaze>
</cer:ceramic>Form Defaults: elementFormDefault and attributeFormDefault
XSD schemas support elementFormDefault and attributeFormDefault to control whether local elements and attributes must be namespace-qualified.
element_form_default
Controls whether local elements (declared inside complexType) must be namespace-qualified in instance documents:
class MyNamespace < Lutaml::Model::XmlNamespace
uri 'http://example.com/ceramic'
prefix_default 'cer'
# Local elements will be namespace-qualified
element_form_default :qualified
endWith element_form_default :qualified, local elements appear with namespace prefix:
<cer:Ceramic xmlns:cer="http://example.com/ceramic">
<cer:type>Porcelain</cer:type> <!-- Prefixed because elementFormDefault="qualified" -->
</cer:Ceramic>With element_form_default :unqualified (the W3C default), local elements appear without prefix:
<cer:Ceramic xmlns:cer="http://example.com/ceramic">
<type>Porcelain</type> <!-- No prefix because elementFormDefault="unqualified" -->
</cer:Ceramic>attribute_form_default
Controls whether local attributes must be namespace-qualified:
class MyNamespace < Lutaml::Model::XmlNamespace
uri 'http://example.com/ceramic'
prefix_default 'cer'
attribute_form_default :qualified # Local attributes will be prefixed
endWith attribute_form_default :qualified, local attributes appear with namespace prefix:
<cer:Ceramic xmlns:cer="http://example.com/ceramic" cer:id="123">
<cer:type>Porcelain</cer:type>
</cer:Ceramic>With attribute_form_default :unqualified (the W3C default), local attributes appear without prefix:
<cer:Ceramic xmlns:cer="http://example.com/ceramic" id="123">
<cer:type>Porcelain</cer:type>
</cer:Ceramic>Overriding Form Defaults for Individual Elements/Attributes
You can override the schema-level default for individual elements or attributes using the form option:
class MixedForms < Lutaml::Model::Serializable
attribute :qualified_content, :string
attribute :unqualified_content, :string
xml do
element "mixedForms"
namespace MyNamespace # elementFormDefault: :qualified
# Override: unqualified despite schema default
map_element "unqualified_content", to: :unqualified_content, form: :unqualified
# Default: qualified (matches element_form_default)
map_element "qualified_content", to: :qualified_content
end
endUsing form Option with Attributes
class MixedAttrForms < Lutaml::Model::Serializable
attribute :qualified_id, :string
attribute :unqualified_id, :string
xml do
element "mixedAttrForms"
namespace MyNamespace # attributeFormDefault: :qualified
# Override: unqualified despite schema default
map_attribute "unqualified_id", to: :unqualified_id, form: :unqualified
# Default: qualified (matches attribute_form_default)
map_attribute "qualified_id", to: :qualified_id
end
endFor more details on XSD form defaults and how they affect schema generation, see XSD Generation with Namespace Support.