콘텐츠로 이동

StaxXmlWriterSync - 동기식 XML 생성

StAX-XML에는 메모리에서 XML 문자열을 빌드하여 프로그래밍 방식으로 XML 문서를 생성하는 동기식 XML 라이터가 포함되어 있습니다. 이 라이터는 작은 문서와 동기식 워크플로우에서 더 나은 성능을 제공합니다.

import { StaxXmlWriterSync } from 'stax-xml';
import { writeFileSync } from 'fs';
// Node.js용 - 로컬 파일에 동기식으로 쓰기
function createLocalXmlFile() {
const writer = new StaxXmlWriterSync({
prettyPrint: true,
indentString: ' '
});
// XML 문서 작성
writer.writeStartDocument('1.0', 'utf-8');
writer.writeStartElement('catalog', { attributes: { version: '1.0' } });
writer.writeStartElement('product', { attributes: { id: '001' } });
writer.writeStartElement('name');
writer.writeCharacters('노트북 컴퓨터');
writer.writeEndElement();
writer.writeStartElement('price', { attributes: { currency: 'KRW' } });
writer.writeCharacters('1200000');
writer.writeEndElement();
writer.writeEndElement(); // product
writer.writeEndElement(); // catalog
writer.writeEndDocument();
// 최종 XML 문자열을 가져와서 파일에 쓰기
writeFileSync('./output.xml', writer.getXmlString());
console.log('XML 파일이 성공적으로 생성되었습니다!');
}
createLocalXmlFile();
import express from 'express';
import { StaxXmlWriterSync } from 'stax-xml';
const app = express();
// XML 응답을 생성하는 미들웨어
app.get('/api/users', (req, res) => {
try {
// 샘플 데이터
const users = [
{ id: 1, name: '홍길동', email: 'hong@example.com' },
{ id: 2, name: '김영희', email: 'kim@example.com' }
];
const writer = new StaxXmlWriterSync({
prettyPrint: true,
indentString: ' '
});
// 적절한 헤더 설정
res.setHeader('Content-Type', 'application/xml; charset=utf-8');
res.setHeader('Cache-Control', 'no-cache');
// XML 작성
writer.writeStartDocument('1.0', 'utf-8');
writer.writeStartElement('users');
for (const user of users) {
writer.writeStartElement('user', { attributes: { id: user.id.toString() } });
writer.writeStartElement('name');
writer.writeCharacters(user.name);
writer.writeEndElement();
writer.writeStartElement('email');
writer.writeCharacters(user.email);
writer.writeEndElement();
writer.writeEndElement(); // user
}
writer.writeEndElement(); // users
writer.writeEndDocument();
// 최종 XML 문자열 전송
res.send(writer.getXmlString());
} catch (error) {
res.status(500).json({ error: 'XML 생성에 실패했습니다' });
}
});
app.listen(3000, () => {
console.log('서버가 포트 3000에서 실행 중입니다');
});
import { Hono } from 'hono';
import { StaxXmlWriterSync } from 'stax-xml';
const app = new Hono();
app.get('/api/products', (c) => {
// 샘플 제품 데이터
const products = [
{ id: 'P001', name: '스마트폰', price: 800000, category: '전자제품' },
{ id: 'P002', name: '헤드폰', price: 250000, category: '전자제품' },
{ id: 'P003', name: '커피메이커', price: 180000, category: '가전제품' }
];
const writer = new StaxXmlWriterSync({
prettyPrint: true,
indentString: ' '
});
try {
// XML 생성
writer.writeStartDocument('1.0', 'utf-8');
writer.writeStartElement('products', {
attributes: {
count: products.length.toString(),
generated: new Date().toISOString()
}
});
for (const product of products) {
writer.writeStartElement('product', {
attributes: {
id: product.id,
category: product.category
}
});
writer.writeStartElement('name');
writer.writeCharacters(product.name);
writer.writeEndElement();
writer.writeStartElement('price', { attributes: { currency: 'KRW' } });
writer.writeCharacters(product.price.toString());
writer.writeEndElement();
writer.writeEndElement(); // product
}
writer.writeEndElement(); // products
writer.writeEndDocument();
// 생성된 XML 문자열을 응답으로 반환
return c.text(writer.getXmlString(), 200, {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'no-cache',
});
} catch (error) {
return c.text('XML 생성에 실패했습니다', 500);
}
});
export default app;
import { StaxXmlWriterSync } from 'stax-xml';
// 사용자 정의 엔티티와 네임스페이스를 사용한 메모리 내 XML 생성
function createAdvancedXml() {
const writer = new StaxXmlWriterSync({
prettyPrint: true,
indentString: ' ',
addEntities: [
{ entity: 'company', value: 'Acme Corporation' },
{ entity: 'copyright', value: '© 2024' }
],
autoEncodeEntities: true
});
// 네임스페이스와 사용자 정의 엔티티를 사용한 XML 작성
writer.writeStartDocument('1.0', 'utf-8');
writer.writeStartElement('document', {
prefix: 'doc',
uri: 'http://example.com/document',
attributes: { version: '2.0' }
});
writer.writeNamespace('meta', 'http://example.com/metadata');
writer.writeStartElement('header', { prefix: 'meta' });
writer.writeStartElement('title');
writer.writeCharacters('제품 카탈로그');
writer.writeEndElement();
writer.writeStartElement('company');
writer.writeCharacters('&company;'); // 자동으로 인코딩됩니다
writer.writeEndElement();
writer.writeEndElement(); // header
writer.writeStartElement('content');
writer.writeStartElement('item', { attributes: { type: 'featured' } });
// 자체 닫힘 요소
writer.writeStartElement('thumbnail', {
attributes: {
src: 'image.jpg',
alt: '제품 이미지'
},
selfClosing: true
});
writer.writeStartElement('description');
writer.writeCData('<p>이것은 CDATA 안의 <b>HTML</b> 콘텐츠입니다</p>');
writer.writeEndElement();
writer.writeEndElement(); // item
writer.writeEndElement(); // content
writer.writeEndElement(); // document
writer.writeEndDocument();
return writer.getXmlString();
}
// 사용법
console.log('생성된 XML:', createAdvancedXml());

