xpath로 CSS 클래스 선택


87

.date라는 클래스 만 선택하고 싶습니다.

어떤 이유로이 작업을 수행 할 수 없습니다. 누군가 내 코드에 무엇이 잘못되었는지 알고 있다면 대단히 감사하겠습니다.

@$doc = new DOMDocument();
@$doc->loadHTML($html);
$xml = simplexml_import_dom($doc); // just to make xpath more simple
$images = $xml->xpath('//[@class="date"]');                             
foreach ($images as $img)
{
    echo  $img." ";
}

2
그리고 html 조각은 어떻습니까? (xpath에 더 가깝기 때문에 asXML ()의 simpleXml 출력을 표시하는 것을 선호합니다.)
SergeS

해야 할 수업이 여러 개인 경우contains(@class, 'date')
Gordon



@Gordon의 대답은 위험합니다. 클래스 속성이 "datetime"이면 일치합니다. user716736의 답변이 더 완벽합니다.
Niels Bom

답변:


242

위의 답변에 문제가 있기 때문에이 질문에 대한 정식 답변을 작성하고 싶습니다.

우리의 문제

CSS의 선택 :

.foo

foo 클래스를 가진 모든 요소를 ​​선택합니다 .

XPath에서이 작업을 어떻게 수행합니까?

XPath는 CSS보다 강력하지만 XPath 에는 CSS 클래스 선택기에 해당하는 기본 기능이 없습니다 . 그러나 해결책이 있습니다.

그것을하는 올바른 방법

XPath 에서 동등한 선택기는 다음과 같습니다 .

//*[contains(concat(" ", normalize-space(@class), " "), " foo ")]

normalize-space 함수는 선행 및 후행 공백을 제거하고 공백 문자 시퀀스를 단일 공백으로 바꿉니다.

(보다 일반적인 의미에서) 이것은 또한 CSS 선택자와 동일합니다.

*[class~="foo"]

클래스 속성 값이 공백으로 구분 된 값 목록 인 모든 요소와 일치 하며 그중 하나는 foo 와 정확히 동일합니다 .

몇 가지 분명하지만 잘못된 방법

XPath 선택기 :

//*[@class="foo"]

작동하지 않습니다! 예를 들어 둘 이상의 클래스가있는 요소와 일치하지 않기 때문입니다.

<div class="foo bar">

클래스 이름 주위에 추가 공백이 있으면 일치하지 않습니다.

<div class="  foo ">

'개선 된'XPath 선택기

//*[contains(@class, "foo")]

작동하지 않습니다! 예를 들어 foobar 클래스와 요소를 잘못 일치시키기 때문입니다.

<div class="foobar">

신용은 웹에서 찾은이 문제에 대한 가장 초기에 발표 된 솔루션 인이 친구에게 돌아갑니다. http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- in-xpathxslt /


공간 정규화의 필요성은 무엇입니까?
Freek 2014 년

"위의 답변"은 아마도 MrGlass를 가리킬 것입니다.
LarsH

이것이 가능 <div class="foo\tbar">합니까? 즉, 탭으로 구분 된 클래스 이름입니다.
Frozen Flame

1
그러나 <div class = "group-conditions"/> 및 <div class = "condition"/>은 $ x ( '// div [contains (concat ( "", normalize-space (@class), ")에 대해 동일합니다. "),"condition ")] ')
Memke

1
@ testerjoe2 시도 //*[contains(concat(" ", normalize-space(@class), " "), " foo ")]했습니까?
Niels Bom 2018

11

//[@class="date"] 유효한 xpath가 아닙니다.

을 시도 //*[@class="date"]하거나 이미지 인 것을 알고 있으면//img[@class="date"]


7

XPath 3.1 은 함수 포함 토큰을 도입 하여 마침내이를 '공식적으로'해결합니다. 클래스지원 하도록 설계되었습니다 .

예:

//*[contains-token(@class, "foo")]

이 함수는 공백 ( (U + 0020) 뿐만 아니라 )이 올바르게 처리되고 클래스 이름이 반복되는 경우 작동하며 일반적으로 가장자리 케이스를 덮도록합니다.


참고 : 오늘 (2016-12-13) 현재 XPath 3.1은 후보 추천 상태입니다 .


오늘의 최신 크롬에서는 작동하지 않습니다. 작동 할 때까지 // * [contains (@class, "foo")]가 foobar, fooz 등과 같이 foo를 포함하는 모든 클래스도 선택한다는 제한을 어떻게 피할 수 있습니까?
MasterJoe


1

HTML은 대소 문자를 구분하지 않는 요소 및 속성 이름을 허용하며 class는 공백으로 구분 된 클래스 이름 목록입니다. 여기에 img태그와 class이름이 있습니다 date.

//*['IMG' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')]/@*['CLASS' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') and contains(concat(' ', normalize-space(.), ' '), concat(' ', 'date', ' '))]

참조 : CSS 선택기를 XPath로 변환


1

템플릿에서 마이너스 기호를 조심하십시오! DOM에서 "my-ownclass"를 쿼리하는 경우 :

<ul class="my-ownclass"><li>...</li></ul>
<ul class="someother"><li>...</li></ul>
<ul><li>...</li></ul>

$finder = new DomXPath($dom);
$nodes = $finder->query(".//ul[contains(@class, 'my-ownclass')]"); // This will NOT behave as expected! This will strangely match all the <ul> elements in DOM.
$nodes = $finder->query(".//ul[contains(@class, 'ownclass')]"); // This will match the element.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.