2026년 06월 15일 | DBMS Error 가이드
이 글에서 다루는 내용
2200L 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2200L not an xml document 는?
PostgreSQL 에러 코드 2200L은 not an xml document라는 메시지로 발생하며, XML 데이터를 처리하는 과정에서 입력된 값이 유효한 XML 문서 형식을 갖추지 못했을 때 나타납니다. 특히 XMLPARSE, xml 타입 캐스팅, 또는 XML 관련 함수(xpath, xmlquery, xmltable 등)를 사용할 때 입력 문자열이 올바른 XML 문서 구조, 즉 단일 루트 엘리먼트와 XML 선언을 포함한 Well-formed Document 조건을 충족하지 못하면 이 에러가 발생합니다. 이 에러는 단순히 XML이 깨진 경우뿐 아니라, XML 단편(fragment)을 문서(document)로 처리하려 할 때도 빈번하게 발생하기 때문에 실무에서 주의가 필요합니다.
주요 발생 원인
1. XML 단편(Fragment)을 XML 문서(Document)로 파싱 시도
PostgreSQL의 xml 데이터 타입은 내부적으로 DOCUMENT 모드와 CONTENT 모드를 구분합니다. XMLPARSE(DOCUMENT ...) 함수를 사용할 때 단일 루트 엘리먼트 없이 여러 개의 최상위 노드가 존재하거나, 루트가 없는 단순 텍스트만 있는 경우 이 에러가 발생합니다. XML 단편은 XMLPARSE(CONTENT ...) 방식으로 처리해야 하며, 이 구분을 혼동하는 경우가 실무에서 가장 흔한 원인입니다.
2. 잘못된 XML 구조 또는 Well-formed 조건 미충족
XML 문서는 반드시 하나의 루트 엘리먼트를 가져야 하고, 모든 태그는 올바르게 열리고 닫혀야 하며, 속성값은 따옴표로 감싸져야 합니다. 예를 들어, 처럼 닫는 태그가 없거나, 처럼 태그 중첩이 잘못된 경우, 또는 앰퍼샌드(&) 같은 특수문자가 이스케이프 처리 없이 포함된 경우 에러가 발생합니다. 애플리케이션에서 동적으로 XML을 생성할 때 이런 실수가 자주 발생합니다.
3. 외부 소스(API, 파일, 타 시스템)에서 유입된 비정형 데이터
외부 API 응답, CSV 파일 임포트, 또는 레거시 시스템에서 전달된 데이터에 XML처럼 보이지만 실제로는 HTML, SGML, 또는 단순 텍스트가 섞인 경우가 많습니다. 이런 데이터를 별도의 검증 없이 곧바로 xml 컬럼에 INSERT하거나 XML 함수에 전달하면 에러가 발생합니다. 특히 HTML과 XML을 혼동하는 경우( 같은 self-closing 미처리 태그)가 대표적인 사례입니다.
해결 방법
원인 1: XMLPARSE DOCUMENT vs CONTENT 구분
XML 단편을 처리할 때는 DOCUMENT 대신 CONTENT 키워드를 사용하거나, 루트 엘리먼트로 감싸줍니다.
-- 에러 발생: 루트 엘리먼트가 없는 단편을 DOCUMENT로 파싱
SELECT XMLPARSE(DOCUMENT '<item>사과</item><item>배</item>');
-- ERROR: 2200L: not an xml document
-- 해결책 1: CONTENT 모드로 변경
SELECT XMLPARSE(CONTENT '<item>사과</item><item>배</item>');
-- 해결책 2: 루트 엘리먼트로 감싸서 유효한 DOCUMENT로 변환
SELECT XMLPARSE(DOCUMENT '<items><item>사과</item><item>배</item></items>');
-- 실무 예시: 테이블에 저장 시
CREATE TABLE product_xml (
id SERIAL PRIMARY KEY,
data XML
);
-- CONTENT 모드로 삽입 (단편도 허용)
INSERT INTO product_xml (data)
VALUES (XMLPARSE(CONTENT '<item>사과</item><item>배</item>'));
원인 2: Well-formed XML 검증 및 수정
데이터를 삽입하기 전에 XML 유효성을 먼저 검사하는 방법입니다.
-- 에러 발생: 닫는 태그 누락
SELECT '<name>홍길동'::xml;
-- ERROR: 2200L: not an xml document
-- 에러 발생: 특수문자 미이스케이프
SELECT '<desc>가격 5000원 & 할인 10%</desc>'::xml;
-- ERROR: 2200L: not an xml document
-- 해결책: 특수문자 이스케이프 처리
SELECT '<desc>가격 5000원 & 할인 10%</desc>'::xml;
-- 실무 패턴: 검증 함수 작성
CREATE OR REPLACE FUNCTION safe_xml_parse(p_text TEXT)
RETURNS XML AS $$
BEGIN
RETURN p_text::xml;
EXCEPTION
WHEN SQLSTATE '2200L' THEN
RAISE WARNING 'not an xml document: %', LEFT(p_text, 100);
RETURN NULL;
WHEN OTHERS THEN
RAISE WARNING 'XML parse error: % - %', SQLERRM, LEFT(p_text, 100);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- 사용 예시
SELECT safe_xml_parse('<root><item>테스트</item></root>') AS valid_xml;
SELECT safe_xml_parse('<broken>태그 미닫힘') AS invalid_xml; -- NULL 반환
원인 3: 외부 데이터 전처리 및 유효성 검증
외부에서 들어오는 데이터는 반드시 전처리 후 저장합니다.
-- 외부 데이터 일괄 검증 쿼리
-- raw_data 테이블에서 유효한 XML만 추출
CREATE TABLE raw_import (
id SERIAL PRIMARY KEY,
raw_content TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 유효한 XML과 그렇지 않은 것을 분리하는 뷰
CREATE VIEW valid_xml_data AS
SELECT
id,
raw_content,
safe_xml_parse(raw_content) AS parsed_xml,
CASE
WHEN safe_xml_parse(raw_content) IS NOT NULL THEN 'VALID'
ELSE 'INVALID'
END AS xml_status
FROM raw_import;
-- XMLTABLE을 사용할 때 안전하게 처리
SELECT
x.product_id,
x.product_name
FROM
product_xml p,
XMLTABLE(
'/items/item'
PASSING p.data
COLUMNS
product_id INT PATH '@id',
product_name TEXT PATH 'name'
) AS x
WHERE p.data IS NOT NULL;
-- xpath 함수 사용 시 안전한 패턴
SELECT
id,
(xpath('//name/text()', data))[1]::TEXT AS name
FROM product_xml
WHERE data IS NOT NULL;
예방 방법
1. 애플리케이션 레벨에서 XML 유효성 검증 후 DB에 전달
데이터베이스에 XML 데이터를 삽입하기 전에 애플리케이션 레벨(Java의 DocumentBuilder, Python의 lxml, Node.js의 xml2js 등)에서 반드시 XML 유효성 검사를 수행하십시오. DB에서 에러가 발생하면 트랜잭션 롤백 비용이 발생하므로, 가능한 한 사전 필터링이 효율적입니다. PostgreSQL의 CHECK 제약 조건과 트리거를 활용해 2중 방어선을 구축하는 것도 좋은 방법입니다.
-- CHECK 제약 조건을 활용한 방어
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_data XML NOT NULL,
CONSTRAINT chk_valid_xml CHECK (order_data IS NOT NULL)
);
-- 트리거를 활용한 XML 로깅
CREATE OR REPLACE FUNCTION log_xml_errors()
RETURNS TRIGGER AS $$
BEGIN
-- 추가 비즈니스 로직 검증
IF NEW.order_data IS NULL THEN
RAISE EXCEPTION 'order_data must be a valid XML document';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
2. XML 처리 시 DOCUMENT/CONTENT 모드 표준화
팀 내에서 XML 데이터 처리 시 DOCUMENT 모드와 CONTENT 모드 중 하나로 표준을 정해 일관성 있게 사용하십시오. 일반적으로 단일 루트 엘리먼트가 보장되는 경우 DOCUMENT 모드를, 여러 노드가 올 수 있는 경우 CONTENT 모드를 사용하는 것이 권장됩니다. 코드 리뷰 체크리스트에 XML 모드 확인 항목을 추가하면 실수를 사전에 방지할 수 있습니다.
관련 에러
2200M(invalid XML content): XML 내용 자체는 파싱되었으나 내용이 유효하지 않을 때 발생합니다.2200L과 유사하지만 구조적 문제보다는 내용 수준의 문제입니다.2200N(invalid XML name): XML 엘리먼트나 속성의 이름이 XML 명명 규칙에 위반될 때 발생합니다.22000(data exception): XML 관련 에러들의 상위 카테고리로, XML 처리 중 발생하는 일반적인 데이터 예외를 포괄합니다.42804(datatype mismatch): XML 타입이 기대되는 컬럼에 다른 타입을 삽입하려 할 때 함께 발생할 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.