CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xml2js

Simple XML to JavaScript object converter.

Overview
Eval results
Files

configuration.mddocs/

Configuration

Default configuration presets and validation error handling for different API versions and usage patterns.

Capabilities

Default Configuration Presets

The defaults module provides version-specific configuration presets that match different API behaviors and compatibility levels.

const defaults: {
  "0.1": DefaultOptions;
  "0.2": DefaultOptions;
};

interface DefaultOptions {
  explicitArray: boolean;
  ignoreAttrs: boolean;
  mergeAttrs: boolean;
  normalize: boolean;
  normalizeTags: boolean;
  attrkey: string;
  charkey: string;
  explicitCharkey: boolean;
  trim: boolean;
  explicitRoot: boolean;
  emptyTag: string;
  strict: boolean;
}

Usage Examples:

const xml2js = require('xml2js');

// Access default configurations
console.log(xml2js.defaults['0.1']);
console.log(xml2js.defaults['0.2']);

// Use version-specific defaults
const parser01 = new xml2js.Parser(xml2js.defaults['0.1']);
const parser02 = new xml2js.Parser(xml2js.defaults['0.2']);

// Extend defaults with custom options
const customOptions = Object.assign({}, xml2js.defaults['0.2'], {
  trim: true,
  parseNumbers: true,
  tagNameProcessors: [xml2js.processors.firstCharLowerCase]
});

const customParser = new xml2js.Parser(customOptions);

Version 0.1 Defaults

Legacy configuration preset for backwards compatibility with older xml2js behavior.

const version01Defaults: {
  explicitArray: false;
  ignoreAttrs: false;
  mergeAttrs: false;
  normalize: true;
  normalizeTags: false;
  attrkey: "@";
  charkey: "#";
  explicitCharkey: false;
  trim: true;
  explicitRoot: false;
  emptyTag: "";
  strict: true;
  validator: null;
  xmlns: false;
  explicitChildren: false;
  childkey: "@@";
  charsAsChildren: false;
  includeWhiteChars: false;
  async: false;
  attrNameProcessors: null;
  attrValueProcessors: null;
  tagNameProcessors: null;
  valueProcessors: null;
};

Characteristics of Version 0.1:

  • explicitArray: false - Single child elements are not wrapped in arrays
  • ignoreAttrs: false - XML attributes are preserved
  • normalize: true and trim: true - Text processing enabled by default
  • explicitRoot: false - Root element not wrapped in result
  • Different attribute/character keys: @ for attributes, # for character content

Usage Examples:

const xml2js = require('xml2js');

// Parser with 0.1 defaults
const legacyParser = new xml2js.Parser(xml2js.defaults['0.1']);

const xmlString = '<person name="John"><age>30</age></person>';
legacyParser.parseString(xmlString, (err, result) => {
  if (!err) {
    console.log(result);
    // With 0.1 defaults: { person: { '@': { name: 'John' }, age: '30' } }
    // Note: attributes preserved with @ key, no root wrapper
  }
});

Version 0.2 Defaults

Current default configuration providing more comprehensive XML handling with attribute support.

const version02Defaults: {
  explicitArray: true;
  ignoreAttrs: false;
  mergeAttrs: false;
  normalize: false;
  normalizeTags: false;
  attrkey: "$";
  charkey: "_";
  explicitCharkey: false;
  trim: false;
  explicitRoot: true;
  emptyTag: "";
  strict: true;
  validator: null;
  xmlns: false;
  explicitChildren: false;
  preserveChildrenOrder: false;
  childkey: "$$";
  charsAsChildren: false;
  includeWhiteChars: false;
  async: false;
  attrNameProcessors: null;
  attrValueProcessors: null;
  tagNameProcessors: null;
  valueProcessors: null;
  rootName: "root";
  xmldec: {
    version: "1.0";
    encoding: "UTF-8";
    standalone: true;
  };
  doctype: null;
  renderOpts: {
    pretty: true;
    indent: "  ";
    newline: "\n";
  };
  headless: false;
  chunkSize: 10000;
  cdata: false;
};

