PostgreSQL 2200L 오류 원인과 해결 방법 완벽 가이드

2200L
2026년 10월 23일 | DBMS Error 가이드

이 글에서 다루는 내용

2200L 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

2200L not an xml document 는?

PostgreSQL 에러 코드 2200L은 not an xml document 에러로, XML 데이터를 처리하는 과정에서 입력된 값이 올바른 XML 문서 형식을 갖추지 못했을 때 발생합니다. PostgreSQL은 XML 타입 컬럼이나 XML 관련 함수(xmlparse, xpath, xmlelement 등)를 사용할 때 입력 데이터가 Well-formed XML Document 규격을 충족해야 한다고 요구합니다. 특히 XML 문서에는 단 하나의 루트 엘리먼트가 존재해야 하며, 이 조건이 충족되지 않으면 해당 에러가 발생합니다.


주요 발생 원인

1. 루트 엘리먼트가 없거나 여러 개인 경우

XML 문서의 핵심 규칙 중 하나는 반드시 단 하나의 루트 엘리먼트를 가져야 한다는 것입니다. 루트 엘리먼트가 없는 빈 텍스트나 여러 개의 최상위 엘리먼트를 가진 데이터를 XML 컬럼에 삽입하거나 XML 함수에 전달하면 2200L 에러가 발생합니다.

-- 에러 발생 예시: 루트 엘리먼트 없음
SELECT XMLPARSE(DOCUMENT 'hello world');
-- ERROR:  invalid XML document
-- DETAIL:  line 1: Start tag expected, '<' not found

-- 에러 발생 예시: 루트 엘리먼트가 여러 개
SELECT XMLPARSE(DOCUMENT '<item>first</item><item>second</item>');
-- ERROR:  invalid XML document
-- DETAIL:  Extra content at the end of the document

-- 올바른 예시: 단일 루트 엘리먼트
SELECT XMLPARSE(DOCUMENT '<root><item>first</item><item>second</item></root>');

2. XML 선언부(Prolog) 또는 태그 형식 오류

XML 문서의 선언부()나 태그가 올바르지 않은 경우에도 이 에러가 발생합니다. 예를 들어 여는 태그와 닫는 태그가 일치하지 않거나, 속성 값에 따옴표가 누락되었거나, 잘못된 문자가 포함된 경우가 해당됩니다.

-- 에러 발생 예시: 닫는 태그 불일치
SELECT XMLPARSE(DOCUMENT '<root><item>value</root>');
-- ERROR:  invalid XML document

-- 에러 발생 예시: 속성 따옴표 누락
SELECT XMLPARSE(DOCUMENT '<root id=1><item>value</item></root>');
-- ERROR:  invalid XML document

-- 올바른 예시: 선언부 포함 및 올바른 형식
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><root id="1"><item>value</item></root>');

3. XML 컬럼에 일반 텍스트나 HTML 데이터 삽입 시도

애플리케이션에서 XML 타입으로 정의된 컬럼에 일반 문자열이나 HTML 콘텐츠를 그대로 삽입하려 할 때 이 에러가 발생합니다. HTML은 XML(정확히는 XHTML)과 달리 엄격한 Well-formed 규칙을 따르지 않기 때문에 그대로 PostgreSQL XML 타입 컬럼에 저장할 수 없습니다.

-- 테이블 생성 예시
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content XML
);

-- 에러 발생 예시: 일반 텍스트 삽입
INSERT INTO documents (content) VALUES ('단순 텍스트입니다');
-- ERROR:  invalid XML document

-- 에러 발생 예시: HTML 삽입
INSERT INTO documents (content) VALUES ('<div><p>Hello<br>World</p></div>');
-- ERROR:  invalid XML document  (br 태그가 self-closing 아님)

-- 올바른 예시: 유효한 XML 삽입
INSERT INTO documents (content) VALUES ('<document><title>제목</title><body>내용입니다.</body></document>');

-- XMLPARSE를 활용한 안전한 삽입
INSERT INTO documents (content)
VALUES (XMLPARSE(DOCUMENT '<?xml version="1.0"?><document><title>제목</title></document>'));

해결 방법

원인 1 해결: 루트 엘리먼트 감싸기

여러 개의 최상위 엘리먼트가 있는 경우, 하나의 루트 엘리먼트로 감싸줍니다.

-- 문제 있는 데이터를 래핑하여 처리
DO $$
DECLARE
    v_raw_data TEXT := '<item>first</item><item>second</item>';
    v_xml XML;
BEGIN
    -- 루트 엘리먼트로 감싸서 유효한 XML 생성
    v_xml := XMLPARSE(DOCUMENT '<root>' || v_raw_data || '</root>');
    RAISE NOTICE 'XML 파싱 성공: %', v_xml;
END;
$$;

-- 기존 테이블 데이터 수정 시 루트 태그 추가
UPDATE documents
SET content = XMLPARSE(DOCUMENT '<root>' || content::TEXT || '</root>')
WHERE content::TEXT NOT LIKE '<%>%</%>';

원인 2 해결: XML 유효성 검사 후 삽입

삽입 전에 XMLPARSE를 활용하여 유효성을 먼저 검사합니다.

-- 유효성 검사를 위한 함수 생성
CREATE OR REPLACE FUNCTION is_valid_xml(p_input TEXT)
RETURNS BOOLEAN AS $$
BEGIN
    PERFORM XMLPARSE(DOCUMENT p_input);
    RETURN TRUE;
