XPath, birden fazla Metin alt düğümüne sahip düğümle kullanıldığında (text (), 'bazı dize') içermiyor


259

Ben domp ile içeren Xpath ile küçük bir sorun var ...

Diyelim ki XML'im

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

Kök Element verilen metinde ABC bulunan tüm düğümleri bulmak istediğimi söyleyelim ...

Yazmam gereken xpath

//*[contains(text(),'ABC')]

Ancak bu Dom4j döndürür .... değil bu bir dom4j sorun veya benim xpath nasıl çalışır anlayışım. çünkü bu sorgu Yorum öğesini değil, yalnızca Sokak Öğesini döndürür.

DOM, Yorum öğesini dört etiketi iki olan bileşik bir öğe yapar

[Text = 'XYZ'][BR][BR][Text = 'ABC'] 

Sorgu hala öğeyi bulmak ve üzerinde içerir çalıştırmak gerekir çünkü öğeyi döndürmek gerektiğini varsayalım ama değil ...

Aşağıdaki sorgu öğeyi döndürür, ancak yalnızca öğeden çok daha fazla döndürür, üst öğeleri de döndürür ... bu da sorun için istenmeyen bir durumdur ...

//*[contains(text(),'ABC')]

Herhangi biri sadece Element dönecekti xpath sorgusu biliyor mu <Street/>ve <Comment/>?


Anlayabildiğim kadarıyla, //*[contains(text(),'ABC')]sadece <Street>elemanı döndürür . <Street>Veya öğesinin atalarını döndürmez <Comment>.
Ken Bloom

Yanıtlar:


707

<Comment>Etiketi, iki metin düğümlerini ve iki içerdiği <br>çocuklar gibi düğümleri.

Xpath ifadeniz şuydu:

//*[contains(text(),'ABC')]

Bunu yıkmak için,

  1. * herhangi bir öğeyle (yani etiketle) eşleşen bir seçicidir - bir düğüm kümesi döndürür.
  2. Bu []düğüm kümesindeki her bir düğümde çalışan koşulludur. Çalıştığı bağımsız düğümlerden herhangi biri, parantez içindeki koşullara uyuyorsa eşleşir.
  3. text()bağlam düğümünün alt öğesi olan tüm metin düğümleriyle eşleşen bir seçicidir - bir düğüm kümesi döndürür.
  4. containsbir dizede çalışan bir işlevdir. Bir düğüm kümesinden geçirilirse, düğüm kümesindeki düğümün dize değeri belge sırasına göre ilk olarak döndürülerek düğüm kümesi bir dizeye dönüştürülür . Bu nedenle, öğenizdeki yalnızca ilk metin düğümü ile eşleşebilir <Comment>- yani BLAH BLAH BLAH. Bu eşleşmediği <Comment>için sonuçlarınızda bir a elde edilemez .

Bunu şu şekilde değiştirmeniz gerekir:

//*[text()[contains(.,'ABC')]]
  1. * herhangi bir öğeyle (yani etiketle) eşleşen bir seçicidir - bir düğüm kümesi döndürür.
  2. Dış [], bu düğüm kümesindeki her bir düğüm üzerinde çalışan bir koşuldur - burada belgedeki her öğe üzerinde çalışır.
  3. text()bağlam düğümünün alt öğesi olan tüm metin düğümleriyle eşleşen bir seçicidir - bir düğüm kümesi döndürür.
  4. İç kısım [], bu düğüm kümesindeki her düğümde çalışan bir koşuldur - burada her bir metin düğümü. Her bir tek metin düğümü, köşeli parantez içindeki herhangi bir yol için başlangıç ​​noktasıdır ve ayrıca .köşeli parantezler içinde olduğu gibi açıkça ifade edilebilir . Çalıştığı bağımsız düğümlerden herhangi biri, parantez içindeki koşullara uyuyorsa eşleşir.
  5. containsbir dizede çalışan bir işlevdir. Burada tek bir metin düğümü ( .) geçirilir . <Comment>Etiketteki ikinci metin düğümünü tek tek geçtiği için , 'ABC'dizeyi görür ve eşleşebilir.

1
Müthiş bir xpath noob biraz im, bu yüzden bunu elde edeyim, text () ifadesi içeren bir işlevdir (., 'ABC'), açıklamak için bir şans var bu yüzden bu tür yapmayın aptal şeyler tekrar;)
Mike Milkin

28
Uzun bir açıklama sağlamak için cevabımı düzenledim. XPath hakkında o kadar çok şey bilmiyorum - bu kombinasyona rastlayana kadar biraz denedim. Bir kez çalışan bir kombinasyon yaşadım, neler olduğunu tahmin ettim ve neler olduğunu düşündüğümü doğrulamak ve açıklamayı yazmak için XPath standardına baktım .
Ken Bloom

2
Bunu nasıl duyarsız bir arama yaparsınız?
Zack

@Zack: Lütfen bunu yeni bir soru yap.
user1129682

1
Bu eski bir iş parçacığı olduğunu biliyorum, ancak herkes Ken Bloom ve verilen cevap arasında bazı basit test vakaları ile, temel bir fark varsa yorum yapabilir //*[contains(., 'ABC')]. Mike Milkin tarafından verilen modeli her zaman kullandım, daha uygun olduğunu düşünmüştüm, ama sadece containsmevcut bağlamda yapmak aslında daha sık istediğim şey gibi görünüyor.
knickum

