Elements vs types

Orthogonal concepts

In W3C XML Schema, Element and Type are separate, orthogonal concepts:

Element declaration

Defines XML structure - what elements can appear in documents

<xs:element name="person" type="PersonType"/>
Type definition

Defines data structure - what content elements can contain

<xs:complexType name="PersonType">
  <xs:sequence>
    <xs:element name="name" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

Lutaml::Model representation

Models can have:

Element with type

Generates both element declaration and type definition

class Person < Lutaml::Model::Serializable
  attribute :name, :string

  xml do
    element 'person'  # Declares <person> element
    map_element 'name', to: :name
  end
end

# Generates:
# <xs:element name="person" type="PersonType"/>
# <xs:complexType name="PersonType">...</xs:complexType>
Type only

Generates only type definition, no element

class Address < Lutaml::Model::Serializable
  attribute :street, :string

  xml do
    # No element() call - type-only model
    sequence do
      map_element 'street', to: :street
    end
  end
end

# Generates:
# <xs:complexType name="AddressType">...</xs:complexType>
# (no element declaration)

Namespace semantics

URI is the identifier

Per W3C specifications, the namespace URI uniquely identifies a namespace:

class ContactNamespace < Lutaml::Model::XmlNamespace
  uri 'https://example.com/schemas/contact/v1'  # The true identifier
end

The URI is what matters for namespace matching during parsing - two elements are in the same namespace if they have the same URI, regardless of prefix.

Prefixes are labels

Namespace prefixes are merely convenient labels with no semantic meaning:

class ContactNamespace < Lutaml::Model::XmlNamespace
  uri 'https://example.com/schemas/contact/v1'
  prefix_default 'contact'  # Default label, can be overridden
end

These XML documents are equivalent:

<contact:person xmlns:contact="https://example.com/schemas/contact/v1">
  <contact:name>John</contact:name>
</contact:person>

<c:person xmlns:c="https://example.com/schemas/contact/v1">
  <c:name>John</c:name>
</c:person>

Both use the same namespace URI, just different prefix labels.

Qualification

Qualification determines whether elements/attributes must include namespace prefixes in instance documents:

Qualified (:qualified)

Elements include namespace prefix

<cer:ceramic xmlns:cer="https://example.com/ceramic">
  <cer:type>Porcelain</cer:type>
</cer:ceramic>
Unqualified (:unqualified)

Elements have no namespace prefix

<cer:ceramic xmlns:cer="https://example.com/ceramic">
  <type>Porcelain</type>
</cer:ceramic>
Even when unqualified, child elements inherit the default namespace from the root element per XML namespace rules.

Qualification hierarchy

Qualification is controlled at three levels:

Qualification control hierarchy
                 ┌─────────────────────────────────────────┐
                 │  1. Namespace-Level Defaults            │
                 │  element_form_default: :qualified       │
                 │  attribute_form_default: :unqualified   │
                 └─────────────────────────────────────────┘
                                    │
                                    ▼
                 ┌─────────────────────────────────────────┐
                 │  2. Element/Attribute-Level Overrides   │
                 │  form: :qualified or :unqualified       │
                 └─────────────────────────────────────────┘
                                    │
                                    ▼
                 ┌─────────────────────────────────────────┐
                 │  3. Global Element/Attribute Rule       │
                 │  Always qualified when in a namespace   │
                 └─────────────────────────────────────────┘

Priority order (highest to lowest):

  1. Global elements/attributes: Always qualified when in namespace

  2. Element/attribute form: override: Explicit per-mapping control

  3. Namespace defaults: element_form_default, attribute_form_default