XRX 아키텍처로 XML 폼과 REST 서비스를 연결하는 방법
XForms, REST, XQuery를 조합한 XRX 아키텍처의 데이터 흐름, 구현 방식, 운영 고려사항과 XML 중심 업무 시스템 적용 기준을 정리합니다.
2026-08-14 · 최초 발행 2025-10-14
XML을 데이터 흐름의 중심에 두는 XRX
XRX는 XForms, REST, XQuery를 결합해 입력부터 검증, 저장, 변환, 응답까지 XML 중심으로 처리하는 아키텍처다. XForms가 UI와 검증을 선언하고, REST가 리소스 접근을 맡으며, XQuery가 XML 저장소의 CRUD와 변환을 수행한다.
클라이언트는 XForms View에서 입력한 XML 인스턴스를 검증한 뒤 REST로 제출한다. 서버에서는 XQuery가 저장소와 상호작용하고, 처리 결과를 XML·HTML·JSON 등의 Representation으로 돌려준다. W3C 표준과의 호환을 유지하면서 문서형 데이터와 폼 기반 업무를 다루려는 구성이다.
표현 변경과 데이터 구조를 분리하는 방식
XForms의 Model은 데이터 인스턴스와 바인딩, 데이터 타입, 기본값, 제출 대상을 관리한다. View는 입력 컨트롤과 반복·섹션 구성을 담당한다. CSS와 XSLT는 스타일과 표현 변환을 맡으므로 데이터 구조와 표현을 각각 바꿀 수 있다.
검증 규칙도 XForms와 XPath로 선언한다. required(), pattern, type(xs:*) 같은 제약을 통해 클라이언트에서 먼저 검증하고, Submit Control에서 트랜잭션 경계와 예외 처리, 상태 반영 정책을 제어한다. 입력→검증→변환→저장→전달 과정에 XML을 유지하면 형식 변환에서 생기는 임피던스 미스매치와 변환 비용을 줄일 수 있다.
REST 경로와 XML 표현을 설계할 때
REST 계층은 리소스 이름, HTTP 메서드, 표현 방식을 분명히 나눈다. /orders, /customers/{id}처럼 컬렉션과 개별 리소스의 경로를 구분하고, GET·POST·PUT·PATCH·DELETE의 의미적 일관성과 멱등성·안전성 원칙을 지킨다.
표현은 Content Negotiation으로 다룬다. application/xml을 기본으로 두고 필요에 따라 HTML이나 JSON을 제공하며, ETag와 Cache-Control도 함께 관리한다. XML Schema나 DTD는 스키마 검증에, XSLT는 뷰와 보고서 변환에, CSS는 스타일 적용에 사용된다.
요청이 저장소까지 도달하는 흐름
단일 문서 쓰기는 원자성을 보장한다. 다문서 갱신 지원은 제품별로 다르므로 최신 정보 확인이 필요하다. 동시성 충돌은 If-Match를 이용한 조건부 요청으로 낙관적 잠금을 구현하는 방식을 권장한다.
모델에서 운영 정책까지 연결하기
정보 모델은 DTD 또는 XML Schema로 설계하고 네임스페이스와 컬렉션 구조를 정의한다. 식별자 전략으로 UUID나 ULID를 정하고, version, etag 같은 버전 속성을 포함한다.
XForms에서는 Model, Instance, Bind, Constraints를 선언한 뒤 Submit Control을 REST 엔드포인트와 연결한다. 스타일은 CSS로 분리하고 aria-* 접근성 속성을 준수한다. API는 자원 경로, HTTP 메서드, 상태 코드, ETag 규칙을 먼저 정하며, Content-Type과 Accept는 XML을 우선으로 삼고 캐시와 오류 스키마를 통일한다.
XQuery 서비스는 CRUD 함수와 XSLT 연계 변환을 모듈화한다. 스키마 검증, 로깅, 그리고 400·404·409·422·500 오류 매핑도 포함한다. 운영 단계에서는 XXE를 비활성화하고 입력 길이 및 스키마를 검증하며, OAuth2/OIDC 인증·인가, CORS 정책, 감사 로그와 백업을 준비한다.
XForms, REST, XQuery 코드 예시
서버는 eXist-db 6.x 또는 MarkLogic 10.x(RESTXQ 지원), XQuery 3.1을 전제로 한다. UI는 Orbeon Forms 2023.1(서버 렌더링 XForms) 또는 betterFORM을 사용하며, 클라이언트와 서버는 UTF-8 및 application/xml을 사용한다.
Orbeon 호환 XForms
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Order Form</title>
<link rel="stylesheet" href="/static/forms.css"/>
<xf:model id="m">
<xf:instance id="order">
<order xmlns="">
<id/>
<customer/>
<items>
<item><sku/><qty>1</qty></item>
</items>
<version>0</version>
</order>
</xf:instance>
<xf:bind nodeset="id" type="xs:string" required="true()"/>
<xf:bind nodeset="customer" type="xs:string" required="true()"/>
<xf:bind nodeset="items/item/qty" type="xs:integer" constraint=". > 0"/>
<xf:submission id="submit-create"
method="post"
action="/api/orders"
ref="instance('order')"
mediatype="application/xml"
replace="none"/>
</xf:model>
</head>
<body>
<h1>Order</h1>
<xf:input ref="id"><xf:label>ID</xf:label></xf:input>
<xf:input ref="customer"><xf:label>Customer</xf:label></xf:input>
<xf:repeat ref="items/item">
<xf:input ref="sku"><xf:label>SKU</xf:label></xf:input>
<xf:input ref="qty"><xf:label>Qty</xf:label></xf:input>
</xf:repeat>
<xf:submit submission="submit-create"><xf:label>Submit</xf:label></xf:submit>
</body>
</html>
XML 리소스 호출
# 생성
curl -i -H "Content-Type: application/xml" \
-d @order.xml \
-X POST https://example.com/api/orders
# 조회(ETag 활용)
curl -i -H "Accept: application/xml" \
https://example.com/api/orders/123
# 조건부 갱신(낙관적 잠금)
curl -i -H "Content-Type: application/xml" \
-H 'If-Match: "etag-value"' \
-d @order.xml \
-X PUT https://example.com/api/orders/123
RESTXQ 기반 XQuery
xquery version "3.1";
module namespace app="http://example.com/app";
declare namespace rest="http://exquery.org/ns/restxq";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare %rest:POST("orders") %rest:path("/api/orders")
%rest:consumes("application/xml") %output:method("xml")
function app:create-order($body as node()) as node() {
let $id := util:uuid()
let $doc := <order id="{$id}">{ $body/*/* }</order>
let $store := xmldb:store("/db/orders", concat($id, ".xml"), $doc)
return <result status="ok" id="{$id}"/>
};
declare %rest:GET("orders") %rest:path("/api/orders/{$id}")
%rest:produces("application/xml")
function app:get-order($id as xs:string) as node()? {
doc(concat("/db/orders/", $id, ".xml"))
};
문서와 복잡한 검증이 중심인 업무
전자정부나 공공 민원 양식은 다단계 검증, 첨부, 서명을 포함하는 워크플로우에서 문서 원본을 XML로 보존하고 XSLT로 여러 증명서 표현을 출력할 수 있다.
규정·매뉴얼·계약서처럼 문서형 데이터를 다루는 CMS에서도 저장과 버전 관리, 웹·PDF·모바일 표현을 병행하는 데 맞는다. 연구·출판 데이터 포털은 계층형·반정형 데이터를 수집, 정규화, 검색하고 메타데이터 스키마화와 장기 보존을 수행할 수 있다. 금융 상품 가입과 심사에서는 복잡한 제약과 계산을 선언적으로 모델링하고, 규정 변경 때 UI와 검증을 분리하는 효과를 기대할 수 있다.
폼과 검증을 선언화하면 프런트엔드와 백엔드의 중복을 줄여 화면·로직 변경 리드타임을 20~40% 단축할 수 있다. 스키마와 Bind에 기반한 이중 검증은 입력 오류를 30%+ 줄이고 회귀 결함 감소에 기여한다. 변환 단계를 줄이면 통신·변환 코드는 25% 감소하며, 문서 보존 및 감사 요구 대응 비용도 낮출 수 있다. 무상태 REST와 캐시 정책은 수평 확장에 적합하고, XML DB의 샤딩·인덱싱은 대용량 문서 처리를 지원할 수 있으나 제품별 특성이 다르므로 최신 정보 확인이 필요하다.
채택 전에 확인할 제약
계약 우선의 스키마 주도 설계와 멱등 요청, If-Match, ETag를 채택한다. XXE 및 DTD 외부 엔티티를 비활성화하고 입력 길이를 제한하며 스키마 검증을 필수로 둔다. 오류 표현은 application/problem+xml로 표준화하고 로깅과 추적 ID를 포함한다.
XML 페이로드는 크기와 파싱 비용을 늘릴 수 있어 JSON보다 네트워크 효율이 낮을 수 있다. 네이티브 XForms를 지원하는 브라우저도 제한적이므로 Orbeon이나 betterFORM 같은 서버 렌더링 또는 엔진 도입이 필요하다. XQuery 경험 인력은 제한될 수 있으므로 내부 교육과 가이드를 마련해야 한다.
| 항목 | XRX(XML 중심) | 전통 SPA(JSON+REST) |
|---|---|---|
| 성능 | 문서형 질의·변환에 강점(XQuery, XSLT). XML 오버헤드 존재 | 경량 페이로드/클라이언트 렌더링. 대규모 DOM 관리 비용 |
| 확장성 | 무상태 REST+캐시, XML DB 인덱스/샤딩(제품별) | 무상태 API+CDN, 프런트 분산 용이 |
| 일관성 | 스키마+XForms 제약의 이중 검증, 표현·데이터 분리 | JSON 스키마 선택적 적용, 검증 일관성 편차 |
| 안정성 | W3C 표준 기반, 로킹/버전 관리 명확 | 광범위 도구/커뮤니티, 종속성 변동성 존재 |
| 운영 편의 | 엔드투엔드 XML 파이프라인, 보존·감사 적합 | 인력 확보 용이, JSON/JS 친화 |