Characteristics of Version 0.2:

  • explicitArray: true - All child elements are wrapped in arrays for consistency
  • ignoreAttrs: false - XML attributes are preserved and accessible
  • More predictable structure for programmatic processing

Usage Examples:

const xml2js = require('xml2js');

// Parser with 0.2 defaults (current default)
const modernParser = new xml2js.Parser(xml2js.defaults['0.2']);

const xmlString = '<person name="John"><age>30</age></person>';
modernParser.parseString(xmlString, (err, result) => {
  if (!err) {
    console.log(result);
    // With 0.2 defaults: { person: { $: { name: 'John' }, age: ['30'] } }
    // Note: attributes preserved, age is an array
  }
});

Custom Configuration Patterns

const xml2js = require('xml2js');

// Web API friendly configuration
const webApiConfig = Object.assign({}, xml2js.defaults['0.2'], {
  explicitArray: false,  // Simpler structure
  mergeAttrs: true,      // Merge attributes with content
  trim: true,            // Clean whitespace
  tagNameProcessors: [xml2js.processors.firstCharLowerCase],
  valueProcessors: [xml2js.processors.parseNumbers, xml2js.processors.parseBooleans]
});

// Configuration for processing RSS/Atom feeds
const feedConfig = Object.assign({}, xml2js.defaults['0.2'], {
  explicitArray: false,
  trim: true,
  normalize: true,
  tagNameProcessors: [xml2js.processors.normalize],
  valueProcessors: [xml2js.processors.parseNumbers]
});

// Configuration for SOAP/XML services
const soapConfig = Object.assign({}, xml2js.defaults['0.2'], {
  explicitArray: false,
  tagNameProcessors: [xml2js.processors.stripPrefix],
  xmlns: true,  // Preserve namespace information
  explicitRoot: false
});

ValidationError Class

Custom error class for XML validation and parsing failures, extending the standard JavaScript Error class.

/**
 * Custom error class for XML validation failures
 */
class ValidationError extends Error {
  /**
   * Create a ValidationError
   * @param message - Error message describing the validation failure
   */
  constructor(message: string);
}

Usage Examples:

const xml2js = require('xml2js');

// ValidationError is thrown for validation failures
const parser = new xml2js.Parser({
  validator: (xpath, currentValue, newValue) => {
    // Custom validation logic
    if (xpath === '/product/price' && isNaN(parseFloat(newValue))) {
      throw new xml2js.ValidationError(`Invalid price value: ${newValue}`);
    }
    return newValue;
  }
});

const invalidXml = '<product><price>not-a-number</price></product>';

parser.parseString(invalidXml, (err, result) => {
  if (err instanceof xml2js.ValidationError) {
    console.error('Validation failed:', err.message);
    // Handle validation error specifically
  } else if (err) {
    console.error('Parse error:', err.message);
    // Handle other parsing errors
  } else {
    console.log('Parse successful:', result);
  }
});

// Using with promises
async function parseWithValidation(xmlString) {
  try {
    const result = await parser.parseStringPromise(xmlString);
    return result;
  } catch (error) {
    if (error instanceof xml2js.ValidationError) {
      console.error('Validation error:', error.message);
      throw new Error(`XML validation failed: ${error.message}`);
    }
    throw error;
  }
}

Custom Validation with ValidationError

const xml2js = require('xml2js');

