Validation
The DDEX Builder provides comprehensive validation to ensure your XML output meets DDEX specifications and partner requirements.
Overview
Validation occurs at multiple stages:
- Preflight validation: Before building begins
- Structure validation: During XML construction
- Schema validation: Against DDEX XSD schemas
- Partner validation: Using partner-specific rules
Preflight Validation
Validate your data before building to catch errors early:
import { DDEXBuilder, ValidationLevel } from 'ddex-builder';
const builder = new DDEXBuilder();
const data = { /* your release data */ };
// Comprehensive validation
const validation = await builder.validate(data, {
level: ValidationLevel.STRICT,
includeWarnings: true,
partnerPreset: 'spotify'
});
if (!validation.isValid) {
console.log('Validation errors:');
validation.errors.forEach(error => {
console.log(`- ${error.path}: ${error.message}`);
});
console.log('Warnings:');
validation.warnings.forEach(warning => {
console.log(`- ${warning.path}: ${warning.message}`);
});
}
Validation Levels
Basic Validation
from ddex_builder import DDEXBuilder, ValidationLevel
builder = DDEXBuilder()
# Basic validation - required fields only
result = builder.validate(data, level=ValidationLevel.BASIC)
Standard Validation
// Standard validation - DDEX specification compliance
const result = await builder.validate(data, {
level: ValidationLevel.STANDARD,
version: '4.3'
});
Strict Validation
# Strict validation - all rules + best practices
result = builder.validate(data,
level=ValidationLevel.STRICT,
enforce_best_practices=True
)
Partner-Specific Validation
Validate against partner requirements:
// Spotify validation
const spotifyValidation = await builder.validate(data, {
partnerPreset: 'spotify',
includeMetadataChecks: true
});
// YouTube Music validation
const youtubeValidation = await builder.validate(data, {
partnerPreset: 'youtube',
requireTerritoryInfo: true
});
// Apple Music validation
const appleValidation = await builder.validate(data, {
partnerPreset: 'apple',
enforceIsrcFormat: true
});
Custom Validation Rules
Add your own validation logic:
from ddex_builder import DDEXBuilder, ValidationRule
class CustomISRCRule(ValidationRule):
def validate(self, data):
errors = []
for track in data.get('tracks', []):
isrc = track.get('isrc')
if isrc and not self.is_valid_isrc(isrc):
errors.append({
'path': f'tracks[{track["id"]}].isrc',
'message': f'Invalid ISRC format: {isrc}',
'severity': 'error'
})
return errors
def is_valid_isrc(self, isrc):
# Your custom ISRC validation logic
return len(isrc) == 12 and isrc[:2].isalpha()
builder = DDEXBuilder()
builder.add_validation_rule(CustomISRCRule())
result = builder.validate(data)
Field-Level Validation
Required Fields
const validation = await builder.validate(data);
// Check specific field requirements
if (validation.missingRequired.length > 0) {
console.log('Missing required fields:');
validation.missingRequired.forEach(field => {
console.log(`- ${field.path}: ${field.description}`);
});
}
Data Type Validation
# Automatic type checking
data = {
'title': 123, # Should be string
'duration': 'invalid', # Should be number
'release_date': '2023-13-45' # Invalid date
}
result = builder.validate(data)
for error in result.type_errors:
print(f"{error.path}: expected {error.expected_type}, got {error.actual_type}")
Format Validation
use ddex_builder::{DDEXBuilder, ValidationOptions};
let options = ValidationOptions {
validate_isrc_format: true,
validate_upc_format: true,
validate_territory_codes: true,
validate_language_codes: true,
validate_currencies: true,
};
let result = builder.validate_with_options(&data, options)?;
Territory and Language Validation
const validation = await builder.validate(data, {
validateTerritories: true,
validateLanguages: true,
allowedTerritories: ['US', 'GB', 'DE'], // Restrict territories
requireLanguageForLyrics: true
});
// Check territory-specific errors
validation.territoryErrors.forEach(error => {
console.log(`Territory error: ${error.territory} - ${error.message}`);
});
Validation During Build
Enable validation during the build process:
builder = DDEXBuilder(
validate_on_build=True,
validation_level=ValidationLevel.STANDARD,
fail_on_warnings=False
)
try:
xml = builder.build(data)
print("Build successful with validation")
except ValidationError as e:
print(f"Validation failed: {e.message}")
for error in e.errors:
print(f" - {error.path}: {error.message}")
Batch Validation
Validate multiple releases efficiently:
const releases = [/* array of release data */];
const batchValidation = await builder.validateBatch(releases, {
parallel: true,
stopOnFirstError: false,
includeValidReleases: true
});
console.log(`Valid: ${batchValidation.valid.length}`);
console.log(`Invalid: ${batchValidation.invalid.length}`);
// Process valid releases
const validXml = await builder.buildBatch(batchValidation.valid);
Error Categories
Critical Errors
- Missing required fields
- Invalid data types
- Schema violations
- Partner requirement violations
Warnings
- Missing recommended fields
- Suboptimal formats
- Best practice violations
- Performance concerns
Info Messages
- Suggestions for improvement
- Alternative approaches
- Additional metadata opportunities
Validation Reports
Generate detailed validation reports:
validation = builder.validate(data, include_suggestions=True)
# Generate HTML report
report_html = validation.to_html_report()
with open('validation_report.html', 'w') as f:
f.write(report_html)
# Generate JSON report for API integration
report_json = validation.to_json()
# Generate CSV for spreadsheet analysis
report_csv = validation.to_csv()
Configuration
Customize validation behavior:
const builder = new DDEXBuilder({
validation: {
enabledRules: [
'required-fields',
'data-types',
'isrc-format',
'territory-codes'
],
customRules: [
new MyCustomRule(),
new AnotherRule()
],
errorThreshold: 10, // Stop after 10 errors
warningThreshold: 50, // Stop after 50 warnings
treatWarningsAsErrors: false
}
});
Performance Considerations
Validation performance tips:
- Use appropriate validation levels - Basic for development, Strict for production
- Enable parallel validation for batch processing
- Cache validation results for repeated builds
- Disable unused rules to improve performance
- Use incremental validation for large datasets
Best Practices
- Validate early and often - Don't wait until build time
- Use partner presets when targeting specific platforms
- Implement custom rules for organization-specific requirements
- Monitor validation metrics to identify common issues
- Provide clear error messages to help users fix issues
- Version your validation rules along with your data schemas
Common Validation Patterns
Pre-submission Validation
async function validateForSubmission(releaseData, targetPartner) {
const validation = await builder.validate(releaseData, {
level: ValidationLevel.STRICT,
partnerPreset: targetPartner,
includeMetadataQuality: true
});
if (!validation.isValid) {
throw new Error(`Release not ready for ${targetPartner}: ${validation.summary}`);
}
return validation;
}
Automated Quality Checks
def automated_quality_check(releases):
builder = DDEXBuilder()
results = []
for release in releases:
validation = builder.validate(release,
level=ValidationLevel.STANDARD,
include_quality_score=True
)
results.append({
'id': release['id'],
'valid': validation.is_valid,
'quality_score': validation.quality_score,
'recommendations': validation.recommendations
})
return results