CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xmldom

A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.

Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Robust error handling system with DOMException classes, configurable parsing error handlers, detailed error reporting, and comprehensive error code support following W3C DOM specifications.

Capabilities

DOMException Class

The DOMException class represents errors that occur during DOM operations, providing specific error codes and descriptive messages.

/**
 * W3C DOMException class for DOM operation errors
 */
class DOMException extends Error {
  /**
   * Creates a new DOMException
   * @param code The error code constant
   * @param message Optional additional error message
   */
  constructor(code: number, message?: string);
  
  /**
   * The error code indicating the type of error
   */
  readonly code: number;
  
  /**
   * Error message describing the exception
   */
  readonly message: string;
  
  // Error code constants
  static readonly INDEX_SIZE_ERR: 1;
  static readonly DOMSTRING_SIZE_ERR: 2;
  static readonly HIERARCHY_REQUEST_ERR: 3;
  static readonly WRONG_DOCUMENT_ERR: 4;
  static readonly INVALID_CHARACTER_ERR: 5;
  static readonly NO_DATA_ALLOWED_ERR: 6;
  static readonly NO_MODIFICATION_ALLOWED_ERR: 7;
  static readonly NOT_FOUND_ERR: 8;
  static readonly NOT_SUPPORTED_ERR: 9;
  static readonly INUSE_ATTRIBUTE_ERR: 10;
  static readonly INVALID_STATE_ERR: 11;
  static readonly SYNTAX_ERR: 12;
  static readonly INVALID_MODIFICATION_ERR: 13;
  static readonly NAMESPACE_ERR: 14;
  static readonly INVALID_ACCESS_ERR: 15;
}

Usage Examples:

const { DOMParser, DOMException } = require('xmldom');
const parser = new DOMParser();
const doc = parser.parseFromString('<root></root>', 'text/xml');

try {
  // Attempt invalid DOM operation
  const element = doc.createElement('test');
  const otherDoc = parser.parseFromString('<other></other>', 'text/xml');
  
  // This will throw WRONG_DOCUMENT_ERR
  element.appendChild(otherDoc.documentElement);
} catch (error) {
  if (error instanceof DOMException) {
    console.log(`DOM Error Code: ${error.code}`);
    console.log(`Error Type: ${error.name}`);
    console.log(`Message: ${error.message}`);
    
    switch (error.code) {
      case DOMException.WRONG_DOCUMENT_ERR:
        console.log('Attempted to use node from different document');
        break;
      case DOMException.HIERARCHY_REQUEST_ERR:
        console.log('Invalid node hierarchy operation');
        break;
      case DOMException.INVALID_CHARACTER_ERR:
        console.log('Invalid character in name');
        break;
      default:
        console.log('Other DOM exception');
    }
  }
}

// Examples of operations that throw specific exceptions
try {
  doc.createElement('invalid name with spaces'); // INVALID_CHARACTER_ERR
} catch (e) {
  console.log(`Invalid character error: ${e.code}`);
}

try {
  const element = doc.createElement('test');
  element.removeChild(doc.createElement('notAChild')); // NOT_FOUND_ERR
} catch (e) {
  console.log(`Not found error: ${e.code}`);
}

Parse Error Handling

Configurable error handling during XML parsing with support for warnings, errors, and fatal errors.

/**
 * Error handler configuration for DOMParser
 */
interface ErrorHandler {
  /**
   * Handle non-fatal warnings during parsing
   * @param message Warning message
   */
  warning?: (message: string) => void;
  
  /**
   * Handle recoverable errors during parsing
   * @param message Error message
   */
  error?: (message: string) => void;
  
  /**
   * Handle fatal errors that stop parsing
   * @param message Fatal error message
   */
  fatalError?: (message: string) => void;
}

/**
 * Alternative function-based error handler
 * @param level The error level ('warning', 'error', or 'fatalError')
 * @param message The error message
 */
type ErrorHandlerFunction = (level: string, message: string) => void;

/**
 * ParseError class for XML parsing errors with location information
 */
class ParseError extends Error {
  constructor(message: string, locator?: object);
  readonly name: 'ParseError';
}

Usage Examples:

const { DOMParser } = require('xmldom');

// Collect all parsing issues
const issues = [];
const parser = new DOMParser({
  errorHandler: {
    warning: function(msg) {
      issues.push({ level: 'warning', message: msg });
    },
    error: function(msg) {
      issues.push({ level: 'error', message: msg });
    },
    fatalError: function(msg) {
      issues.push({ level: 'fatal', message: msg });
      throw new Error(`Fatal XML Error: ${msg}`);
    }
  }
});