// Complex validation example
function createValidatingParser(schema) {
  return new xml2js.Parser({
    validator: (xpath, currentValue, newValue) => {
      const rule = schema[xpath];
      if (rule) {
        // Type validation
        if (rule.type === 'number' && isNaN(parseFloat(newValue))) {
          throw new xml2js.ValidationError(`Expected number at ${xpath}, got: ${newValue}`);
        }
        
        // Range validation
        if (rule.type === 'number' && rule.min !== undefined) {
          const numValue = parseFloat(newValue);
          if (numValue < rule.min) {
            throw new xml2js.ValidationError(`Value ${numValue} at ${xpath} is below minimum ${rule.min}`);
          }
        }
        
        // String length validation
        if (rule.type === 'string' && rule.maxLength !== undefined) {
          if (newValue.length > rule.maxLength) {
            throw new xml2js.ValidationError(`String at ${xpath} exceeds maximum length ${rule.maxLength}`);
          }
        }
        
        // Required field validation
        if (rule.required && (!newValue || newValue.trim() === '')) {
          throw new xml2js.ValidationError(`Required field ${xpath} is empty`);
        }
      }
      
      return newValue;
    }
  });
}

// Define validation schema
const productSchema = {
  '/product/id': { type: 'number', required: true, min: 1 },
  '/product/name': { type: 'string', required: true, maxLength: 100 },
  '/product/price': { type: 'number', required: true, min: 0 },
  '/product/description': { type: 'string', maxLength: 500 }
};

const validatingParser = createValidatingParser(productSchema);

// Test with valid XML
const validXml = `
  <product>
    <id>123</id>
    <name>Laptop</name>
    <price>999.99</price>
    <description>High-performance laptop</description>
  </product>
`;

// Test with invalid XML
const invalidXml = `
  <product>
    <id>0</id>
    <name></name>
    <price>-100</price>
    <description>${'x'.repeat(600)}</description>
  </product>
`;

validatingParser.parseString(validXml, (err, result) => {
  if (err instanceof xml2js.ValidationError) {
    console.error('Validation failed:', err.message);
  } else if (!err) {
    console.log('Valid XML parsed successfully');
  }
});

Configuration Best Practices

Choosing the Right Defaults

const xml2js = require('xml2js');

// For simple XML consumption (e.g., configuration files)
const simpleConfig = xml2js.defaults['0.1']; // No arrays, ignores attributes

// For comprehensive XML processing (e.g., APIs, complex documents)  
const comprehensiveConfig = xml2js.defaults['0.2']; // Preserves structure

// For web applications (JSON-like structure)
const webConfig = Object.assign({}, xml2js.defaults['0.2'], {
  explicitArray: false,
  mergeAttrs: true
});

Performance Considerations

const xml2js = require('xml2js');

// High-performance parsing for large documents
const performanceConfig = {
  // Minimal processing
  explicitArray: false,
  ignoreAttrs: true,
  trim: false,
  normalize: false,
  
  // No text processors to avoid overhead
  tagNameProcessors: null,
  valueProcessors: null,
  
  // Async processing for large documents
  async: true,
  chunkSize: 50000
};

// Memory-efficient parsing
const memoryEfficientConfig = {
  explicitArray: false,
  explicitRoot: false,
  trim: true,
  emptyTag: null, // Don't create empty values
  strict: false   // More lenient parsing
};

Error Handling Strategies

const xml2js = require('xml2js');

// Comprehensive error handling
function createRobustParser(options = {}) {
  const defaultOptions = Object.assign({}, xml2js.defaults['0.2'], {
    // Enable strict validation
    strict: true,
    
    // Custom validator for business logic
    validator: (xpath, currentValue, newValue) => {
      try {
        // Apply custom validation rules here
        return newValue;
      } catch (validationError) {
        throw new xml2js.ValidationError(`Validation failed at ${xpath}: ${validationError.message}`);
      }
    }
  }, options);
  
  return new xml2js.Parser(defaultOptions);
}

// Usage with comprehensive error handling
async function safeParseXML(xmlString, options) {
  const parser = createRobustParser(options);
  
  try {
    const result = await parser.parseStringPromise(xmlString);
    return { success: true, data: result };
  } catch (error) {
    if (error instanceof xml2js.ValidationError) {
      return {
        success: false,
        error: 'validation',
        message: error.message
      };
    } else {
      return {
        success: false,
        error: 'parsing',
        message: error.message
      };
    }
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-xml2js

docs

building.md

configuration.md

index.md

parsing.md

processing.md

tile.json