xsd-lookup
v1.11.0
Published
Multi-schema XSD lookup utility
Maintainers
Readme
XSD schema validation for XML nodes, attributes and values
A comprehensive TypeScript-based XSD schema validation system for XML files, which provides nodes, attributes, and values validation against XSD schemas, including the strict hierarchical dependencies.
Developed to support scripting language validation in X4: Foundations game modding, but can be used for any XML validation needs, based on XSD schemas.
🎯 Features
- 🔍 XSD-Based Validation: Pure XSD schema validation without hardcoded logic
- 📊 Comprehensive Attribute Validation: Validates attribute existence, types, and values
- 🔧 Infrastructure Attribute Filtering: Automatically ignores XML namespace attributes (
xmlns,xmlns:*,xsi:*) - 🔗 Type Inheritance Support: Handles complex XSD type hierarchies and restrictions
- 🧩 Hierarchical Context: Getting list of possible child elements based on current element hierarchy
- 🔄 Previous Sibling Context: Optional previous sibling element name to filter results based on sequence constraints
- ⚡ Fast Child Validity Check: Direct API to check if a specific child is valid under a parent (with optional previous sibling)
- 🔀 Union Type Processing: Merges validation rules from multiple member types
- 📋 Enumeration Support: Complete enumeration value extraction and validation with annotations
- 🎯 SimpleType Enumeration Discovery: Extract enumeration values from named SimpleTypes, including union types
- 📏 Range Validation: Numeric and length constraint validation
- 🗂️ Multi-line Normalization: Handles multi-line XML attribute values correctly
- 📈 Performance Optimized: Caching and indexing for fast validation
- 🧰 Singleton Convenience: Use the exported
xsdReferenceinstance instead of creating your own
🚀 Quick Start
Installation
npm install xsd_lookup --saveBasic Usage
// ES6 imports (from TypeScript/modern JavaScript)
import { XsdReference } from 'xsd_lookup';
// Initialize the validation system
const xsdRef = new XsdReference();
xsdRef.init('./tests/data/xsd');
const schemaName = 'aiscripts';
const elementName = 'set_value';
const elementHierarchy = ['actions', 'attention', 'aiscript']; // bottom-up (parent -> root)
const elementDefinition = xsdRef.getElementDefinition(schemaName, elementName, elementHierarchy);
console.log(`Element ${elementName} is ${elementDefinition ? 'defined' : 'not defined'} in the schema.`);
// Returns Record<string, EnhancedAttributeInfo>
const elementAttributes = xsdRef.getElementAttributesWithTypes(schemaName, elementName, elementHierarchy);
console.log(`Element ${elementName} has ${Object.keys(elementAttributes).length} attributes.`);
// Static utilities operate on the attribute info map
const attributeValues = XsdReference.getAttributePossibleValues(elementAttributes, 'operation');
console.log(`Possible values for 'operation': ${Array.from(attributeValues.keys()).join(', ')}`);
const checkAttributeValue = XsdReference.validateAttributeValueAgainstRules(elementAttributes, 'operation', 'unknown');
console.log(`Attribute 'operation' value 'unknown' is ${checkAttributeValue.isValid ? 'valid' : 'invalid'}.`);
// Get enumeration values from SimpleType definitions
const classEnums = xsdRef.getSimpleTypeEnumerationValues('common', 'classlookup');
if (classEnums) {
console.log(`Found ${classEnums.values.length} class types: ${classEnums.values.slice(0, 3).join(', ')}...`);
}
// Clean up resources when done (optional but recommended)
xsdRef.dispose();Alternatively, use the singleton instance:
import { xsdReference } from 'xsd_lookup';
// Initialize once
xsdReference.init('./tests/data/xsd');
const elementName = 'set_value';
const elementHierarchy = ['actions', 'attention', 'aiscript'];
const elementDefinition = xsdReference.getElementDefinition('aiscripts', elementName, elementHierarchy);
const elementAttributes = xsdReference.getElementAttributesWithTypes('aiscripts', elementName, elementHierarchy); // Record<string, EnhancedAttributeInfo>
// Clean up when done
xsdReference.dispose();📖 API Reference
🏷️ Type Definitions
Exported Interfaces
// Location of a schema element definition
interface ElementLocation {
uri: string; // file:// URI to the XSD file
line: number; // 1-based
column: number; // 1-based
lengthOfStartTag: number; // number of characters in the element's start tag
}
// Enhanced attribute information with validation rules
interface EnhancedAttributeInfo {
name: string;
type?: string;
// Location packaged as a single object
location?: ElementLocation;
required?: boolean;
patterns?: string[];
enumValues?: string[];
enumValuesAnnotations?: Map<string, string>;
annotation?: string;
minLength?: number;
maxLength?: number;
minInclusive?: number;
maxInclusive?: number;
minExclusive?: number;
maxExclusive?: number;
}
// Attribute validation result
interface AttributeValidationResult {
isValid: boolean;
errorMessage?: string;
expectedType?: string;
restrictions?: string[];
allowedValues?: string[];
}
// Attribute name validation result
interface AttributeNameValidationResult {
wrongAttributes: string[];
missingRequiredAttributes: string[];
}Notes:
- Methods returning attribute info use an object map keyed by attribute name: Record<string, EnhancedAttributeInfo>.
🏷️ Input parameters
schemaName: Name of the schema to operate on (e.g., 'aiscripts'). Equal to the XSD file name without extension.elementName: Name of the XML element to validate (e.g., 'do_if').attributeName: Name of the attribute to validate (e.g., 'value').value: The value to validate against the attribute's XSD rules (e.g., 'player.money gt 1000').hierarchy: Parameter to specify the hierarchy of elements in bottom-up order (from immediate parent to root element) in XML-file. This is crucial for correct validation context.
🏗️ Hierarchy Parameter Usage
Important: All methods that accept a hierarchy parameter expect it in bottom-up order (from immediate parent to root element).
Hierarchy Examples
// For XML structure:
// <aiscript>
// <attention>
// <actions>
// <do_if value="$condition">
// <debug_text text="message" />
// </do_if>
// <set_value name="$value" exact="100" />
// </actions>
// </attention>
// </aiscript>
// For 'do_if' element:
const doIfHierarchy = ['actions', 'attention', 'aiscript'];
// For 'debug_text' element:
const debugTextHierarchy = ['do_if', 'actions', 'attention', 'aiscript'];
// Usage:
const attributes = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', doIfHierarchy);
const validation = xsdRef.validateAttributeValue('aiscripts', 'debug_text', 'text', 'Hello', debugTextHierarchy);XsdReference Class
The main entry point for any operations.
Constructor
new XsdReference()init(xsdDirectory: string): void
Initialize or reinitialize the instance with the directory that contains your .xsd files. This clears any previously loaded schemas.
const xsdRef = new XsdReference();
xsdRef.init('./tests/data/xsd');Singleton instance
You can also use a ready-to-use singleton and avoid manual instantiation.
import { xsdReference } from 'xsd_lookup';
xsdReference.init('./tests/data/xsd');
// Then call API methods on xsdReference
const children = xsdReference.getPossibleChildElements('aiscripts', 'actions', ['attention', 'aiscript']);Core Methods
getSchema(schemaName: string): Schema | null
Load and return a schema by name.
const schema = xsdRef.getSchema('aiscripts');getAvailableSchemas(): string[]
Get all currently loaded schema types.
const loadedSchemas: string[] = xsdRef.getAvailableSchemas();
// Returns: ['aiscripts', 'md'] (schemas that are currently loaded in memory)getDiscoverableSchemas(): string[]
Get all discoverable schema files in the XSD directory.
const availableSchemas: string[] = xsdRef.getDiscoverableSchemas();
// Returns: ['aiscripts', 'common', 'md'] (all .xsd files found in directory, without extension)getElementDefinition(schemaName: string, elementName: string, hierarchy?: string[]): Element | undefined
Get the element definition for a specific element in a schema, considering hierarchy context.
Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).
// For element structure: <aiscript><attention><actions><set_value>
// Hierarchy for 'set_value' element should be: ['actions', 'attention', 'aiscript']
const elementDef = xsdRef.getElementDefinition('aiscripts', 'set_value', ['actions', 'attention', 'aiscript']);
// Returns: Element definition object or undefined if not foundgetElementAttributes(schemaName: string, elementName: string, hierarchy?: string[]): Record<string, Element>
Get basic attribute elements for an element as a map of attribute name to the defining Element node.
Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).
// For element structure: <aiscript><attention><actions><set_value>
// Hierarchy for 'set_value' element should be: ['actions', 'attention', 'aiscript']
const attributes: Record<string, Element> = xsdRef.getElementAttributes('aiscripts', 'set_value', ['actions', 'attention', 'aiscript']);
// Returns Record<string, EnhancedAttributeInfo> keyed by attribute name:
// {
// name: Element, // DOM element reference to xs:attribute definition
// value: Element,
// ...
// }getElementAttributesWithTypes(schemaName: string, elementName: string, hierarchy?: string[], elementDef?: Element): Record<string, EnhancedAttributeInfo>
Get all attributes for an element with complete type information including:
- Type name
- Required status
- Enumeration values (if applicable)
- Pattern restrictions
- Numeric/length constraints
- Attribute definition location (file URI, line, column, lengthOfStartTag)
- Attribute annotation text (if available)
Performance tip: You can pass an optional elementDef (from getElementDefinition) to avoid re-resolving the element in the schema.
Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).
// For element structure: <aiscript><attention><actions><do_if>
// Hierarchy for 'do_if' element should be: ['actions', 'attention', 'aiscript']
const attributes = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
// Returns Record<string, EnhancedAttributeInfo> keyed by attribute name:
// {
// value: {
// name: 'value',
// type: 'expression',
// required: true,
// patterns: ['[pattern regex]'],
// enumValues: undefined,
// annotation: 'Description text...'(optional),
// location: {
// uri: 'file:///C:/path/to/aiscripts.xsd',
// line: 123,
// column: 5,
// lengthOfStartTag: 42
// }
// }
// }validateAttributeValue(schemaName: string, elementName: string, attributeName: string, value: string, hierarchy?: string[]): AttributeValidationResult
Validate an attribute value against XSD constraints.
Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).
// For element structure: <aiscript><attention><actions><do_if><debug_text>
// Hierarchy for 'debug_text' element should be: ['do_if', 'actions', 'attention', 'aiscript']
const result: AttributeValidationResult = xsdRef.validateAttributeValue('aiscript', 'debug_text', 'chance', '50', ['do_if', 'actions', 'attention', 'aiscript']);
// Returns:
// {
// isValid: true,
// expectedType: 'expression',
// restrictions: ['Pattern: ...']
// }getPossibleChildElements(schemaName: string, elementName: string, hierarchy?: string[], previousSibling?: string): Map<string, string>
Get possible child elements for a given element, with their annotation text.
Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).
Important: The previousSibling parameter can be used to filter results based on sequence constraints (e.g., if the element must come after a specific sibling).
// For element structure: <aiscript><attention><actions>
// Get possible children of 'actions' element
const children: Map<string, string> = xsdRef.getPossibleChildElements('aiscripts', 'actions', ['attention', 'aiscript']);
// Returns: Map where key is child element name, value is annotation text
// Example: Map { 'do_if' => 'Conditional execution', 'do_while' => 'Loop execution', ... }
// Usage examples:
if (children.size > 0) {
console.log('Possible child elements:');
for (const [elementName, annotation] of children) {
console.log(` ${elementName}: ${annotation || '(no description)'}`);
}
}isValidChild(schemaName: string, elementName: string, parentName: string, parentHierarchy?: string[], previousSibling?: string): boolean
Check if a specific element is valid as a child of a given parent in the provided hierarchy, using the same engine and sequence/choice constraints as getPossibleChildElements, but without building the full child set.
Important: The parentHierarchy parameter should be provided in bottom-up order (from immediate parent to root element).
Important: The optional previousSibling parameter narrows the check to respect sequence constraints within the parent’s content model.
// Validate if 'do_else' can follow 'do_if' inside <actions>
const ok = xsdRef.isValidChild(
'aiscripts',
'do_else',
'actions',
['attention', 'aiscript'],
'do_if'
);
console.log('do_else after do_if is', ok ? 'allowed' : 'not allowed');
// Check if 'do_if' can start under <actions> (no previousSibling)
const canStart = xsdRef.isValidChild('aiscripts', 'do_if', 'actions', ['attention', 'aiscript']);
console.log('do_if at start of <actions> is', canStart ? 'allowed' : 'not allowed');getSimpleTypesWithBaseType(schemaName: string, baseType: string): string[]
Get all simple types that use a specific type as their base.
// Find all simple types based on 'lvalueexpression'
const derivedTypes: string[] = xsdRef.getSimpleTypesWithBaseType('aiscripts', 'lvalueexpression');
// Returns: ['expression', 'objectref', 'paramname', ...] (types that extend lvalueexpression)
// Find all types based on xs:string
const stringTypes: string[] = xsdRef.getSimpleTypesWithBaseType('common', 'xs:string');
// Returns: ['name', 'comment', 'text', ...] (string-based types)getSimpleTypeEnumerationValues(schemaName: string, simpleTypeName: string): { values: string[], annotations: Map<string, string> } | null
Get enumeration values for a named SimpleType, including support for union types.
Union Type Support: This method properly handles union types by extracting enumeration values from all member types and combining them into a single result.
// Get enumeration values from a simple enumeration type
const quadrantResult = xsdRef.getSimpleTypeEnumerationValues('common', 'quadrantlookup');
// Returns:
// {
// values: ['quadrant.none', 'quadrant.front', 'quadrant.back'],
// annotations: Map {
// 'quadrant.none' => 'No specific quadrant',
// 'quadrant.front' => 'Front quadrant',
// 'quadrant.back' => 'Back quadrant'
// }
// }
// Get enumeration values from a union type (combines multiple enumerations)
const classResult = xsdRef.getSimpleTypeEnumerationValues('common', 'classlookup');
// Returns:
// {
// values: ['class.component', 'class.buildprocessor', 'class.ship', 'class.station', ...],
// annotations: Map {
// 'class.component' => 'Component',
// 'class.buildprocessor' => 'Build processor',
// 'class.ship' => 'Ship',
// // ... 80+ values from union of 'positionalclasslookup' and 'expression' types
// }
// }
// Handle non-existent or non-enumeration types
const nonExistent = xsdRef.getSimpleTypeEnumerationValues('common', 'nonexistent');
// Returns: null
// Usage example:
if (classResult) {
console.log(`Found ${classResult.values.length} enumeration values`);
for (const value of classResult.values) {
const annotation = classResult.annotations.get(value);
console.log(` ${value}: ${annotation || '(no description)'}`);
}
// Check if a specific value exists
if (classResult.values.includes('class.ship')) {
console.log('class.ship is a valid enumeration value');
}
}dispose(): void
Clear all internal caches to release resources.
// Get a schema instance
const schema = xsdRef.getSchema('aiscripts');
// Use the schema for validation...
const result = schema.validateAttributeValue('do_if', 'value', 'condition');
// Clean up schema resources when done
schema.dispose();Note: Not recommended for frequent use in performance-sensitive scenarios.
Static Methods
XsdReference.getElementLocation(element: Element): ElementLocation
Get the source file URI and 1-based position for a schema element definition.
// Obtain an element definition first
const def = xsdRef.getElementDefinition('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
if (def) {
const loc = XsdReference.getElementLocation(def);
// Example output: file:///C:/path/to/tests/data/xsd/aiscripts.xsd:123:5
console.log(`${loc.uri}:${loc.line}:${loc.column}`);
// Start tag length is also available when you need precise range handling
// console.log('start tag length:', loc.lengthOfStartTag);
}Notes:
- uri is a file:// URI pointing to the XSD file that defined the element.
- line and column are 1-based positions within that file.
- lengthOfStartTag is the character length of the element’s start tag (from '<' to the matching '>').
XsdReference.validateAttributeNames(attributeInfos: Record<string, EnhancedAttributeInfo>, providedAttributes: string[]): AttributeNameValidationResult
Validate attribute names against schema definitions. This static method checks which attributes are valid and identifies missing required attributes.
🔧 Infrastructure Attribute Handling: XML infrastructure attributes (xmlns, xmlns:*, xsi:*) are automatically filtered out before validation.
// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
const providedAttrs = ['value', 'chance', 'xmlns:xsi', 'invalid_attr'];
const nameValidation: AttributeNameValidationResult = XsdReference.validateAttributeNames(attributeInfos, providedAttrs);
// Returns:
// {
// wrongAttributes: ['invalid_attr'], // Infrastructure attrs filtered out
// missingRequiredAttributes: ['negate', ...] // Required attributes missing
// }
// Note: 'xmlns:xsi' is ignored and doesn't appear in wrongAttributesXsdReference.validateAttributeValueAgainstRules(attributeInfos: Record<string, EnhancedAttributeInfo>, attributeName: string, attributeValue: string)
Validate an attribute value against all XSD rules (patterns, enumerations, ranges, etc.). This static method provides detailed validation with rule violation information.
🔧 Infrastructure Attribute Handling: XML infrastructure attributes (xmlns, xmlns:*, xsi:*) are automatically ignored and always return { isValid: true }.
// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
const valueValidation = XsdReference.validateAttributeValueAgainstRules(
attributeInfos,
'value',
'player.money gt 1000'
);
// Returns:
// {
// isValid: true,
// errorMessage: undefined, // Only present if invalid
// violatedRules: undefined // Only present if invalid - array of specific rule violations
// }
// Example with invalid value:
const invalidValidation = XsdReference.validateAttributeValueAgainstRules(
attributeInfos,
'chance',
'150'
);
// Returns:
// {
// isValid: false,
// errorMessage: "Value must be <= 100",
// violatedRules: ["Value must be <= 100"]
// }
// Infrastructure attributes are ignored:
const infraValidation = XsdReference.validateAttributeValueAgainstRules(
attributeInfos,
'xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance'
);
// Returns:
// {
// isValid: true
// }XsdReference.getAttributePossibleValues(attributeInfos: Record<string, EnhancedAttributeInfo>, attributeName: string): Map<string, string>
Get all possible enumeration values for an attribute, if it has enumeration restrictions.
🔧 Infrastructure Attribute Handling: XML infrastructure attributes always return an empty Map.
// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'set_value', ['actions', 'attention', 'aiscript']);
const possibleValues: Map<string, string> = XsdReference.getAttributePossibleValues(attributeInfos, 'operator');
// Returns: Map<string, string> where key is enum value, value is annotation
// Example: Map { 'set' => 'Set value', 'add' => 'Add to value', 'subtract' => 'Subtract from value', ... }
// Returns: Map() (empty map if no enumeration exists or if it's an infrastructure attribute)
// Usage examples:
if (possibleValues.size > 0) {
console.log('Available values:');
for (const [value, annotation] of possibleValues) {
console.log(` ${value}: ${annotation || '(no description)'}`);
}
// Get just the values as an array
const valueArray = Array.from(possibleValues.keys());
console.log('Values only:', valueArray); // ['set', 'add', 'subtract', 'insert']
}XsdReference.filterAttributesByType(attributeInfos: Record<string, EnhancedAttributeInfo>, attributeType: string): string[]
Filter attributes by their XSD type (e.g., 'xs:string', 'xs:int', 'expression').
🔧 Infrastructure Attribute Handling: XML infrastructure attributes are automatically excluded from results.
// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
const stringAttributes: string[] = XsdReference.filterAttributesByType(attributeInfos, 'xs:string');
// Returns: ['comment', 'name'] (example - attributes with xs:string type)
const expressionAttributes: string[] = XsdReference.filterAttributesByType(attributeInfos, 'expression');
// Returns: ['value', 'chance'] (example - attributes with expression type)XsdReference.filterAttributesByRestriction(attributeInfos: Record<string, EnhancedAttributeInfo>, restrictionType: 'enumeration' | 'pattern' | 'length' | 'range'): string[]
Filter attributes by the type of XSD restriction they have.
🔧 Infrastructure Attribute Handling: XML infrastructure attributes are automatically excluded from results.
// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
const enumAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'enumeration');
// Returns: ['operator', 'type'] (example - attributes with enumeration restrictions)
const patternAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'pattern');
// Returns: ['ref', 'name'] (example - attributes with pattern restrictions)
const rangeAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'range');
// Returns: ['min', 'max'] (example - attributes with numeric range restrictions)
const lengthAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'length');
// Returns: ['text'] (example - attributes with length restrictions)extractAnnotationText(schemaName: string, element: Element): string | undefined (instance)
Extract annotation text from an XML element in the context of a specific schema. This is used by the test runner to track annotation coverage and is also available for consumers.
// This is typically used internally, but can be useful for custom schema processing
const element: Element = /* DOM element from XSD */;
const annotation: string | undefined = xsdRef.extractAnnotationText('aiscripts', element);
// Returns: "Description text from xs:annotation/xs:documentation" or undefined
// Example usage with element definitions:
const elementDef = xsdRef.getElementDefinition('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
if (elementDef) {
const description = xsdRef.extractAnnotationText('aiscripts', elementDef);
console.log('Element description:', description || 'No description available');
}Typical Validation Workflow
// 1. Get schema and attribute info once
const xsdRef = new XsdReference();
xsdRef.init('./tests/data/xsd');
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
// 2. Validate attribute names (fast, no schema lookup needed)
// Infrastructure attributes (xmlns, xsi:) are automatically filtered out
const nameValidation: AttributeNameValidationResult = XsdReference.validateAttributeNames(attributeInfos, ['value', 'xmlns:xsi', 'invalid_attr']);
if (nameValidation.wrongAttributes.length > 0) {
console.error('Invalid attributes:', nameValidation.wrongAttributes); // Only shows 'invalid_attr'
}
// 3. Validate attribute values (fast, no schema lookup needed)
// Infrastructure attributes automatically return { isValid: true }
for (const attrName of Object.keys(attributeInfos)) {
const valueValidation = XsdReference.validateAttributeValueAgainstRules(
attributeInfos,
attrName,
attributeValue
);
if (!valueValidation.isValid) {
console.error(`Invalid value for ${attrName}:`, valueValidation.violatedRules);
}
}
// 4. Use helper methods to analyze attributes by type or restriction
const enumAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'enumeration');
const possibleValues: Map<string, string> = XsdReference.getAttributePossibleValues(attributeInfos, 'operator');
// Work with possible values Map
if (possibleValues.size > 0) {
console.log('Operator values:', Array.from(possibleValues.keys()));
// Check if a specific value is valid
if (possibleValues.has('eq')) {
console.log('eq annotation:', possibleValues.get('eq') || '(no description)');
}
}
// Alternatively, using the singleton
// import { xsdReference } from 'xsd_lookup';
// xsdReference.init('./tests/data/xsd');
// const attributeInfos = xsdReference.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);Schema Class
There is a main engine for validating XML files against XSD schemas. It provides detailed validation capabilities for a specific XSD schema.
Note: Not recommended to use directly, prefer using XsdReference for schema management.
XsdDetector Class
Automatically detects the appropriate XSD schema for XML files.
getSchemaName(xmlFilePath: string): string | null
Detect schema name from XML file path and content.
const schemaName = XsdDetector.getSchemaName('./scripts/my-script.xml');
// Returns: 'aiscripts'� Infrastructure Attribute Handling
The validation system automatically handles XML infrastructure attributes to focus validation on content-relevant attributes:
What are Infrastructure Attributes?
Infrastructure attributes are XML namespace and schema-related attributes that are part of the XML specification itself, not your content:
xmlns- Default namespace declarationxmlns:*- Namespace prefix declarations (e.g.,xmlns:xsi)xsi:*- XML Schema Instance attributes (e.g.,xsi:schemaLocation)
Automatic Filtering
All static validation methods automatically filter out infrastructure attributes:
<!-- Example XML with infrastructure attributes -->
<do_if value="player.money gt 1000"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="..."
chance="50">
<!-- content -->
</do_if>// Only 'value' and 'chance' are validated; xmlns/xsi attributes are ignored
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', hierarchy);
const nameValidation = XsdReference.validateAttributeNames(
attributeInfos,
['value', 'chance', 'xmlns:xsi', 'xsi:schemaLocation']
);
// Result: { wrongAttributes: [], missingRequiredAttributes: [] }
// Infrastructure attributes don't appear in wrongAttributes
const valueValidation = XsdReference.validateAttributeValueAgainstRules(
attributeInfos,
'xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance'
);
// Result: { isValid: true } - Infrastructure attributes always pass🔧 Development
Project Structure
├── src/ # TypeScript source files
│ ├── Schema.ts # Core validation engine
│ ├── XsdReference.ts # Main API interface
│ └── XsdDetector.ts # Schema auto-detection
├── dist/ # Compiled JavaScript output
├── tests/ # Comprehensive test suite
│ ├── data/ # Test data and schemas
│ │ ├── xsd/ # XSD schema definitions
│ │ ├── aiscripts/ # AI script test files
│ │ └── md/ # Mission director test files
│ └── test_all_files_comprehensive.js
├── package.json # Project configuration
└── tsconfig.json # TypeScript configuration📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- X4 Foundations by Egosoft for the complex and rich modding system
- XML Schema (XSD) specification for comprehensive validation standards
- TypeScript and Node.js ecosystem for excellent development tools
Performance Tips
- Reuse
XsdReferenceinstances when validating multiple files with the same schemas - Call
dispose()only when completely finished with validation tasks - Use static methods (
XsdReference.validateAttributeNames, etc.) for batch operations with pre-fetched attribute info
