콘텐츠로 이동

StaxXmlWriter - 비동기 XML 스트림 라이터

StaxXmlWriter - 비동기 XML 스트림 라이터

섹션 제목: “StaxXmlWriter - 비동기 XML 스트림 라이터”

StaxXmlWriter는 대용량 문서와 메모리 효율적인 처리를 위해 설계된 비동기, 스트림 기반 XML 라이터입니다. XML 데이터를 WritableStream에 직접 작성하여 스트리밍 응답과 실시간 XML 생성에 이상적입니다.

  • 스트림 기반: 메모리 효율성을 위해 WritableStream에 직접 작성
  • 비동기: 논블로킹 작업을 위해 모든 메서드가 promise 반환
  • 대용량 문서 지원: 임의의 크기의 XML 문서 처리
  • 메모리 효율적: 전체 XML을 메모리에 저장할 필요 없음
  • 실시간 생성: 스트리밍 API와 라이브 데이터에 완벽

참고: 동기식, 메모리 내 XML 생성을 위해서는 XML을 문자열로 구성하는 StaxXmlWriterSync를 참조하세요.

import { Hono } from 'hono';
import { stream } from 'hono/streaming';
import { StaxXmlWriter } from 'stax-xml';
const app = new Hono();
app.get('/api/products', (c) => {
// 샘플 제품 데이터
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' }
];
// 적절한 헤더 설정
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 {
// 스트림에 직접 XML 생성 - 모든 메서드에 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(); // 중요: 스트림 닫기
} catch (error) {
console.error('XML 생성 오류:', error);
// 참고: 스트리밍 컨텍스트에서 오류 처리는 제한적입니다
}
});
});
export default app;
네임스페이스와 사용자 정의 엔터티를 포함한 고급 기능
섹션 제목: “네임스페이스와 사용자 정의 엔터티를 포함한 고급 기능”
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 {
// 네임스페이스와 사용자 정의 엔터티로 XML 작성
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;'); // 자동으로 인코딩됩니다
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();
// 자체 닫는 엘리먼트
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 생성 오류:', error);
}
});
});
export default app;

StaxXmlWriter는 엘리먼트 생성을 단순화하는 통합 API를 지원합니다:

// 속성이 있는 자체 닫는 엘리먼트
await writer.writeStartElement('img', {
attributes: {
src: 'image.jpg',
alt: 'Image'
},
selfClosing: true // writeEndElement() 호출 불필요
});
// 네임스페이스가 있는 엘리먼트
await writer.writeStartElement('title', {
prefix: 'html',
uri: 'http://www.w3.org/1999/xhtml',
attributes: { lang: 'ko' }
});

StaxXmlWriter (비동기식, 스트림 기반)

섹션 제목: “StaxXmlWriter (비동기식, 스트림 기반)”
class StaxXmlWriter {
// 생성자 - WritableStream에 직접 XML 스트리밍용
constructor(stream: WritableStream<Uint8Array>, options?: StaxXmlWriterOptions)
// 문서 레벨 메서드
writeStartDocument(version?: string, encoding?: string): Promise<this>
writeEndDocument(): Promise<void>
// 엘리먼트 작성 메서드
writeStartElement(localName: string, options?: WriteElementOptions): Promise<this>
writeEndElement(): Promise<this>
// 콘텐츠 작성 메서드
writeCharacters(text: string): Promise<this>
writeCData(cdata: string): Promise<this>
writeComment(comment: string): Promise<this>
// 스트림 관리
close(): Promise<void> // 기본 스트림 닫기
flush(): Promise<void> // 수동 플러시
getMetrics(): object // 성능 메트릭
}
interface StaxXmlWriterOptions {
encoding?: string; // 기본값: 'utf-8'
prettyPrint?: boolean; // 기본값: false
indentString?: string; // 기본값: ' '
addEntities?: { entity: string, value: string }[];
autoEncodeEntities?: boolean; // 기본값: true
namespaces?: NamespaceDeclaration[];
bufferSize?: number; // 기본값: 16384
highWaterMark?: number; // 기본값: 65536
flushThreshold?: number; // 기본값: 0.8
enableAutoFlush?: boolean; // 기본값: true
}
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;
}

🚀 StaxXmlWriter를 언제 사용해야 할까요?

섹션 제목: “🚀 StaxXmlWriter를 언제 사용해야 할까요?”

StaxXmlWriter를 사용하는 경우:

  • 대용량 XML 문서 구성 (> 100MB)
  • 클라이언트에 실시간 XML 스트리밍
  • 메모리 효율성이 중요한 경우
  • 비동기/스트리밍 아키텍처 작업
  • 메모리에 맞지 않는 데이터 처리
  • 응답을 스트리밍해야 하는 API 구축
  • 라이브 데이터 소스에서 실시간 XML 생성

소규모 문서나 동기식 작업의 경우 XML을 메모리에서 문자열로 구성하는 StaxXmlWriterSync를 고려하세요.