StaxXmlWriter - Asynchronous XML Stream Writer
StaxXmlWriter - Asynchronous XML Stream Writer
Section titled “StaxXmlWriter - Asynchronous XML Stream Writer”StaxXmlWriter
is an asynchronous, stream-based XML writer designed for large documents and memory-efficient processing. It writes XML data directly to a WritableStream, making it ideal for streaming responses and real-time XML generation.
Key Features
Section titled “Key Features”- Stream-Based: Writes directly to WritableStream for memory efficiency
- Asynchronous: All methods return promises for non-blocking operations
- Large Document Support: Handles arbitrarily large XML documents
- Memory Efficient: No need to store entire XML in memory
- Real-time Generation: Perfect for streaming APIs and live data
Note: For synchronous, in-memory XML generation, see StaxXmlWriterSync which builds XML as a string.
🔧 Quick Start
Section titled “🔧 Quick Start”import { Hono } from 'hono';import { stream } from 'hono/streaming';import { StaxXmlWriter } from 'stax-xml';
const app = new Hono();
app.get('/api/products', (c) => { // Sample product data const products = [ { id: 'P001', name: 'Smartphone', price: 699.99, category: 'Electronics' }, { id: 'P002', name: 'Headphones', price: 199.99, category: 'Electronics' }, { id: 'P003', name: 'Coffee Maker', price: 149.99, category: 'Appliances' } ];
// Set appropriate headers c.header('Content-Type', 'application/xml; charset=utf-8'); c.header('Cache-Control', 'no-cache');
return stream(c, async (stream) => { const writer = new StaxXmlWriter(stream, { prettyPrint: true, indentString: ' ' });
try { // Generate XML directly to stream - all methods need await await writer.writeStartDocument('1.0', 'utf-8'); await writer.writeStartElement('products', { attributes: { count: products.length.toString(), generated: new Date().toISOString() } });
for (const product of products) { await writer.writeStartElement('product', { attributes: { id: product.id, category: product.category } });
await writer.writeStartElement('name'); await writer.writeCharacters(product.name); await writer.writeEndElement();
await writer.writeStartElement('price', { attributes: { currency: 'USD' } }); await writer.writeCharacters(product.price.toString()); await writer.writeEndElement();
await writer.writeEndElement(); // product }
await writer.writeEndElement(); // products await writer.writeEndDocument(); await writer.close(); // Important: close the stream
} catch (error) { console.error('XML generation error:', error); // Note: Error handling in streaming context is limited } });});
export default app;
Advanced Features with Namespaces and Custom Entities
Section titled “Advanced Features with Namespaces and Custom Entities”import { Hono } from 'hono';import { stream } from 'hono/streaming';import { StaxXmlWriter } from 'stax-xml';
const app = new Hono();
app.get('/api/catalog', (c) => { const items = [ { id: '001', name: 'Premium Laptop', featured: true }, { id: '002', name: 'Wireless Mouse', featured: false } ];
c.header('Content-Type', 'application/xml; charset=utf-8');
return stream(c, async (stream) => { const writer = new StaxXmlWriter(stream, { prettyPrint: true, indentString: ' ', addEntities: [ { entity: 'company', value: 'Acme Corporation' }, { entity: 'copyright', value: '© 2024' } ], autoEncodeEntities: true });
try { // Write XML with namespaces and custom entities await writer.writeStartDocument('1.0', 'utf-8');
await writer.writeStartElement('catalog', { prefix: 'cat', uri: 'http://example.com/catalog', attributes: { version: '2.0' } }); await writer.writeNamespace('meta', 'http://example.com/metadata');
await writer.writeStartElement('header', { prefix: 'meta' }); await writer.writeStartElement('title'); await writer.writeCharacters('Product Catalog'); await writer.writeEndElement();
await writer.writeStartElement('company'); await writer.writeCharacters('&company;'); // Will be encoded automatically await writer.writeEndElement(); await writer.writeEndElement(); // header
await writer.writeStartElement('products'); for (const item of items) { await writer.writeStartElement('product', { attributes: { id: item.id, featured: item.featured.toString() } });
await writer.writeStartElement('name'); await writer.writeCharacters(item.name); await writer.writeEndElement();
// Self-closing element await writer.writeStartElement('thumbnail', { attributes: { src: `${item.id}.jpg`, alt: 'Product Image' }, selfClosing: true });
await writer.writeStartElement('description'); await writer.writeCData('<p>This is <b>HTML</b> content in CDATA</p>'); await writer.writeEndElement();
await writer.writeEndElement(); // product } await writer.writeEndElement(); // products await writer.writeEndElement(); // catalog
await writer.writeEndDocument(); await writer.close();
} catch (error) { console.error('XML generation error:', error); } });});
export default app;
WriteElementOptions API
Section titled “WriteElementOptions API”StaxXmlWriter
supports a unified API that simplifies element creation:
// Self-closing element with attributesawait writer.writeStartElement('img', { attributes: { src: 'image.jpg', alt: 'Image' }, selfClosing: true // No need to call writeEndElement()});
// Element with namespaceawait writer.writeStartElement('title', { prefix: 'html', uri: 'http://www.w3.org/1999/xhtml', attributes: { lang: 'en' }});
📚 API Reference
Section titled “📚 API Reference”StaxXmlWriter (Asynchronous, Stream-Based)
Section titled “StaxXmlWriter (Asynchronous, Stream-Based)”class StaxXmlWriter { // Constructor - for streaming XML directly to WritableStream constructor(stream: WritableStream<Uint8Array>, options?: StaxXmlWriterOptions)
// Document Level Methods writeStartDocument(version?: string, encoding?: string): Promise<this> writeEndDocument(): Promise<void>
// Element Writing Methods writeStartElement(localName: string, options?: WriteElementOptions): Promise<this> writeEndElement(): Promise<this>
// Content Writing Methods writeCharacters(text: string): Promise<this> writeCData(cdata: string): Promise<this> writeComment(comment: string): Promise<this>
// Stream Management close(): Promise<void> // Closes the underlying stream flush(): Promise<void> // Manual flush getMetrics(): object // Performance metrics}
interface StaxXmlWriterOptions { encoding?: string; // Default: 'utf-8' prettyPrint?: boolean; // Default: false indentString?: string; // Default: ' ' addEntities?: { entity: string, value: string }[]; autoEncodeEntities?: boolean; // Default: true namespaces?: NamespaceDeclaration[]; bufferSize?: number; // Default: 16384 highWaterMark?: number; // Default: 65536 flushThreshold?: number; // Default: 0.8 enableAutoFlush?: boolean; // Default: true}
Interfaces
Section titled “Interfaces”interface WriteElementOptions { prefix?: string; uri?: string; attributes?: Record<string, string | AttributeInfo>; selfClosing?: boolean;}
interface AttributeInfo { value: string; localName: string; prefix?: string; uri?: string;}
interface NamespaceDeclaration { prefix?: string; uri: string;}
🚀 When to Use StaxXmlWriter
Section titled “🚀 When to Use StaxXmlWriter”Use StaxXmlWriter when:
- Building large XML documents (> 100MB)
- Streaming XML to clients in real-time
- Memory efficiency is critical
- Working with asynchronous/streaming architectures
- Processing data that doesn’t fit in memory
- Building APIs that need to stream responses
- Real-time XML generation from live data sources
For small documents or synchronous operations, consider StaxXmlWriterSync which builds XML in memory as a string.