Xpath 빠른 참고표
셀렉터
자손 셀렉터
| CSS | Xpath | ? |
|---|---|---|
h1 | //h1 | ? |
div p | //div//p | ? |
ul > li | //ul/li | ? |
ul > li > a | //ul/li/a | |
div > * | //div/* | |
:root | / | ? |
:root > body | /body |
속성 셀렉터
| CSS | Xpath | ? |
|---|---|---|
#id | //*[@id="id"] | ? |
.class | //*[@class="class"] ...kinda | |
input[type="submit"] | //input[@type="submit"] | |
a#abc[for="xyz"] | //a[@id="abc"][@for="xyz"] | ? |
a[rel] | //a[@rel] | |
a[href^='/'] | //a[starts-with(@href, '/')] | ? |
a[href$='pdf'] | //a[ends-with(@href, '.pdf')] | |
a[href*='://'] | //a[contains(@href, '://')] | |
a[rel~='help'] | //a[contains(@rel, 'help')] ...kinda |
순서 셀렉터
| CSS | Xpath | ? |
|---|---|---|
ul > li:first-of-type | //ul/li[1] | ? |
ul > li:nth-of-type(2) | //ul/li[2] | |
ul > li:last-of-type | //ul/li[last()] | |
li#id:first-of-type | //li[1][@id="id"] | ? |
a:first-child | //*[1][name()="a"] | |
a:last-child | //*[last()][name()="a"] |
형제 요소
| CSS | Xpath | ? |
|---|---|---|
h1 ~ ul | //h1/following-sibling::ul | ? |
h1 + ul | //h1/following-sibling::ul[1] | |
h1 ~ #id | //h1/following-sibling::[@id="id"] |
jQuery
| CSS | Xpath | ? |
|---|---|---|
$('ul > li').parent() | //ul/li/.. | ? |
$('li').closest('section') | //li/ancestor-or-self::section | |
$('a').attr('href') | //a/@href | ? |
$('span').text() | //span/text() |
기타
| CSS | Xpath | ? |
|---|---|---|
h1:not([id]) | //h1[not(@id)] | ? |
| 텍스트 일치 | //button[text()="Submit"] | ? |
| 텍스트 일치(부분) | //button[contains(text(),"Go")] | |
| 산술 비교 | //product[@price > 2.50] | |
| 자식 요소 있음 | //ul[*] | |
| 특정 자식 요소 있음 | //ul[li] | |
| OR 로직 | //a[@name or @href] | ? |
| 합집합(결과 결합) | //a | //div | ? |
Class check
//div[contains(concat(' ',normalize-space(@class),' '),' foobar ')]
Xpath에는 “공백으로 구분된 목록에 포함되는지”를 바로 확인하는 연산자가 없으므로 위 방식이 일반적입니다.
표현식
스텝과 축
// | ul | / | a[@id='link'] |
|---|---|---|---|
| 축 | 스텝 | 축 | 스텝 |
접두사
| 접두사 | 예시 | 의미 |
|---|---|---|
// | //hr[@class='edge'] | 아무 위치 |
./ | ./a | 상대 경로 |
/ | /html/body/div | 루트 |
표현식은 어떤 접두사로 시작해도 됩니다.
축
| 축 | 예시 | 의미 |
|---|---|---|
/ | //ul/li/a | 자식 노드 |
// | //[@id="list"]//a | 후손 노드 |
스텝은 /로 구분합니다. 직접 자식만 선택하지 않으려면 //를 사용하세요.
스텝
//div
//div[@name='box']
//[@id='link']
스텝은 요소 이름(div)과 조건절([...])로 구성되며 둘 다 생략 가능합니다. 다음과 같은 형태도 가능합니다:
//a/text() #=> "Go home"
//a/@href #=> "index.html"
//a/* #=> All a's child elements
조건절
조건절
//div[true()]
//div[@class="head"]
//div[@class="head"][@id="top"]
조건이 참일 때만 노드셋을 유지합니다. 조건절은 체이닝할 수 있습니다.
연산자
# Comparison
//a[@id = "xyz"]
//a[@id != "xyz"]
//a[@price > 25]
# Logic (and/or)
//div[@id="head" and position()=2]
//div[(x and y) or not(z)]
비교/논리 연산자로 조건을 구성합니다.
노드 사용
# Use them inside functions
//ul[count(li) > 2]
//ul[count(li[@class='hide']) > 0]
# This returns `<ul>` that has a `<li>` child
//ul[li]
노드는 조건절 안에서 직접 사용할 수 있습니다.
인덱싱
//a[1] # first <a>
//a[last()] # last <a>
//ol/li[2] # second <li>
//ol/li[position()=2] # same as above
//ol/li[position()>1] # :not(:first-of-type)
[] 안에 숫자, last(), position()을 사용합니다.
체이닝 순서
a[1][@href='/']
a[@href='/'][1]
순서에 따라 결과가 달라집니다.
중첩 조건절
//section[.//h1[@id='hi']]
<section>에 id='hi'인 <h1> 후손이 있으면 매칭됩니다.
함수
노드 함수
name() # //[starts-with(name(), 'h')]
text() # //button[text()="Submit"]
# //button/text()
lang(str)
namespace-uri()
count() # //table[count(tr)=1]
position() # //ol/li[position()=2]
불리언 함수
not(expr) # button[not(starts-with(text(),"Submit"))]
문자열 함수
contains() # font[contains(@class,"head")]
starts-with() # font[starts-with(@class,"head")]
ends-with() # font[ends-with(@class,"head")]
concat(x,y)
substring(str, start, len)
substring-before("01/02", "/") #=> 01
substring-after("01/02", "/") #=> 02
translate()
normalize-space()
string-length()
타입 변환
string()
number()
boolean()
축
축 사용
//ul/li # ul > li
//ul/child::li # ul > li (same)
//ul/following-sibling::li # ul ~ li
//ul/descendant-or-self::li # ul li
//ul/ancestor-or-self::li # $('ul').closest('li')
스텝은 보통 /로 자식 노드를 선택하지만, ::로 다른 축을 지정할 수 있습니다.
// | ul | /child:: | li |
|---|---|---|---|
| 축 | 스텝 | 축 | 스텝 |
자식 축
# both the same
//ul/li/a
//child::ul/child::li/child::a
child::가 기본 축입니다. 그래서 //a/b/c가 동작합니다.
# both the same
# this works because `child::li` is truthy, so the predicate succeeds
//ul[li]
//ul[child::li]
# both the same
//ul[count(li) > 2]
//ul[count(child::li) > 2]
후손-자기 축
# both the same
//div//h4
//div/descendant-or-self::h4
//는 descendant-or-self:: 축의 축약형입니다.
# both the same
//ul//[last()]
//ul/descendant-or-self::[last()]
기타 축
| 축 | 약어 | 비고 |
|---|---|---|
ancestor | ||
ancestor-or-self | ||
attribute | @ | @href는 attribute::href의 축약형 |
child | div는 child::div의 축약형 | |
descendant | ||
descendant-or-self | // | //는 /descendant-or-self::node()/의 축약형 |
namespace | ||
self | . | .는 self::node()의 축약형 |
parent | .. | ..는 parent::node()의 축약형 |
following | ||
following-sibling | ||
preceding | ||
preceding-sibling |
다른 축도 사용할 수 있습니다.
합집합
//a | //span
|로 두 표현식을 결합합니다.
추가 예시
예시
//* # all elements
count(//*) # count all elements
(//h1)[1]/text() # text of the first h1 heading
//li[span] # find a <li> with an <span> inside it
# ...expands to //li[child::span]
//ul/li/.. # use .. to select a parent
부모 찾기
//section[h1[@id='section-name']]
h1#section-name를 직접 포함하는 <section>을 찾습니다.
//section[//h1[@id='section-name']]
h1#section-name를 포함하는 <section>을 찾습니다. (위와 같지만 child 대신 descendant-or-self를 사용합니다.)
가장 가까운 조상
./ancestor-or-self::[@class="box"]
jQuery의 $().closest('.box')와 유사합니다.
속성
//item[@price > 2*@discount]
<item>을 찾고 속성을 검사합니다.
테스트
브라우저 콘솔
$x("//div")