특정 문자열이 포함 된 속성에서 어떻게 일치시킬 수 있습니까?


442

속성에 둘 이상의 단어가 포함 된 경우 속성별로 노드를 선택하는 데 문제가 있습니다. 예를 들면 다음과 같습니다.

<div class="atag btag" />

이것은 내 xpath 표현입니다.

//*[@class='atag']

표현은

<div class="atag" />

그러나 이전 예제에는 해당되지 않습니다. 를 어떻게 선택할 수 <div>있습니까?


9
"atag btag"는 두 가지가 아니라 하나의 속성이라는 점을 지적 할 가치가 있습니다. xpath에서 하위 문자열 일치를 시도하고 있습니다.
skaffman

3
네 당신 말이 맞아요-내가 원하는 것입니다.
crazyrails


1
CSS 선택기를 사용해야하는 이유는 ... div.atag또는 div.btag입니다. 문자열 일치가 아닌 매우 간단하고 더 빠릅니다 (브라우저에서 더 잘 지원됩니다). HTML에 대한 XPath는 포함 된 텍스트로 요소를 찾고 DOM 탐색에 유용한 것으로 강등되어야합니다.
JeffC

답변:


486

다음은 className에 포함 된 div 요소를 찾는 예입니다 atag.

//div[contains(@class, 'atag')]

다음은 className이 포함 atag하고 div 요소를 찾는 예제입니다 btag.

//div[contains(@class, 'atag') and contains(@class ,'btag')]

그러나와 같은 부분 일치도 찾습니다 class="catag bobtag".

부분적으로 일치하지 않으려면 아래 bobince의 답변을 참조하십시오.


123
@ Redbeard : 문자 그대로의 대답이지만 일반적으로 클래스 일치 솔루션이 목표로하는 것은 아닙니다. 특히 <div class="Patagonia Halbtagsarbeit">대상 문자열을 포함하지만 주어진 클래스의 div는 아닙니다.
bobince

3
이것은 간단한 시나리오에서 작동하지만 확인하려는 속성 값을 거의 또는 전혀 제어하지 않고 더 넓은 컨텍스트에서이 답변을 사용하려면주의하십시오. 정답은 bobince입니다.
Oliver

16
죄송합니다, 이것은 수업과 일치하지 않습니다, 그것은 하위 문자열과 일치합니다
Timo Huovinen

5
<div class = "annatag bobtag"> 또한 찾을 때 분명히 잘못되었습니다.
Alexei Vinogradov

6
문제는 "특정 클래스와 일치하지 않는" "특정 문자열 포함"
Alsatian

303

mjv의 대답은 좋은 시작이지만 atag가 나열된 첫 번째 클래스 이름이 아닌 경우 실패합니다.

일반적인 접근 방식은 다소 다루기 힘든 것입니다.

//*[contains(concat(' ', @class, ' '), ' atag ')]

이것은 클래스가 공백으로 만 분리되고 다른 형태의 공백이 아닌 한 작동합니다. 이것은 거의 항상 그렇습니다. 그렇지 않은 경우 여전히 다루기 힘들어 야합니다.

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

(클래스 이름과 같이 공백으로 구분 된 문자열로 선택하는 것은 일반적인 경우입니다. CSS3의 '[class ~ = "atag"]'와 같이 특정 XPath 함수가없는 것은 놀라운 일입니다.)


58
bah, xpath는 약간의 수정이 필요합니다
Randy L

