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

2200N
2026년 06월 15일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2200N invalid xml content 는?

PostgreSQL 에러 코드 2200N: invalid xml content는 XML 타입 컬럼이나 XML 관련 함수에 유효하지 않은 XML 데이터를 삽입하거나 처리하려 할 때 발생하는 오류입니다. PostgreSQL은 XML 데이터의 구조적 유효성을 엄격하게 검사하며, W3C XML 표준을 준수하지 않는 데이터는 모두 이 에러를 발생시킵니다. 주로 외부 시스템에서 받아온 XML 문자열을 직접 DB에 저장하거나, 애플리케이션에서 XML을 동적으로 생성하는 과정에서 자주 발생합니다.


주요 발생 원인

  • 잘못된 XML 구조 또는 태그 불일치

XML은 모든 여는 태그에 반드시 대응하는 닫는 태그가 있어야 하며, 태그가 올바르게 중첩되어야 합니다. 실무에서는 외부 API로부터 수신한 XML 데이터나 사용자 입력값을 그대로 사용할 때 태그가 닫히지 않거나 순서가 잘못 중첩되어 이 에러가 발생하는 경우가 많습니다. 예를 들어 처럼 중첩 순서가 뒤바뀐 경우가 대표적입니다.

  • 잘못된 특수 문자 또는 인코딩 문제

XML에서는 &, <, >, ", ' 같은 특수 문자를 그대로 사용할 수 없으며, 반드시 XML 엔티티(&, <, >, ", ')로 이스케이프 처리해야 합니다. 또한 UTF-8이 아닌 인코딩이 섞이거나 BOM(Byte Order Mark)이 포함된 경우, XML 선언부의 인코딩 설정과 실제 데이터 인코딩이 다를 경우에도 이 에러가 발생합니다.

  • 여러 루트 엘리먼트 존재 또는 루트 엘리먼트 부재

XML 문서는 반드시 단 하나의 루트 엘리먼트만 가져야 합니다. 여러 개의 최상위 엘리먼트가 존재하거나, 루트 엘리먼트 없이 텍스트만 있는 경우, 또는 XML 선언() 이후에 루트 엘리먼트가 없는 경우에도 이 에러가 발생합니다. 이는 여러 XML 조각을 단순 문자열 연결로 합칠 때 자주 발생합니다.


해결 방법

원인 1: 잘못된 XML 구조 수정

먼저 문제가 되는 XML 문자열을 XMLPARSE 함수로 테스트하여 구조를 확인합니다.

-- 잘못된 XML 삽입 시도 (에러 발생)
INSERT INTO orders (order_id, xml_data)
VALUES (1, XMLPARSE(DOCUMENT '<order><item>사과</order></item>'));
-- ERROR: invalid xml content

-- 올바른 중첩 구조로 수정
INSERT INTO orders (order_id, xml_data)
VALUES (1, XMLPARSE(DOCUMENT '<order><item>사과</item></order>'));

-- 기존 데이터 중 유효한 XML인지 확인하는 방법 (함수 작성)
CREATE OR REPLACE FUNCTION is_valid_xml(p_text TEXT)
RETURNS BOOLEAN AS $$
BEGIN
    PERFORM XMLPARSE(DOCUMENT p_text);
    RETURN TRUE;
EXCEPTION
    WHEN invalid_xml_content THEN
        RETURN FALSE;
END;
$$ LANGUAGE plpgsql;

-- 활용 예시
SELECT id, raw_xml
FROM staging_xml_data
WHERE is_valid_xml(raw_xml) = FALSE;

원인 2: 특수 문자 이스케이프 처리

-- 특수 문자가 포함된 경우 (에러 발생)
INSERT INTO products (prod_id, xml_info)
VALUES (1, XMLPARSE(DOCUMENT '<product><name>AT&T</name></product>'));
-- ERROR: invalid xml content

-- xmlescape를 활용한 올바른 처리
-- PostgreSQL에서는 xmlelement 함수를 사용하면 자동으로 이스케이프됩니다
SELECT xmlelement(name product,
           xmlelement(name name, 'AT&T'),
           xmlelement(name price, 100)
       );
-- 결과: <product><name>AT&amp;T</name><price>100</price></product>