EXCEPTION
    WHEN invalid_xml_document THEN
        RETURN FALSE;
    WHEN others THEN
        RETURN FALSE;
END;
$$ LANGUAGE plpgsql;

-- 함수 사용 예시
SELECT is_valid_xml('<root><item>valid</item></root>');   -- TRUE
SELECT is_valid_xml('<root><item>invalid</root>');        -- FALSE
SELECT is_valid_xml('단순 텍스트');                        -- FALSE

-- 유효한 경우에만 삽입하는 패턴
INSERT INTO documents (content)
SELECT XMLPARSE(DOCUMENT raw_input)
FROM (VALUES ('<?xml version="1.0"?><doc><title>테스트</title></doc>')) AS t(raw_input)
WHERE is_valid_xml(raw_input);

원인 3 해결: TEXT 타입으로 변경 또는 데이터 변환

HTML 등 비XML 데이터를 저장해야 하는 경우 컬럼 타입을 TEXT로 변경하거나, XHTML로 변환하는 방법을 사용합니다.

-- 컬럼 타입을 TEXT로 변경
ALTER TABLE documents ALTER COLUMN content TYPE TEXT;

-- 또는 별도의 TEXT 컬럼 추가
ALTER TABLE documents ADD COLUMN html_content TEXT;

-- XML 타입과 TEXT 타입을 모두 지원하는 테이블 설계
CREATE TABLE mixed_documents (
    id SERIAL PRIMARY KEY,
    doc_type VARCHAR(10) CHECK (doc_type IN ('xml', 'html', 'text')),
    xml_content XML,          -- 순수 XML 데이터
    text_content TEXT,        -- HTML 또는 일반 텍스트
    created_at TIMESTAMPTZ DEFAULT NOW()
);

예방 방법

1. 애플리케이션 레벨에서 XML 유효성 검사 수행

데이터베이스에 데이터를 저장하기 전에 애플리케이션 레벨에서 먼저 XML 유효성을 검사하는 습관을 들이는 것이 중요합니다. Python의 lxml, Java의 javax.xml, Node.js의 fast-xml-parser 등 각 언어별 XML 파서를 활용하여 DB INSERT 전에 검증 단계를 추가하면 에러를 사전에 방지할 수 있습니다.

-- PostgreSQL CHECK 제약조건으로 XML 유효성 강제
CREATE TABLE validated_documents (
    id SERIAL PRIMARY KEY,
    content XML NOT NULL,
    -- XML 타입 자체가 유효성을 강제하므로 추가 CHECK 불필요
    -- 하지만 특정 구조를 강제하려면 아래처럼 xpath 활용 가능
    CONSTRAINT chk_has_root_title
        CHECK (xpath('/document/title/text()', content) != '{}')
);

-- 테스트
INSERT INTO validated_documents (content)
VALUES ('<document><title>필수 제목</title><body>내용</body></document>');
-- 성공

INSERT INTO validated_documents (content)
VALUES ('<document><body>제목 없음</body></document>');
-- ERROR: 체크 제약조건 위반

2. XML 데이터 저장 시 표준 인코딩 및 선언부 명시

XML 데이터를 저장할 때는 반드시 UTF-8 인코딩을 명시하고, XML 선언부를 포함하는 것을 표준으로 삼으세요. 이는 인코딩 관련 파싱 오류를 예방하고, 다른 시스템과의 데이터 호환성을 높입니다.

-- XML 데이터 삽입 시 표준 템플릿 사용
CREATE OR REPLACE FUNCTION create_xml_document(
    p_root_element TEXT,
    p_content TEXT
) RETURNS XML AS $$
DECLARE
    v_xml_string TEXT;
BEGIN
    v_xml_string := format(
        '<?xml version="1.0" encoding="UTF-8"?><%s>%s</%s>',
        p_root_element,
        p_content,
        p_root_element
    );
    RETURN XMLPARSE(DOCUMENT v_xml_string);
EXCEPTION
    WHEN invalid_xml_document THEN
        RAISE EXCEPTION 'XML 문서 생성 실패: 유효하지 않은 콘텐츠입니다. root=%, content=%',
            p_root_element, p_content;
END;
$$ LANGUAGE plpgsql;

-- 함수 활용
SELECT create_xml_document('document', '<title>테스트 문서</title><body>내용</body>');

관련 에러

  • 2200M (invalid_xml_content): XML 콘텐츠(Document가 아닌 Fragment)가 유효하지 않을 때 발생합니다. XMLPARSE(CONTENT ...)를 사용할 때 만나는 에러로, 2200L과 밀접한 관련이 있습니다.
  • 22000 (data_exception): XML 처리 시 발생하는 일반적인 데이터 예외의 상위 카테고리 에러입니다.
  • 2200S (invalid_xml_comment): XML 주석 형식이 올바르지 않을 때 발생합니다. (--를 포함하는 주석 등)
  • 2200T (invalid_xml_processing_instruction): XML 처리 지시자(Processing Instruction)가 잘못된 형식일 때 발생합니다.
  • 42804 (datatype_mismatch): XML 타입 컬럼에 호환되지 않는 타입을 삽입하려 할 때 발생할 수 있습니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기