// Parse problematic XML
try {
  const doc = parser.parseFromString(`
    <root>
      <unclosed-tag>
      <invalid-&-entity>content</invalid-&-entity>
      <duplicate id="1">
        <item id="1">conflict</item>
      </duplicate>
    </root>
  `, 'text/xml');
  
  console.log('Parsing completed with issues:');
  issues.forEach(issue => {
    console.log(`${issue.level.toUpperCase()}: ${issue.message}`);
  });
} catch (error) {
  console.log('Parsing failed:', error.message);
  console.log('Issues found:', issues);
}

// Function-style error handler with custom logic
const strictParser = new DOMParser({
  errorHandler: function(level, msg) {
    const timestamp = new Date().toISOString();
    const logMessage = `[${timestamp}] XML ${level.toUpperCase()}: ${msg}`;
    
    switch (level) {
      case 'warning':
        console.warn(logMessage);
        break;
      case 'error':
        console.error(logMessage);
        // Convert errors to fatal in strict mode
        throw new Error(`Strict mode: ${msg}`);
      case 'fatalError':
        console.error(logMessage);
        throw new Error(`Fatal: ${msg}`);
    }
  }
});

// Position-aware error handling
const positionParser = new DOMParser({
  locator: {},
  errorHandler: function(level, msg) {
    // Error messages include position information when locator is enabled
    console.log(`${level}: ${msg}`);
    // Message format: "[xmldom error] message @file#[line:X,col:Y]"
  }
});

DOM Operation Error Scenarios

Common scenarios where DOMExceptions are thrown during DOM manipulation.

Usage Examples:

const { DOMParser, DOMException } = require('xmldom');
const parser = new DOMParser();
const doc = parser.parseFromString('<root></root>', 'text/xml');

// HIERARCHY_REQUEST_ERR - Invalid parent-child relationships
try {
  const element = doc.createElement('test');
  element.appendChild(element); // Cannot append element to itself
} catch (e) {
  console.log(`Hierarchy error: ${e.message}`);
}

try {
  doc.documentElement.appendChild(doc); // Cannot append document to element
} catch (e) {
  console.log(`Hierarchy error: ${e.message}`);
}

// WRONG_DOCUMENT_ERR - Using nodes from different documents
try {
  const otherDoc = parser.parseFromString('<other></other>', 'text/xml');
  doc.documentElement.appendChild(otherDoc.documentElement);
} catch (e) {
  console.log(`Wrong document error: ${e.message}`);
}

// INVALID_CHARACTER_ERR - Invalid names
try {
  doc.createElement('123invalid'); // Names cannot start with digits
} catch (e) {
  console.log(`Invalid character error: ${e.message}`);
}

try {
  doc.createElement('invalid name'); // Names cannot contain spaces
} catch (e) {
  console.log(`Invalid character error: ${e.message}`);
}

// NOT_FOUND_ERR - Removing non-existent nodes
try {
  const parent = doc.createElement('parent');
  const child = doc.createElement('child');
  parent.removeChild(child); // Child is not actually a child of parent
} catch (e) {
  console.log(`Not found error: ${e.message}`);
}

// INUSE_ATTRIBUTE_ERR - Attribute already in use
try {
  const element1 = doc.createElement('element1');
  const element2 = doc.createElement('element2');
  const attr = doc.createAttribute('test');
  
  element1.setAttributeNode(attr);
  element2.setAttributeNode(attr); // Attribute already belongs to element1
} catch (e) {
  console.log(`Attribute in use error: ${e.message}`);
}

// NAMESPACE_ERR - Invalid namespace operations
try {
  doc.createElementNS('', 'prefix:name'); // Empty namespace with prefix
} catch (e) {
  console.log(`Namespace error: ${e.message}`);
}

try {
  doc.createElementNS('http://example.com', 'xml:test'); // Reserved xml prefix
} catch (e) {
  console.log(`Namespace error: ${e.message}`);
}

Custom Error Handler Patterns

Advanced patterns for handling parsing errors in different application contexts.

Usage Examples:

const { DOMParser } = require('xmldom');

// Validation-focused error handler
class XMLValidator {
  constructor() {
    this.warnings = [];
    this.errors = [];
    this.isValid = true;
  }
  
  createParser() {
    return new DOMParser({
      errorHandler: {
        warning: (msg) => {
          this.warnings.push(msg);
        },
        error: (msg) => {
          this.errors.push(msg);
          this.isValid = false;
        },
        fatalError: (msg) => {
          this.errors.push(msg);
          this.isValid = false;
          throw new Error(`XML Validation Failed: ${msg}`);
        }
      }
    });
  }
  