-- 문자열에서 직접 이스케이프 처리가 필요한 경우
SELECT XMLPARSE(DOCUMENT
    replace(
        replace(
            replace(raw_text, '&', '&amp;'),
        '<', '&lt;'),
    '>', '&gt;')
)
FROM staging_table
WHERE id = 1;

-- 인코딩 선언 제거 후 재시도 (BOM 문제 해결)
SELECT XMLPARSE(DOCUMENT
    regexp_replace(raw_xml, '^\s*<\?xml[^?]*\?>\s*', '', 'i')
)
FROM staging_table;

원인 3: 단일 루트 엘리먼트로 감싸기

-- 여러 루트가 있는 경우 (에러 발생)
SELECT XMLPARSE(DOCUMENT '<item>A</item><item>B</item>');
-- ERROR: invalid xml content

-- 단일 루트로 감싸서 해결
SELECT XMLPARSE(DOCUMENT '<root><item>A</item><item>B</item></root>');

-- 여러 XML 조각을 안전하게 합치는 방법
WITH xml_fragments AS (
    SELECT '<item>A</item>' AS frag
    UNION ALL
    SELECT '<item>B</item>'
)
SELECT XMLPARSE(DOCUMENT
    '<root>' || string_agg(frag, '') || '</root>'
)
FROM xml_fragments;

-- XML 타입 컬럼에서 문제 데이터 업데이트
UPDATE product_catalog
SET xml_description = XMLPARSE(DOCUMENT
    '<description>' || raw_text || '</description>'
)
WHERE xml_description IS NULL
  AND raw_text IS NOT NULL
  AND is_valid_xml('<description>' || raw_text || '</description>') = TRUE;

예방 방법

  • 애플리케이션 레벨에서 XML 유효성 검증 후 DB 저장

DB에 XML 데이터를 저장하기 전에 반드시 애플리케이션 단에서 XML 파서를 통한 유효성 검증을 수행하고, 유효한 데이터만 INSERT/UPDATE 하도록 합니다. 또한 스테이징 테이블(TEXT 타입)에 먼저 적재한 후 위에서 작성한 is_valid_xml() 함수로 배치 검증을 거쳐 XML 타입 컬럼으로 이관하는 2단계 파이프라인을 구축하면 운영 테이블에 유효하지 않은 XML이 유입되는 것을 원천 차단할 수 있습니다.

```sql

-- 스테이징에서 운영 테이블로 안전하게 이관

INSERT INTO production_xml_table (id, xml_data, created_at)

SELECT id, XMLPARSE(DOCUMENT raw_xml), NOW()

FROM staging_xml_table

WHERE is_valid_xml(raw_xml) = TRUE

AND processed = FALSE;

-- 실패 건은 에러 로그 테이블로 이동

INSERT INTO xml_error_log (id, raw_xml, error_time)

SELECT id, raw_xml, NOW()

FROM staging_xml_table

WHERE is_valid_xml(raw_xml) = FALSE

AND processed = FALSE;

```

  • XML 생성 시 문자열 연결 대신 PostgreSQL 내장 XML 함수 사용

XML 데이터를 동적으로 생성할 때 문자열 연결(||) 방식을 지양하고, xmlelement(), xmlforest(), xmlagg(), xmlcomment() 등 PostgreSQL 내장 XML 함수를 사용합니다. 이 함수들은 특수 문자를 자동으로 이스케이프하고 올바른 XML 구조를 보장하므로 2200N 에러 발생 가능성을 크게 줄여줍니다.

```sql

-- 권장: 내장 함수 사용 (특수문자 자동 이스케이프)

SELECT xmlelement(name order,

xmlattributes(o.order_id AS id, o.order_date AS date),

xmlforest(

c.customer_name AS customer,

o.total_amount AS total

)

)

FROM orders o

JOIN customers c ON o.customer_id = c.id;

```


관련 에러

  • 2200M (invalid XML document): XML 문서 선언은 올바르지만 내용이 유효하지 않을 때 발생하며, 2200N과 혼동될 수 있습니다.
  • 22000 (data exception): XML 관련 에러의 상위 카테고리 에러 코드입니다.
  • 42804 (datatype mismatch): TEXT 타입 데이터를 XML 타입 컬럼에 명시적 캐스팅 없이 삽입할 때 발생합니다.
  • 22021 (character not in repertoire): XML 처리 중 지원되지 않는 문자 인코딩이 발견될 때 함께 발생할 수 있습니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기