Belirli bir dizeyi içeren bir özellikle nasıl eşleşebilirim?


442

Öznitelikleri birden fazla kelime içerdiğinde özniteliğe göre düğümleri seçme konusunda sorun yaşıyorum. Örneğin:

<div class="atag btag" />

Bu benim xpath ifadem:

//*[@class='atag']

İfade ile çalışır

<div class="atag" />

ancak önceki örnek için değil. Nasıl seçebilirim <div>?


9
Bence, "atag btag" iki değil, tek bir özelliktir. Xpath'de alt dize eşleştirmesi yapmaya çalışıyorsunuz.
skaffman

3
Evet haklısın - istediğim bu.
crazyrails


1
Bu yüzden bir CSS seçici kullanmalısınız ... div.atagveya div.btag. Süper basit, dize eşleme değil ve WAY daha hızlı (ve tarayıcılarda daha iyi desteklenir). XPath (HTML'ye karşı), içerilen metne göre öğeleri bulmak ve DOM navigasyonu için kullanması gerekenlerle ilişkilendirilmelidir.
JeffC

Yanıtlar:


486

ClassName içeren div öğelerini bulan bir örnek atag:

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

ClassName içeren div öğelerini bulan bir örnek atagve btag:

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

Ancak, aynı zamanda kısmi eşleşmeler de bulacaktır class="catag bobtag".

Kısmi eşleşmeler istemiyorsanız, aşağıdaki bobince'nin cevabına bakın.


123
@Kırmızı sakal: Bu tam anlamıyla bir cevap ama genellikle sınıf eşleştirme çözümünün neyi hedeflemesi gerektiği değil. Özellikle <div class="Patagonia Halbtagsarbeit">, hedef dizeleri içeren ancak verilen sınıflarla bir div olmayan eşleşir .
bobince

3
Bu basit senaryolar için işe yarar - ancak bu cevabı kontrol ettiğiniz özellik değerleri üzerinde daha az kontrole sahip olan veya hiç kontrol sahibi olmayan daha geniş bağlamlarda kullanmak isteyip istemediğinize dikkat edin. Doğru cevap Bobince'dir.
Oliver

16
Üzgünüz, bu bir sınıfla eşleşmiyor, bir alt dize ile eşleşiyor
Timo Huovinen

5
ayrıca bulduğu açıkça yanlıştır: <div class = "annatag bobtag">.
Alexei Vinogradov

6
Soru "belli bir dize içeriyor" değil "belli bir sınıfla eşleşir"
Alsatian

303

mjv'nin yanıtı iyi bir başlangıçtır ancak atag listelenen ilk sınıf adı değilse başarısız olur.

Genel yaklaşım oldukça kullanışsızdır:

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

bu, sınıflar diğer boşluk türleriyle değil, yalnızca boşluklarla ayrıldığı sürece çalışır. Bu neredeyse her zaman böyledir. Değilse, hala daha hantal yapmak zorundasınız:

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

(Classname benzeri boşlukla ayrılmış dizelerle seçim yapmak yaygın bir durumdur, CSS3'ün '[class ~ = "atag"]' gibi belirli bir XPath işlevi olmaması şaşırtıcıdır.)


58
bah, xpath bazı düzeltmelere ihtiyacı var
Randy L

13
@Redbeard supra123, "atagnumbertwo" gibi bir css sınıfı varsa seçmek istemediğiniz soruyu sorunludur, ancak bu muhtemelen olası olmayabilir (:
drevicko

7
@crazyrails: Bu yanıtı doğru cevap olarak kabul eder misiniz? Bu, gelecekteki arama yapanların sorunuzda açıklanan soruna doğru çözümü belirlemesine yardımcı olacaktır. Teşekkür ederim!
Oliver

2
@ cha0site: Evet, XPath 2.0 ve sonrasında yapabilirler. Bu cevap XPath 2.0 resmi olmadan önce yazıldı. Bkz. Stackoverflow.com/a/12165032/423105 veya stackoverflow.com/a/12165195/423105
LarsH

1
Benim gibi olmayın ve bu örnekte aradığınız sınıfın çevresindeki boşlukları kaldırın; onlar gerçekten önemlidir. Aksi takdirde işe yarayabilir, ancak amacı yener.
CTS_AE

40

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


Sınıf adı ne olacak grabatagonabag? (İpucu: yine de eşleşecek.)
Wayne

38

DÜZENLEME : bakın bobince yerine içeren içeren çözüm karşılaştırmanın tam bir belirteç düzeyinde yapıldığından emin olmak için bir hile ile birlikte , başlangıçtan bobince'nin çözümüne bakın ('atag' kalıbı başka bir 'etiketinin bir parçası olarak bulunsa da).

"atag btag", sınıf özniteliği için tek bir değerdir, ancak daha azını asla deneyin:

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

XPath motorunuz start-with komutunu destekliyorsa bunu kullanabilirsiniz, örneğin JVM 6 hatırladığım kadarıyla desteklemiyor
Mohamed Faramawi

10
@mjv: Bir CSS sınıfı özelliğinin birden çok değer belirtmesi yaygındır. CSS böyle yapılır.
skaffman

7
@mjv Bu adın class özniteliğinin başında görüneceğini garanti edemezsiniz.
Alan Krueger

@tuktun @skaffman. Teşekkürler, harika yorumlar. Buna göre bobince çözeltisine 'yönlendirdim'.
mjv

Yukarıda eşdeğer olan <div class = "btag atag"> için çalışmaz
Alexei Vinogradov

30

Çalışan 2.0 XPath:

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

veya bir değişkenle:

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

@classBirden fazla unsuru varsa bu nasıl çalışır ? Çünkü bir kelime listesi döndürecek ve bunu bir dizeyle karşılaştırmak yanlış kardinalite ile başarısız oluyor .
Alexis Wilke

3
@AlexisWilke - Spesifikasyondan ( w3.org/TR/xpath20/#id-general-comparisons ): Genel karşılaştırmalar, herhangi bir uzunluktaki işlenen sekanslara uygulanabilecek varoluşsal olarak nicel karşılaştırmalardır. Denediğim her 2.0 işlemcide çalıştı.
Daniel Haley

1
Ayrıca, XPath 3.1'de bu basitleştirilebilir//*[tokenize(@class)=$classname]
Michael Kay

1
Ve tamlık için, şema bilincine sahip bir XPath işlemci kullanacak kadar şanslıysanız ve @class liste değerli bir türe sahipse, yazabilirsiniz//*[@class=$classname]
Michael Kay

21

İlgilendiğiniz sınıf adının başka bir olası sınıf adının bir alt dizesi olmadığını varsayarsanız, bobince'nin cevabının aşırı karmaşık olabileceğini unutmayın . Bu doğruysa, içeren işlev aracılığıyla alt dize eşleşmesini kullanabilirsiniz. Aşağıdakiler, sınıfı 'atag' alt dizesini içeren herhangi bir öğeyle eşleşecektir:

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

Yukarıdaki varsayım geçerli değilse, bir alt dize eşleşmesi niyetinde olmadığınız öğelerle eşleşir. Bu durumda, kelime sınırlarını bulmanız gerekir. Sınıf adı sınırlarını bulmak için boşluk sınırlayıcıları kullanarak, bobince'nin ikinci cevabı tam eşleşmeleri bulur:

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

Bu eşleşir atagve eşleşmez matag.


Aradığım çözüm buydu. Sınıf = 'merhaba test dünyası' içinde açıkça 'test' bulur ve 'merhaba test-test dünyası' ile eşleşmez. Ben sadece XPath 1.0 kullandığım ve hiçbir RegEx var bu sadece çalışan bir çözümdür.
Jan Stanicek

7

Bobince'nin cevabına eklemek için ... Kullandığınız araç / kütüphane Xpath 2.0 kullanıyorsa, bunu da yapabilirsiniz:

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

index-of (), dizede eşleştiği her dizinin bir dizisini döndürdüğü için count () görünüşte gereklidir.


1
$classnameDeğişken tırnak arasına DEĞİL koymak istemiştim ? Çünkü olduğu gibi, bu bir dize.
Alexis Wilke

1
Son olarak, '$classname'elbette dize hazır bilgisi dışında getElementsByClassName ... komutunun doğru (JavasScript uyumlu) uygulaması .
Joel Mellon

1
Bu aşırı derecede karmaşık. Doğru XPath 2.0 yanıtı için @ DanielHaley yanıtına bakın.
Michael Kay


0

Buraya Ranorex Studio 9.0.1 için çözüm aramaya geldim. Henüz orada include () yok. Bunun yerine aşağıdaki gibi normal ifadeleri kullanabiliriz:

div[@class~'atag']

-1

Ortak url içeren bağlantılar için bir değişken içinde konsollamak zorunda. Sonra sırayla deneyin.

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();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.