StaxXmlWriterSync는 모든 옵션을 단일 WriteElementOptions 객체로 통합하여 요소 생성을 단순화하는 통합 API를 지원합니다:

import { StaxXmlWriterSync, WriteElementOptions } from 'stax-xml';
function createXmlWithNewAPI() {
const writer = new StaxXmlWriterSync({ prettyPrint: true });
writer.writeStartDocument();
// 속성이 있는 기본 요소
writer.writeStartElement('catalog', {
attributes: { version: '2.0', xmlns: 'http://example.com/catalog' }
});
// 네임스페이스와 속성이 있는 요소
writer.writeStartElement('product', {
prefix: 'cat',
uri: 'http://example.com/catalog',
attributes: { id: '001', featured: 'true' }
});
writer.writeStartElement('name');
writer.writeCharacters('프리미엄 노트북');
writer.writeEndElement();
// 속성이 있는 자체 닫힘 요소
writer.writeStartElement('thumbnail', {
attributes: {
src: 'image.jpg',
alt: '제품 이미지',
width: '200'
},
selfClosing: true // writeEndElement() 호출 불필요
});
// 간단한 자체 닫힘 요소
writer.writeStartElement('br', { selfClosing: true });
writer.writeEndElement(); // product
writer.writeEndElement(); // catalog
writer.writeEndDocument();
return writer.getXmlString();
}
// 출력:
// <?xml version="1.0" encoding="UTF-8"?>
// <catalog version="2.0" xmlns="http://example.com/catalog">
// <cat:product id="001" featured="true" xmlns:cat="http://example.com/catalog">
// <name>프리미엄 노트북</name>
// <thumbnail src="image.jpg" alt="제품 이미지" width="200"/>
// <br/>
// </cat:product>
// </catalog>

