XPath 축(Axis)과 술어로 XML 트리를 정밀하게 짚어내는 법
XPath의 축·노드 테스트·술어 조합, 네임스페이스 바인딩, 버전별 데이터 모델 차이를 웹 스크래핑·ETL·XSLT 연계 관점에서 정리한다.
2026-08-13 · 최초 발행 2025-12-03
XML·HTML 같은 트리 구조 문서에서 원하는 노드와 값을 뽑아내는 방법은 여러 가지지만, 위치·조상 관계·값 조건을 한 표현식 안에 결합해 선언적으로 짚어낼 수 있는 언어는 많지 않다. XPath(XML Path Language)가 그 자리를 맡는다. XSLT, XQuery, 브라우저 DOM API, 백엔드 통합 파이프라인 등 여러 계층에서 표준화된 선택·집계·탐색 수단으로 쓰인다.
축·노드 테스트·술어의 조합
XPath는 문서 트리를 축(Axis), 노드 테스트, 술어(Predicate), 함수로 탐색한다. 반환값은 노드 집합(node-set/sequence)이거나 string·number·boolean·dateTime 같은 스칼라 값이다. 버전은 1.0 → 2.0 → 3.1로 발전해왔는데, 타입 시스템과 함수·연산자가 늘고 3.1에서는 맵·어레이 같은 구조까지 다룰 수 있게 됐다.
축(Axes)과 경로 표현
자식(child), 자손(descendant), 조상(ancestor), 형제(sibling), 속성(attribute) 등 13개 축이 탐색 구조의 기반이다. 절대 경로(/)와 상대 경로(//, ..)를 섞어 쓸 수 있고, 축 선택에 노드 테스트(이름, node(), text(), *)와 술어([@id='x'], [position()=1])를 결합해 최종 표현식을 완성한다.
노드 집합과 데이터 타입
XPath 1.0은 node-set과 string/number/boolean 중심 모델이고, XPath 2.0 이상은 sequence와 풍부한 정적 타입을 더했다. position(), last() 같은 위치 기반 접근과 스칼라 함수 처리 메커니즘도 이 모델 위에서 동작한다.
네임스페이스 처리
접두사(prefix)를 URI에 바인딩해 QName을 해석하는 구조라, 식을 평가할 때 컨텍스트에 네임스페이스 맵이 반드시 있어야 한다. HTML과 XML이 섞인 문서나 기본 네임스페이스(default namespace)가 있는 경우 혼동을 막으려면 명시적으로 바인딩해두는 편이 안전하다.
함수 라이브러리와 확장성
string(), normalize-space(), contains(), starts-with(), sum(), count() 같은 core 함수를 기본 제공하고, 2.0 이상에서는 정규식·날짜/시간·시퀀스 함수까지 확장됐다. Saxon·libxml2 같은 구현체별 확장 함수도 쓸 수 있지만 이식성이 떨어지는 트레이드오프가 있다.
평가 엔진과 최적화
파서 → AST → 평가기 실행이라는 파이프라인 구조 위에서, 술어 푸시다운·상수 폴딩·인덱스 활용 같은 최적화가 가능하다. DOM 메모리 기반으로 평가할지 스트리밍(SAX, pull)으로 평가할지는 문서 크기·지연시간·메모리 한계에 따라 전략을 달리 세워야 한다.
활용 사례
웹 스크래핑·테스트 자동화에서는 동적 DOM에서 안정적으로 요소를 선택하거나 CSS 셀렉터로 표현하기 곤란한 관계성을 탐색하는 데 XPath가 유리하다. 위치·속성·텍스트를 조합해 추출하면 UI 구조 변화에 강한 선택자를 설계할 수 있다.
XML 기반 통합·ETL에서는 SOAP/REST XML 응답이나 금융·공공 표준 XML 스키마를 변환할 때 필드 매핑을 추출하는 데 쓰인다. 다중 네임스페이스 문서에서도 일관되게 추출할 수 있고, 대량 문서 처리 파이프라인에서는 컴파일된 XPath를 재사용해 처리량을 높인다.
XSLT/XQuery 연계에서는 XSLT 템플릿 매칭이나 XQuery FLWOR 문 안에서 노드를 선택하는 핵심 구성 요소가 XPath다. 동일한 XPath 표현식을 재사용하면 규칙 일관성을 확보할 수 있고, 스키마 인식(schema-aware) 처리를 결합하면 타입 안전성도 강화된다.
설정 검증·정책 규칙 엔진에서는 XML 구성 파일이 정책을 준수하는지, 금칙 조건이나 필수 속성 부재, 값 범위 위반 등을 자동으로 검사하는 데 쓰인다.
프로세스 다이어그램: XPath 평가 흐름
입력에서 처리, 출력까지 단계를 명확히 구분해두면 오류가 났을 때 컨텍스트·네임스페이스부터 검증하기가 쉬워진다. 대용량 문서를 다룰 때는 스트리밍 평가를 도입해 DOM 구축 자체를 생략하는 편이 낫다.
코드 예시
전제조건은 Python 3.11+에 lxml 5.x(pip install lxml)이고, 브라우저 DOM 예시는 Chrome 120+ 또는 최신 Firefox를 기준으로 한다.
샘플 XML은 기본 네임스페이스와 bk 접두사 네임스페이스가 섞인 카탈로그다.
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://ex.com/ns" xmlns:bk="http://ex.com/book">
<bk:book id="b1" category="fiction">
<title lang="en">The Maze</title>
<author>Jane Doe</author>
<price>12.50</price>
</bk:book>
<bk:book id="b2" category="tech">
<title lang="en">Data Pipes</title>
<author>John Roe</author>
<price>29.00</price>
</bk:book>
</catalog>
Python(lxml)에서는 네임스페이스 맵을 명시적으로 지정해 질의한다.
from lxml import etree
xml = etree.fromstring(open("catalog.xml", "rb").read())
ns = {
"d": "http://ex.com/ns", # default namespace에 접두사 부여
"bk": "http://ex.com/book",
}
# 1) tech 카테고리 도서의 제목
titles = xml.xpath("//bk:book[@category='tech']/d:title/text()", namespaces=ns)
print(titles) # ['Data Pipes']
# 2) 가격이 20 이상인 도서의 @id
ids = xml.xpath("//bk:book[number(d:price) >= 20]/@id", namespaces=ns)
print(ids) # ['b2']
# 3) 컴파일 후 재사용(성능)
expr = etree.XPath("//bk:book[d:price < 20]/d:title/text()", namespaces=ns)
print(expr(xml)) # ['The Maze']
기본 네임스페이스가 있으면 요소 선택 시 항상 접두사를 써야 하고, number()나 text() 같은 함수의 암시적 캐스팅 결과도 확인해두는 게 좋다.
브라우저 DOM에서는 document.evaluate로 같은 작업을 한다.
<script>
// XML 파싱
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "application/xml");
const nsResolver = (prefix) =>
({
d: "http://ex.com/ns",
bk: "http://ex.com/book",
})[prefix] || null;
// 첫 번째 도서 제목
const result = xmlDoc.evaluate(
"//bk:book[1]/d:title/text()",
xmlDoc,
nsResolver,
XPathResult.STRING_TYPE,
null,
);
console.log(result.stringValue); // The Maze
</script>
document.evaluate는 반환 타입(XPathResult.*_TYPE)을 반드시 지정해야 하고, 네임스페이스 리졸버도 함께 제공해야 한다.
모범사례와 트레이드오프
선택자를 설계할 때는 구조 안정성을 우선해야 한다. 위치 인덱스를 남용하기보다 고유 속성·키 기반 선택을 권장하고, 텍스트 매칭은 normalize-space()로 공백을 정규화하되 contains()를 남용하면 오탐이 늘어나는 트레이드오프가 있다.
네임스페이스 관리에서는 기본 네임스페이스가 있으면 모든 요소에 접두사를 붙이는 원칙을 지켜야 한다. 혼합 문서에서는 접두사 충돌을 막기 위해 명확한 맵을 유지해야 하는데, 실제로 런타임 실패 대부분이 네임스페이스 해석 오류에서 발생하므로 초기화 단계에서 검증 절차를 두는 게 좋다.
성능·확장성 측면에서는 반복 실행되는 표현식을 컴파일·캐시하는 전략이 유효하다. 입력 크기 N을 기준으로 처리량이 1.5~3배 개선된 경험치가 있는데 환경에 따라 다르다. DOM 전체를 구축하기엔 메모리가 부족하면 스트리밍 평가를 도입해야 하지만, 그만큼 표현식에 제약이 늘어나는 트레이드오프가 따른다.
운영·디버깅에서는 표현식을 린팅하고 테스트 케이스화하며, 실패 시 최소 재현 가능한 XML 샘플을 보관해두는 게 도움이 된다. 1.0과 2.0/3.1, 브라우저와 서버 엔진 간 해석 차이로 이식성 리스크가 있으니 공통 교집합 규칙서를 운영하는 편이 낫다.
XPath 버전별 실무 지표
| 지표 | XPath 1.0 | XPath 2.0 | XPath 3.1 | 실무 영향 |
|---|---|---|---|---|
| 성능 | 단순 타입, 최적화 제한 | 정적 타입 기반 최적화 가능 | 맵/어레이 도입, 엔진 최적화 성숙 | 대규모 질의에서 10~30% 개선 가능성 |
| 확장성 | 구현체 확장 함수 의존 | 풍부한 표준 함수 | JSON 유사 구조 처리 강화 | 복합 데이터 처리 단순화 |
| 일관성 | 엔진별 해석 차이 존재 | 스키마 인식 일관성 강화 | 함수/타입 표준화 진전 | 멀티엔진 간 결과 일치도 개선 |
| 안정성 | 암시적 캐스팅 오류 잠재 | 타입 시스템 강화 | 예외 의미 명확화 | 런타임 오류 감소 |
| 운영 편의 | 도구/라이브러리 풍부 | 학습 곡선 증가 | 최신 엔진 필요 | 도입 전 호환성 검토 필요 |
최신 명세·엔진 지원 여부는 별도로 확인해야 한다.
선언형으로 옮겼을 때 달라지는 것들
복잡한 선택·필터 로직을 XPath로 선언적으로 옮기면 코드량이 3050% 줄어들 가능성이 있고, 규칙 재사용성도 함께 좋아진다. 표현식을 컴파일·캐시하고 네임스페이스를 사전 바인딩해두면 반복 질의 처리량이 1.53배 개선될 가능성이 있다. 테스트 가능한 선언적 규칙으로 정리해두면 회귀 결함이 20~40% 줄어들 것으로 기대할 수 있고, 이식성을 고려한 공통 규칙서를 운영하면 엔진 교체 비용도 완화된다. 다만 이 수치들은 프로젝트 규모·문서 구조·엔진에 따라 달라진다.
트리 구조 문서를 다룰 때 XPath의 본질은 축·술어·함수의 조합으로 선언적이고 정밀한 탐색을 제공한다는 데 있다. 네임스페이스를 명시하고 표현식을 컴파일·캐시하며 스트리밍/DOM 전략을 상황에 맞게 병행하고, 여러 엔진을 아우르는 공통 규칙서를 운영하는 것이 XSLT/XQuery·테스트 자동화·ETL 전반에서 추출 안정성과 성능, 유지보수성을 함께 얻는 길이다.