콘텐츠로 이동

Converter - 스키마 타입

StAX-XML Converter는 다양한 종류의 XML 데이터를 파싱하기 위한 네 가지 핵심 스키마 타입을 제공합니다: 문자열, 숫자, 객체, 배열.

XML 요소 또는 속성에서 문자열 값을 파싱합니다.

import { x } from 'stax-xml/converter';
// 요소 텍스트 내용 파싱
const schema = x.string().xpath('/root/message');
const result = schema.parseSync('<root><message>안녕하세요</message></root>');
// "안녕하세요"

/@ 접두사를 사용하여 속성 값 선택:

const schema = x.string().xpath('/book/@id');
const result = schema.parseSync('<book id="123">제목</book>');
// "123"
// 하위 속성 검색
const schema = x.string().xpath('//@href');
const result = schema.parseSync('<a><link href="http://example.com"/></a>');
// "http://example.com"

요소 선택을 위한 XPath 표현식 설정

XML 쓰기 동작 구성:

const schema = x.string().writer({
element: 'message',
cdata: true // CDATA 섹션으로 래핑
});

유효성 검사를 지원하는 XML에서 숫자 값을 파싱합니다.

const schema = x.number().xpath('/data/count');
const result = schema.parseSync('<data><count>42</count></data>');
// 42

최소값 제약 설정:

const schema = x.number().xpath('/age').min(18);
schema.parseSync('<age>25</age>'); // ✅ 25
schema.parseSync('<age>15</age>'); // ❌ 에러: 값 15가 최소값 18보다 작음

최대값 제약 설정

정수 값 요구 (소수점 없음):

const schema = x.number().xpath('/count').int();
schema.parseSync('<count>42</count>'); // ✅ 42
schema.parseSync('<count>42.5</count>'); // ❌ 에러: 정수 예상, 42.5 받음
const ageSchema = x.number()
.xpath('/person/age')
.min(0)
.max(120)
.int();

구조화된 데이터를 타입이 지정된 객체로 파싱합니다.

const bookSchema = x.object({
title: x.string().xpath('/book/title'),
author: x.string().xpath('/book/author'),
year: x.number().xpath('/book/year'),
price: x.number().xpath('/book/price')
});
const xml = `
<book>
<title>1984</title>
<author>조지 오웰</author>
<year>1949</year>
<price>15.99</price>
</book>
`;
const book = bookSchema.parseSync(xml);
// {
// title: "1984",
// author: "조지 오웰",
// year: 1949,
// price: 15.99
// }

TypeScript가 자동으로 객체 타입을 추론합니다:

import { type Infer } from 'stax-xml/converter';
const schema = x.object({
id: x.number().xpath('//id'),
name: x.string().xpath('//name'),
active: x.string().xpath('//active').transform(v => v === 'true')
});
type MyType = Infer<typeof schema>;
// {
// id: number;
// name: string;
// active: boolean; // 주의: transform이 타입을 변경함
// }

객체는 다른 객체를 포함할 수 있습니다:

const personSchema = x.object({
name: x.string().xpath('/person/name'),
address: x.object({
street: x.string().xpath('/person/address/street'),
city: x.string().xpath('/person/address/city'),
zip: x.string().xpath('/person/address/zip')
})
});

객체 자체에 XPath를 사용하여 자식 XPath의 범위를 지정:

// 객체 XPath 없이 - 절대 경로 필요
const schema1 = x.object({
cpu: x.string().xpath('/product/specs/cpu'),
ram: x.string().xpath('/product/specs/ram')
});
// 객체 XPath 사용 - 상대 경로 (더 깔끔함)
const schema2 = x.object({
cpu: x.string().xpath('./cpu'),
ram: x.string().xpath('./ram')
}).xpath('/product/specs');

반복되는 XML 요소를 배열로 파싱합니다.

// 문자열 배열
const schema = x.array(x.string(), '//item');
const xml = `
<list>
<item>사과</item>
<item>바나나</item>
<item>체리</item>
</list>
`;
const fruits = schema.parseSync(xml);
// ["사과", "바나나", "체리"]

배열은 항상 XPath가 필요합니다 - 어떤 요소를 포함할지 선택:

// ❌ 에러: xpath 누락
x.array(x.string());
// ✅ 올바름
x.array(x.string(), '//item');
x.array(x.number(), '//value');

가장 일반적인 사용 사례 - 구조화된 반복 요소 파싱:

const booksSchema = x.array(
x.object({
title: x.string().xpath('./title'),
author: x.string().xpath('./author'),
year: x.number().xpath('./year').int()
}),
'//book'
);
const xml = `
<library>
<book>
<title>1984</title>
<author>조지 오웰</author>
<year>1949</year>
</book>
<book>
<title>멋진 신세계</title>
<author>올더스 헉슬리</author>
<year>1932</year>
</book>
</library>
`;
const books = booksSchema.parseSync(xml);
// [
// { title: "1984", author: "조지 오웰", year: 1949 },
// { title: "멋진 신세계", author: "올더스 헉슬리", year: 1932 }
// ]
type Book = Infer<typeof booksSchema>[number];
// { title: string; author: string; year: number; }

XPath 조건절로 배열 요소 필터링:

// 픽션 책만
const fictionBooks = x.array(
x.object({
title: x.string().xpath('./title'),
author: x.string().xpath('./author')
}),
'//book[@category="fiction"]'
);

배열은 객체 내에 중첩될 수 있습니다:

const catalogSchema = x.object({
name: x.string().xpath('/catalog/name'),
categories: x.array(
x.object({
name: x.string().xpath('./@name'),
products: x.array(
x.object({
id: x.number().xpath('./@id'),
name: x.string().xpath('./name'),
price: x.number().xpath('./price')
}),
'./product'
)
}),
'//category'
)
});

일치하는 요소가 없으면 배열은 빈 []를 반환:

const schema = x.array(x.string(), '//item');
const result = schema.parseSync('<root></root>');
// []
기능StringNumberObjectArray
목적텍스트 값숫자 값구조화된 데이터반복 요소
XPath선택사항선택사항선택사항필수
유효성 검사-min, max, int필드별요소별
중첩--예 (객체 in 객체)예 (배열 in 객체)
타입 추론stringnumber{ ... }T[]
빈 결과""NaN{} with NaN/empty[]
Transform
Optional
Writer
// ❌ 너무 광범위
x.string().xpath('//name') // 모든 name 요소와 일치
// ✅ 구체적인 경로
x.string().xpath('/user/profile/name')
// ✅ 유효성 검사를 추가하여 조기에 에러 발견
const schema = x.object({
age: x.number().xpath('//age').min(0).max(120).int(),
email: x.string().xpath('//email')
});
// ✅ 한 번 정의하고 재사용
const priceSchema = x.number().min(0);
const idSchema = x.number().int().min(1);
const productSchema = x.object({
id: idSchema.xpath('//id'),
price: priceSchema.xpath('//price'),
salePrice: priceSchema.xpath('//salePrice').optional()
});

4. 스코핑을 위한 객체 XPath 사용

섹션 제목: “4. 스코핑을 위한 객체 XPath 사용”
// ✅ 객체 XPath로 더 깔끔하게
const specs = x.object({
cpu: x.string().xpath('./cpu'),
ram: x.string().xpath('./ram'),
storage: x.string().xpath('./storage')
}).xpath('/product/specs');
// ✅ 재사용을 위한 타입 추출
const userSchema = x.object({...});
type User = Infer<typeof userSchema>;
function processUsers(users: User[]) {
// TypeScript가 정확한 형태를 알고 있음
}