  validate(xmlString) {
    this.warnings = [];
    this.errors = [];
    this.isValid = true;
    
    try {
      const parser = this.createParser();
      const doc = parser.parseFromString(xmlString, 'text/xml');
      return {
        isValid: this.isValid,
        document: doc,
        warnings: this.warnings,
        errors: this.errors
      };
    } catch (error) {
      return {
        isValid: false,
        document: null,
        warnings: this.warnings,
        errors: [...this.errors, error.message]
      };
    }
  }
}

// Usage
const validator = new XMLValidator();
const result = validator.validate('<root><unclosed></root>');
console.log('Valid:', result.isValid);
console.log('Errors:', result.errors);

// Logging-focused error handler with different output targets
class XMLLogger {
  constructor(options = {}) {
    this.logWarnings = options.logWarnings !== false;
    this.logErrors = options.logErrors !== false;
    this.throwOnError = options.throwOnError || false;
    this.logger = options.logger || console;
  }
  
  createParser() {
    return new DOMParser({
      errorHandler: {
        warning: (msg) => {
          if (this.logWarnings) {
            this.logger.warn(`XML Warning: ${msg}`);
          }
        },
        error: (msg) => {
          if (this.logErrors) {
            this.logger.error(`XML Error: ${msg}`);
          }
          if (this.throwOnError) {
            throw new Error(`XML Error: ${msg}`);
          }
        },
        fatalError: (msg) => {
          this.logger.error(`XML Fatal Error: ${msg}`);
          throw new Error(`XML Fatal Error: ${msg}`);
        }
      }
    });
  }
}

// Usage with custom logger
const customLogger = {
  warn: (msg) => console.log(`[WARN] ${new Date().toISOString()} ${msg}`),
  error: (msg) => console.log(`[ERROR] ${new Date().toISOString()} ${msg}`)
};

const logger = new XMLLogger({ 
  logger: customLogger,
  throwOnError: true 
});

// Silent parser that collects errors without logging
const silentIssues = [];
const silentParser = new DOMParser({
  errorHandler: (level, msg) => {
    silentIssues.push({ level, message: msg, timestamp: Date.now() });
  }
});

const doc = silentParser.parseFromString('<root><problem>', 'text/xml');
console.log('Silent parsing issues:', silentIssues);

Error Recovery Strategies

Strategies for handling and recovering from parsing errors in robust applications.

Usage Examples:

const { DOMParser } = require('xmldom');

// Fallback parsing with progressively more lenient settings
function robustParse(xmlString) {
  const strategies = [
    // Strategy 1: Strict parsing
    () => {
      const parser = new DOMParser({
        errorHandler: {
          warning: () => {}, // Ignore warnings
          error: (msg) => { throw new Error(msg); },
          fatalError: (msg) => { throw new Error(msg); }
        }
      });
      return parser.parseFromString(xmlString, 'text/xml');
    },
    
    // Strategy 2: Warning-tolerant parsing
    () => {
      const parser = new DOMParser({
        errorHandler: {
          warning: () => {}, // Ignore warnings
          error: () => {}, // Ignore errors
          fatalError: (msg) => { throw new Error(msg); }
        }
      });
      return parser.parseFromString(xmlString, 'text/xml');
    },
    
    // Strategy 3: HTML parsing mode (more lenient)
    () => {
      const parser = new DOMParser({
        errorHandler: () => {} // Ignore all issues
      });
      return parser.parseFromString(xmlString, 'text/html');
    }
  ];
  
  const errors = [];
  
  for (let i = 0; i < strategies.length; i++) {
    try {
      const doc = strategies[i]();
      return {
        success: true,
        document: doc,
        strategy: i + 1,
        errors: errors
      };
    } catch (error) {
      errors.push(`Strategy ${i + 1}: ${error.message}`);
    }
  }
  
  return {
    success: false,
    document: null,
    strategy: null,
    errors: errors
  };
}

// Usage
const problematicXML = '<root><unclosed><invalid&entity>content</root>';
const result = robustParse(problematicXML);

if (result.success) {
  console.log(`Parsed successfully using strategy ${result.strategy}`);
  console.log('Document:', result.document.toString());
} else {
  console.log('All parsing strategies failed');
  result.errors.forEach(error => console.log('Error:', error));
}

Install with Tessl CLI

npx tessl i tessl/npm-xmldom

docs

dom-manipulation.md

error-handling.md

index.md

namespace-support.md

xml-parsing.md

xml-serialization.md

tile.json