통합 API의 주요 장점:

  • 통합 매개변수: 모든 요소 옵션(속성, 네임스페이스, 자체 닫힘)이 단일 옵션 객체로 통합됨
  • 자체 닫힘 지원: selfClosing: true 설정으로 writeEndElement() 호출 없이 자동으로 요소 닫힘
  • 깔끔한 구문: 더 직관적이고 읽기 쉬운 코드 구조
  • 타입 안전성: 포괄적인 타입 정의를 통한 완전한 TypeScript 지원

사용 예제:

// 속성이 있는 간단한 요소
writer.writeStartElement('img', {
attributes: {
src: 'image.jpg',
alt: '이미지'
},
selfClosing: true
});
// 네임스페이스가 있는 요소
writer.writeStartElement('title', {
prefix: 'html',
uri: 'http://www.w3.org/1999/xhtml',
attributes: { lang: 'ko' }
});
class StaxXmlWriterSync {
constructor(
options?: StaxXmlWriterSyncOptions
)
// 문서 레벨 메서드
writeStartDocument(version?: string, encoding?: string): this
writeEndDocument(): void
// 요소 작성 메서드
writeStartElement(localName: string, options?: WriteElementOptions): this
writeEndElement(): this
// 속성 및 네임스페이스 메서드
writeAttribute(localName: string, value: string, prefix?: string): this
writeNamespace(prefix: string, uri: string): this
// 콘텐츠 작성 메서드
writeCharacters(text: string): this
writeCData(cdata: string): this
writeComment(comment: string): this
writeProcessingInstruction(target: string, data?: string): this
// 유틸리티 메서드
setPrettyPrint(enabled: boolean): this
setIndentString(indentString: string): this
isPrettyPrintEnabled(): boolean
getIndentString(): string
getXmlString(): string
}
interface StaxXmlWriterSyncOptions {
encoding?: string; // 기본값: 'utf-8'
prettyPrint?: boolean; // 기본값: false
indentString?: string; // 기본값: ' '
addEntities?: { entity: string, value: string }[];
autoEncodeEntities?: boolean; // 기본값: true
namespaces?: NamespaceDeclaration[];
}
interface XmlAttribute {
localName: string;
value: string;
prefix?: string;
uri?: string;
}
interface NamespaceDeclaration {
prefix?: string;
uri: string;
}
  • 동기식 작업: 즉시 접근을 위한 메모리 내 XML 문자열 빌드
  • 고성능: 작은~중간 크기 문서에 최적화
  • 프리티 프린팅: 구성 가능한 들여쓰기 및 포맷팅
  • 네임스페이스 지원: 접두사 관리를 통한 완전한 XML 네임스페이스 처리
  • 엔티티 인코딩: 자동 또는 사용자 정의 엔티티 인코딩
  • 자체 닫힘 요소: 자체 닫힘 태그에 대한 내장 지원
  • 타입 안전성: 세부적인 타입 정의를 통한 완전한 TypeScript 지원
  • 메모리 효율적: 스트리밍 오버헤드 없는 직접 문자열 빌드

다음과 같은 경우에 StaxXmlWriterSync를 사용하세요:

  • 완전한 XML 문서를 메모리에서 즉시 필요로 할 때
  • 작은~중간 크기의 XML 문서 작업 시
  • 웹 API용 XML 응답 빌드 시
  • 구성 파일이나 데이터 내보내기 생성 시
  • 블로킹이 허용되는 동기식 워크플로우에서 작업 시
  • 메모리 사용량이 주요 관심사가 아닐 때

대용량 문서나 스트리밍 시나리오의 경우 비동기 StaxXmlWriter를 대신 사용하는 것을 고려하세요.