7

[contains(text(),'')]yalnızca doğru veya yanlış döndürür. Hiçbir öğe sonucu döndürmez.


'' ya da '' olsaydı bu işe yaramaz.
shareef

contains(text(),'JB-')iş değil! argüman olarak iki dizgeconatains alır - ! text () dize değildir , bir işlevdir! contains(**string**, **string**)
AtachiShadow

6

XML belgesi:

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

XPath ifadesi:

//*[contains(text(), 'ABC')]

//*herhangi maçları soyundan eleman ait kök düğümü . Yani, kök düğüm dışında herhangi bir eleman.

[...]bir yüklemdir , düğüm kümesini filtreler. Bunun için bu düğümlerin döndürür ...olduğu true:

Bir yüklem, bir düğüm kümesini [...] süzerek yeni bir düğüm kümesi oluşturur. Filtrelenecek düğüm kümesindeki her düğüm için PredicateExpr değerlendirilir [...]; PredicateExpr bu düğüm için true olarak değerlendirilirse, düğüm yeni düğüm kümesine dahil edilir; aksi takdirde dahil edilmez.

contains('haystack', 'needle')döndürür trueeğer haystack içeriyor needle :

İşlev: boolean içerir (dize, dize)

Birinci argüman dizesi ikinci argüman dizesini içeriyorsa, include işlevi true değerini, aksi halde false değerini döndürür.

Ancak contains()bir dizeyi ilk parametresi olarak alır. Ve düğümler geçti. İlk parametre olarak iletilen her düğüm veya düğüm kümesinin işlev tarafından bir dizeye dönüştürülmesiyle başa çıkmak için string():

Bir bağımsız değişken, string işlevini çağırıyormuş gibi string türüne dönüştürülür.

string()fonksiyon döner string-valueve ilk birleşme noktası :

Düğüm kümesi, düğüm kümesinde, belge düzeninde ilk sırada yer alan düğümün dize değeri döndürülerek bir dizeye dönüştürülür. Düğüm kümesi boşsa, boş bir dize döndürülür.

string-valuebir eleman düğümü :

Bir eleman düğümünün dize değeri, öğe düğümünün tüm metin düğümü torunlarının dize değerlerinin belge düzeninde bir araya getirilmesidir.

string-valuebir metin düğümü :

Metin düğümünün dize değeri karakter verisidir.

Yani, temelde string-valuebir düğümde bulunan tüm metinler (tüm alt metin düğümlerinin birleştirilmesi).

text() herhangi bir metin düğümü ile eşleşen bir düğüm testidir:

Düğüm testi metni () herhangi bir metin düğümü için doğrudur. Örneğin, child :: text (), bağlam düğümünün metin düğümü alt öğelerini seçer.

Bunu söyledikten sonra //*[contains(text(), 'ABC')], ilk metin düğümü içeren herhangi bir öğeyle (kök düğüm hariç) eşleşir ABC. Çünkü text(), bağlamsal düğümün (ifadenin değerlendirildiği göreceli olarak) tüm alt metin düğümlerini içeren bir düğüm kümesi döndürür. Ama contains()sadece ilkini alır. Yani yukarıdaki belge için yol Streetöğeyle eşleşir .

Aşağıdaki ifade //*[text()[contains(., 'ABC')]], en az bir alt metin düğümü olan herhangi bir öğeyle (kök düğüm hariç) eşleşir ABC. .bağlam düğümünü temsil eder. Bu durumda, kök düğüm dışında herhangi bir öğenin alt metin düğümüdür. Yani yukarıdaki belge için yol Street, ve Commentöğelerle eşleşir .

Şimdi //*[contains(., 'ABC')], ABC(alt metin düğümlerinin birleşiminde ) içeren herhangi bir öğeyle (kök düğüm hariç) eşleşir . Eşleştiği Yukarıdaki belgede için Home, Addr, Street, ve Commentelemanları. Bunun gibi, //*[contains(., 'BLAH ABC')]maçları Home, Addrve Commentelemanları.


0

Biraz zamanımı aldı ama sonunda anladım. Aşağıda bazı metinler içeren özel xpath benim için mükemmel çalıştı.

//a[contains(text(),'JB-')]

2
contains(text(),'JB-')iş değil! argüman olarak iki dizgeconatains alır - ! text () dize değildir , bir işlevdir! contains(**string**, **string**)
AtachiShadow

0

Kabul edilen cevap tüm üst düğümleri de döndürecektir. Dizeden sonra olsa bile yalnızca ABC ile gerçek düğümleri almak için
:

//*[text()[contains(.,'ABC')]]/text()[contains(.,"ABC")]

0
//*[text()='ABC'] 

İadeler

<street>ABC</street>
<comment>BLAH BLAH BLAH <br><br>ABC</comment>

3
Dokuz yaşındaki bir soruna mevcut beş yanıtı içeren bir cevap eklerken, yanıtınızın hangi benzersiz yeni yönünü ele aldığını belirtmek çok önemlidir.
Jason Aller

Gönderdiğim cevap çok basitti. Bu yüzden benim gibi yeni başlayanlara yardımcı olabilecek paylaşım gibi düşünülmüş.
user3520544
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.