LXR Packages: A Complete Guide to Portable XSD Schema Repositories
When you work with XSD schemas in production, you quickly discover a fundamental truth: schemas are not isolated artifacts — they form ecosystems. This post explains what LXR packages are, why they exist, and how to use them.
The Problem: XML Schemas Are Ecosystems
Consider a typical urban planning schema like the i-UR standard used in Japan’s PLATEAU project. Its import graph looks like this:
urbanFunction.xsd
└── urbanObject.xsd
└── gml/3.2.1/gml.xsd
├── xlink/xlink.xsd
├── iso/19139/gmd/gmd.xsd
│ ├── gco/gco.xsd
│ ├── gss/gss.xsd
│ ├── gts/gts.xsd
│ ├── gmx/gmx.xsd
│ └── gsr/gsr.xsd
└── gml/3.2.1/basicTypes.xsd
└── ...
CityGML modules
├── appearance.xsd
├── building.xsd
├── rel_CityObject.xsd
└── ...
└── gml/3.2.1/gml.xsd (shared dependency)
This creates an import graph spanning dozens of schemas from multiple organizations — OGC, ISO, CityGML working groups. When you need to build XML documents against this ecosystem, you must answer questions like:
- What is the full definition of
gml:CodeType? What elements can use it? - When
uro:BuildingTypeextendsgml:AbstractFeatureType, what does it inherit? - What elements and attributes are available on
urf:LandUseType?
Answering these questions requires tracing type references across namespace boundaries — manually tracking import chains, fetching remote schemas, and writing resolution code. This is the problem LXR packages solve.
What Is an LXR Package?
An LXR package (LutaML XML Schema Repository) is a self-contained archive that captures a fully resolved schema ecosystem.
It is not just a collection of XSD files. An LXR package contains:
- All XSD schema files (when using
include_allmode) — no external fetching required - Pre-resolved type index — every type, element, attribute, group, and their relationships
- Namespace mappings — prefix-to-URI resolution for human-readable queries
- Schema location mappings — rewrite rules that redirect remote imports to local files
- Package metadata — version, description, creation date, statistics
When you load an LXR package, you have immediate access to:
- Type definitions with all elements, attributes, restrictions, extensions
- Reference resolution —
gml:CodeTyperesolves to its exact definition - Dependency graph — what types reference what, and what references them (
used_by) - Namespace awareness — query by prefix (
gml:PointType) or full URI - Cross-schema navigation — traverse from any type to any other type in the package
Building an LXR Package
An LXR package is built from a YAML configuration file:
# config.yml
files:
- schemas/person.xsd
- schemas/company.xsd
namespace_mappings:
- prefix: "p"
uri: "http://example.com/person"
- prefix: "c"
uri: "http://example.com/company"
Then build with the CLI:
lutaml-xsd build from-config config.yml --output package.lxr
Package Contents
An LXR package is a ZIP archive:
package.lxr/
├── metadata.yaml # Package metadata and configuration
├── schemas/ # Bundled XSD files
│ ├── person.xsd
│ └── company.xsd
└── schemas_data/ # Pre-serialized schemas (when resolved)
├── person.marshal
└── company.marshal
Configuration Axes
LXR packages are configured along three independent axes:
XSD Bundling Mode
| Mode | Description |
|---|---|
include_all |
Bundles all XSD files with rewritten paths. Fully offline. |
allow_external |
Keeps original URL references. Smaller, but requires network. |
Resolution Mode
| Mode | Description |
|---|---|
resolved |
Pre-serializes schemas for instant loading. Best for production. |
bare |
Parses XSD on load. Smaller packages. Best for development. |
Serialization Format
| Format | Description |
|---|---|
marshal |
Ruby’s native binary. Fastest. Ruby-only. |
json |
Cross-platform. Human-readable. |
yaml |
Most human-readable. Best for debugging. |
parse |
No serialization. Always parses XSD. Smallest. |
Recommended for production: include_all + resolved + marshal.
What You Can Do With a Package
Query Types by Qualified Name
lutaml-xsd pkg type find gml:CodeType urban_function.lxr
Returns the full type definition: base type, elements, attributes, restrictions.
Search Across All Namespaces
lutaml-xsd pkg search Geometry urban_function.lxr --limit 10
Finds types matching “Geometry” across all bundled schemas.
Inspect Package Statistics
lutaml-xsd pkg stats urban_function.lxr
Shows type counts by category, namespace counts, and more.
View Package Structure
lutaml-xsd pkg tree urban_function.lxr
lutaml-xsd pkg inspect urban_function.lxr
A Real-World Example
The PLATEAU i-UR Schema Browser demonstrates a production LXR package. Its configuration declares:
- Entry files:
urbanFunction.xsdandurbanObject.xsd - Schema location mappings: 12 regex rules mapping remote URLs (OGC, ISO, CityGML) to local files for offline processing
- Namespace mappings:
urf,uro,gml,xlink,xs - Appearance: Custom logos, colors, and favicons for the SPA
Building the package:
lutaml-xsd build from-config config.yml --output urban_function.lxr
The resulting package contains 50+ schemas, 200+ types, and 10+ namespaces — fully resolvable offline, with a complete type index ready for queries.
Summary
LXR packages solve the real problems of working with XSD schema ecosystems:
- Full type resolution: Every type, element, attribute — resolved across namespaces and imports
- Offline reliability: All schemas bundled locally, no network dependency
- Instant loading: Pre-serialized schemas load in milliseconds, not seconds
- Portable distribution: Single
.lxrfile contains everything needed
For more details, see the LXR Packages Guide and Package Configuration.