Builder Overview
The DDEX Builder generates deterministic, industry-compliant DDEX XML files from structured data. Built with Rust for maximum performance and featuring byte-perfect reproducibility, it's the perfect companion to the DDEX Parser for complete metadata workflows.
What is DDEX Builder?
DDEX Builder transforms structured data (JSON, objects, DataFrames) into valid DDEX XML messages that are guaranteed to be byte-identical on every generation. Whether you're building music distribution systems, content management platforms, or analytics pipelines, the builder ensures your DDEX deliveries meet industry standards while maintaining perfect consistency.
Key Features
🎯 Deterministic Output
- 100% reproducible XML generation with stable, content-based IDs
- DB-C14N/1.0 canonicalization ensures byte-perfect consistency across platforms
- Content-addressable resource references for reliable cross-references
- Stable ordering of all XML elements and attributes
🏭 Industry Presets
Pre-configured settings for major music platforms:
- Spotify: Streaming platform requirements with explicit content flags
- YouTube Music: Content ID and monetization compliance
- Apple Music: iTunes Store requirements and Mastered for iTunes specs
- Amazon Music: Prime and Unlimited platform requirements
- Universal: Generic preset for broad distributor compatibility
🚀 High Performance
- Native Rust core with optimized language bindings
- Sub-millisecond builds for typical releases (<15ms average)
- Streaming generation for massive catalogs (>100,000 tracks)
- Memory-efficient processing with configurable limits
🔒 Comprehensive Validation
- Real-time DDEX schema validation with detailed error messages
- Business rule enforcement for industry compliance
- Reference integrity checking across entire message structure
- Territory and rights validation with intelligent suggestions
🌐 Universal Language Support
- JavaScript/TypeScript: Native Node.js performance with full type safety
- Python: PyO3 bindings with pandas DataFrame integration
- WebAssembly: Browser-ready bundle optimized at <400KB
- Rust: Direct access to the core building engine
Core Concepts
Deterministic Generation
Traditional XML generation produces different output for the same data due to:
- Non-deterministic hash functions
- Unstable element ordering
- Platform-specific timestamp formats
- Memory address-based IDs
DDEX Builder solves this with:
// These calls produce IDENTICAL XML every time
const xml1 = await builder.build(releaseData);
const xml2 = await builder.build(releaseData);
console.assert(xml1 === xml2); // ✅ Always true
// Even across different machines/platforms
const xmlLinux = buildOnLinux(data);
const xmlMacOS = buildOnMacOS(data);
const xmlWindows = buildOnWindows(data);
// All three XML strings are byte-identical
DB-C14N/1.0 Canonicalization
The builder implements the Database Canonicalization 1.0 specification:
- Lexicographic ordering of attributes
- Normalized whitespace handling
- Consistent namespace declarations
- Standardized character encoding
- Deterministic element ordering
This ensures that semantically identical XML produces identical bytes:
<!-- Input A -->
<Release territoryCode="US" upc="123456789">
<Title>Album</Title>
</Release>
<!-- Input B -->
<Release upc="123456789" territoryCode="US">
<Title>Album</Title>
</Release>
<!-- Both produce IDENTICAL canonicalized output -->
Content-Based IDs
Rather than random UUIDs, the builder generates deterministic IDs based on content:
const releaseData = {
title: "My Album",
artist: "Artist Name",
upc: "123456789012"
};
// ID is generated from content hash: REL_a1b2c3d4e5f6...
// Same data = same ID, every time
const xml = await builder.build(releaseData);
Architecture
Core Components
- Rust Builder Core: High-performance XML generation with canonicalization
- Validation Engine: Schema and business rule validation
- Preset System: Platform-specific configuration templates
- Language Bindings: Native interfaces for JavaScript, Python, and WASM
- Streaming Engine: Memory-efficient processing for large datasets
Data Flow
Structured Data → Validation → Content IDs → XML Generation → Canonicalization
↓ ↓ ↓ ↓ ↓
JSON/Object Schema Check Content Hash Raw XML DB-C14N/1.0
DataFrame Business Rules Deterministic Elements Byte-perfect
Use Cases
Music Distribution Platforms
Generate DDEX deliveries for record labels and distributors:
import { DdexBuilder } from 'ddex-builder';
const builder = new DdexBuilder();
builder.applyPreset('spotify'); // Platform-specific requirements
const delivery = await builder.build({
messageHeader: {
messageId: 'DELIVERY_2024_001',
messageSenderName: 'My Record Label'
},
releases: [{
title: 'New Album',
artist: 'Amazing Artist',
upc: '123456789012',
territories: ['WorldWide'],
releaseDate: '2024-01-15'
}],
resources: [{
title: 'Hit Single',
isrc: 'US1234567890',
duration: 'PT3M45S'
}]
});
console.log('Generated delivery:', delivery.length, 'bytes');
Content Management Systems
Build administrative interfaces for managing music metadata:
from ddex_builder import DdexBuilder
import pandas as pd
# Load catalog from database
catalog_df = pd.read_sql('SELECT * FROM releases', connection)
# Build DDEX messages from DataFrame
builder = DdexBuilder(preset='generic_audio_album', validate=True)
xml = builder.from_dataframe(catalog_df, version='4.3')
# Save for distribution
with open('catalog_delivery.xml', 'w') as f:
f.write(xml)
Analytics and Reporting
Generate DDEX reports from analytics data:
// Transform analytics data to DDEX format
const analyticsData = await fetchAnalyticsData();
const reportBuilder = new DdexBuilder({
preset: 'analytics_report',
canonical: true
});
const ddexReport = await reportBuilder.build({
reportingPeriod: {
startDate: '2024-01-01',
endDate: '2024-01-31'
},
performances: analyticsData.map(item => ({
isrc: item.track_isrc,
territory: item.country,
playCount: item.streams,
revenue: item.net_revenue
}))
});
Round-Trip Workflows
Perfect integration with DDEX Parser for complete workflows:
import { DDEXParser } from 'ddex-parser';
import { DdexBuilder } from 'ddex-builder';
// Parse existing DDEX file
const parser = new DDEXParser();
const parsed = await parser.parseFile('original.xml');
// Modify specific data
const modified = { ...parsed.flat };
modified.releases[0].title = 'Remastered Edition';
modified.releases[0].releaseDate = '2024-02-01';
// Build new deterministic XML
const builder = new DdexBuilder({ canonical: true });
const newXml = await builder.build(parsed.toBuildRequest());
// Verify round-trip integrity
const reparsed = await parser.parseString(newXml);
console.assert(reparsed.flat.releases[0].title === 'Remastered Edition');
Performance Characteristics
Build Speed Benchmarks
Dataset Size | Node.js | Python | Rust Core | Browser (WASM) |
---|---|---|---|---|
Single release (10 tracks) | 3ms | 5ms | 0.8ms | 8ms |
Album catalog (100 releases) | 25ms | 40ms | 12ms | 85ms |
Label catalog (1,000 releases) | 180ms | 280ms | 95ms | 650ms |
Large catalog (10,000 releases) | 1.8s | 2.8s | 950ms | 6.5s |
Memory Efficiency
Traditional XML builders vs DDEX Builder:
Dataset Size | Traditional | DDEX Builder | Improvement |
---|---|---|---|
1,000 releases | 450MB | 120MB | 73% reduction |
10,000 releases | 4.2GB | 300MB | 93% reduction |
100,000 releases | >16GB | 500MB* | >97% reduction |
*With streaming mode enabled
Determinism Performance
The canonicalization process adds minimal overhead:
Operation | Without Canonicalization | With DB-C14N/1.0 | Overhead |
---|---|---|---|
Small release (10 tracks) | 2.1ms | 2.3ms | +9% |
Medium catalog (100 releases) | 18ms | 21ms | +17% |
Large catalog (1000 releases) | 140ms | 165ms | +18% |
Supported DDEX Versions
The builder supports all major DDEX ERN versions with full compliance:
Version | Status | Coverage | Notes |
---|---|---|---|
ERN 4.3 | ✅ Full | 100% | Latest specification, recommended |
ERN 4.2 | ✅ Full | 100% | Stable version, widely adopted |
ERN 3.8.2 | ✅ Full | 100% | Legacy support for older systems |
Version-Specific Features
// ERN 4.3 - Latest features
const ern43Builder = new DdexBuilder({ version: '4.3' });
// Supports: Enhanced territories, streaming-specific metadata
// ERN 4.2 - Stable production
const ern42Builder = new DdexBuilder({ version: '4.2' });
// Supports: Standard territories, established metadata fields
// ERN 3.8.2 - Legacy compatibility
const ern382Builder = new DdexBuilder({ version: '3.8.2' });
// Supports: Core functionality, basic territory handling
Industry Compliance
Platform Requirements
The preset system ensures compliance with major platforms:
Spotify Requirements
- Explicit content flagging (required)
- Territory restrictions for streaming
- Artist ID validation
- Genre normalization to Spotify taxonomy
YouTube Music Requirements
- Content ID metadata
- Monetization policy compliance
- Territory-specific rights handling
- Revenue reporting integration
Apple Music Requirements
- iTunes Store compliance rules
- Mastered for iTunes specifications
- Region-specific pricing tiers
- Album artwork requirements
Business Rules Engine
The builder enforces industry best practices:
const builder = new DdexBuilder({
businessRules: {
enforceISRC: true, // Require ISRC for all tracks
validateTerritoryRights: true, // Check territory/rights consistency
requireUPCForAlbums: true, // UPC mandatory for album releases
genreNormalization: true, // Standardize genre classifications
explicitContentFlag: true // Require parental advisory flags
}
});
Integration Patterns
Microservices Architecture
Deploy as a dedicated building service:
// Express.js microservice
app.post('/build', async (req, res) => {
try {
const builder = new DdexBuilder({
preset: 'generic_audio_album',
validate: true
});
const xml = await builder.build(req.body.data);
res.json({
success: true,
xml: xml,
metadata: {
sizeBytes: xml.length,
version: req.body.data.version || '4.3',
generatedAt: new Date().toISOString()
}
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
type: error.constructor.name
});
}
});
Event-Driven Processing
React to catalog changes with automatic DDEX generation:
import asyncio
from ddex_builder import DdexBuilder
async def handle_catalog_update(event):
"""Generate DDEX when catalog changes."""
builder = DdexBuilder(
preset=event.platform,
validate=True,
canonical=True
)
try:
# Build DDEX from updated catalog
xml = await builder.build_async(event.catalog_data)
# Emit built DDEX event
await emit_event('ddex.generated', {
'xml': xml,
'platform': event.platform,
'catalog_id': event.catalog_id,
'size_bytes': len(xml)
})
except Exception as e:
await emit_event('ddex.build_failed', {
'error': str(e),
'catalog_id': event.catalog_id
})
Batch Processing Pipelines
Process large catalogs efficiently:
import { batchBuild } from 'ddex-builder';
async function processCatalogBatch(catalogItems: any[]) {
// Prepare build requests
const buildRequests = catalogItems.map(item => ({
messageId: `MSG_${item.id}`,
releases: item.releases,
resources: item.resources
}));
// Batch build with parallel processing
const results = await batchBuild(buildRequests, {
preset: 'generic_audio_album',
parallel: true,
maxConcurrency: 10
});
// Process results
results.forEach((result, index) => {
if (result.success) {
console.log(`✅ Built catalog ${catalogItems[index].id}: ${result.xml.length} bytes`);
saveToDisk(result.xml, `catalog_${catalogItems[index].id}.xml`);
} else {
console.error(`❌ Failed catalog ${catalogItems[index].id}:`, result.error);
}
});
}
Getting Started
Ready to start building DDEX files? Choose your path:
- Installation Guide - Set up the builder in your environment
- Quick Start - Build your first DDEX file in minutes
- API Reference - Complete API documentation
- Canonicalization - Deep dive into DB-C14N/1.0
- Presets - Platform-specific configurations
For complete workflows, combine with the DDEX Parser for parsing existing files and round-trip operations.