13
당신은 내가 이것을 인정한다하지만 가능성이되지 않을 수도 있습니다, 선택 싶지 않아 "atagnumbertwo"와 같은 CSS 클래스가있는 경우 @Redbeard supra123의 대답은 문제가 (:
drevicko

7
@crazyrails :이 답변을 정답으로 수락 하시겠습니까? 그러면 향후 검색자가 질문에 설명 된 문제에 대한 올바른 솔루션을 식별하는 데 도움이됩니다. 감사합니다!
Oliver

2
@ cha0site : 예. XPath 2.0 이상에서 가능합니다. 이 답변은 XPath 2.0이 공식화되기 전에 작성되었습니다. 참조 stackoverflow.com/a/12165032/423105 또는 stackoverflow.com/a/12165195/423105
LarsH

1
나처럼되지 말고이 예제에서 찾고있는 클래스 주위의 공백을 제거하십시오. 그들은 실제로 중요합니다. 그렇지 않으면 작동하는 것처럼 보이지만 목적을 무효화합니다.
CTS_AE

40

이 시도: //*[contains(@class, 'atag')]


클래스 이름이 grabatagonabag무엇입니까? (힌트 : 여전히 일치합니다.)
Wayne

38

편집 : 완전한 토큰 수준에서 비교를 수행하는 트릭과 함께 start-with 대신 contains 를 사용하는 bobince의 솔루션을 참조하십시오 ( 'atag'패턴은 다른 'tag'의 일부로 찾을 수 있어야 함).

"atag btag"는 클래스 속성에 대한 홀수 값이지만 결코 적습니다.

//*[starts-with(@class,"atag")]

XPath 엔진이 starts-with 명령을 지원하는 경우이를 사용할 수 있습니다. 예를 들어 JVM 6은 내가 기억하는
한이를

10
@mjv : CSS 클래스 속성이 여러 값을 지정하는 것이 일반적입니다. 이것이 CSS가 수행되는 방식입니다.
skaffman

7
@mjv 클래스 속성의 시작 부분에 해당 이름이 나타날 것이라고 보장 할 수 없습니다.
Alan Krueger

@thuktun @skaffman. 고마워, 좋은 의견. 그에 따라 솔루션을 bobince로 '리디렉션'했습니다.
mjv

위와 동등한 <div class = "btag atag">에서 작동하지 않음
Alexei Vinogradov

30

작동하는 2.0 XPath :

//*[tokenize(@class,'\s+')='atag']

또는 변수와 함께 :

//*[tokenize(@class,'\s+')=$classname]

@class요소가 둘 이상인 경우 어떻게 작동 합니까? 단어 목록을 반환하고 문자열과 비교하면 잘못된 카디널리티 로 인해 실패합니다 .
Alexis Wilke

3
@AlexisWilke-스펙에서 ( w3.org/TR/xpath20/#id-general-comparisons ) : 일반적인 비교는 모든 길이의 피연산자 시퀀스에 적용될 수있는 실재적으로 수량화 된 비교입니다. 내가 시도한 모든 2.0 프로세서에서 작동했습니다.
다니엘 헤일리

1
또한 XPath 3.1에서는 다음과 같이 단순화 할 수 있습니다.//*[tokenize(@class)=$classname]
Michael Kay

1
그리고 완전성을 위해 스키마 인식 XPath 프로세서를 사용하기에 충분히 운이 좋으며 @class에 목록 값 유형이 있으면 간단히 다음과 같이 작성할 수 있습니다.//*[@class=$classname]
Michael Kay

21

관심있는 클래스 이름이 다른 가능한 클래스 이름의 하위 문자열이 아니라고 가정 할 수 있으면 bobince의 답변이 지나치게 복잡 할 수 있습니다 . 이것이 사실이라면, contains 함수를 통해 부분 문자열 매칭을 사용할 수 있습니다. 다음은 클래스에 하위 문자열 'atag'가 포함 된 모든 요소와 일치합니다.

//*[contains(@class,'atag')]

위의 가정이 유지되지 않으면 하위 문자열 일치가 의도하지 않은 요소와 일치합니다. 이 경우 단어 경계를 찾아야합니다. 공백 구분 기호를 사용하여 클래스 이름 경계를 찾으면 bobince의 두 번째 답변이 다음과 정확히 일치합니다.

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

일치 atag하지 않습니다 matag.


이것이 내가 찾고있는 해결책입니다. class = 'hello test world'에서 'test'를 명확하게 찾고 'hello test-test world'와 일치하지 않습니다. XPath 1.0 만 사용하고 RegEx가 없으므로 이것이 작동하는 솔루션 일뿐입니다.
Jan Stanicek

7

bobince의 답변에 추가하려면 ... 사용하는 도구 / 라이브러리가 Xpath 2.0을 사용하는 경우 다음을 수행 할 수도 있습니다.

//*[count(index-of(tokenize(@class, '\s+' ), $classname)) = 1]

index-of ()는 문자열에서 일치하는 각 인덱스의 시퀀스를 반환하므로 count ()는 분명히 필요합니다.


1
$classname따옴표 사이 에 변수를 넣지 말아야한다고 가정 합니까? 그것이 바로 문자열이기 때문입니다.
Alexis Wilke

1
마지막으로 문자열 리터럴 '$classname'을 제외하고 getElementsByClassName의 올바른 (JavasScript 호환) 구현입니다 .
Joel Mellon

1
이것은 지나치게 복잡합니다. 올바른 XPath 2.0 답변은 @DanielHaley의 답변을 참조하십시오.
Michael Kay


0

Ranorex Studio 9.0.1에 대한 솔루션을 찾고 있습니다. 아직 contains ()가 없습니다. 대신 다음과 같이 정규식을 사용할 수 있습니다.

div[@class~'atag']

-1

공통 URL을 포함하는 링크의 경우 변수에서 콘솔해야합니다. 그런 다음 순차적으로 시도하십시오.

webelements allLinks=driver.findelements(By.xpath("//a[contains(@href,'http://122.11.38.214/dl/appdl/application/apk')]"));
int linkCount=allLinks.length();
for(int i=0; <linkCount;i++)
{
    driver.findelement(allLinks[i]).click();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.