Birden çok etiket seçmek için XPath


132

Bu basitleştirilmiş veri biçimi göz önüne alındığında:

<a>
    <b>
        <c>C1</c>
        <d>D1</d>
        <e>E1</e>
        <f>don't select this one</f>
    </b>
    <b>
        <c>C2</c>
        <d>D2</d>
        <e>E1</e>
        <g>don't select me</g>
    </b>
    <c>not this one</c>
    <d>nor this one</d>
    <e>definitely not this one</e>
</a>

Elementlerin alt öğesi olan tüm Ce, Dleri ve Eleri nasıl seçersiniz B?

Temel olarak, şöyle bir şey:

a/b/(c|d|e)

Bunun yerine sadece benim kendi durumda, a/b/bu seçme giden sorgu C, D, Edüğümler aslında oldukça karmaşıktır Bunu yaparken önlemek istiyorum böylece:

a/b/c|a/b/d|a/b/e

Mümkün mü?

Yanıtlar:


208

Doğru cevaplardan biri :

/a/b/*[self::c or self::d or self::e]

Bunu not edin

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

hem çok uzun hem de yanlış . Bu XPath ifadesi aşağıdaki gibi düğümleri seçecektir:

OhMy:c

NotWanted:d 

QuiteDifferent:e

2
'veya' her biri için çalışmaz, bunun yerine dikey bir çizgi kullanmanız gerekir '|'
Guasqueño

8
@ Guasqueño, ormantıksal bir operatördür - iki Boolean değeriyle çalışır. XPath birleştirme operatörü |iki düğüm kümesi üzerinde çalışır. Bunlar oldukça farklıdır ve her biri için özel kullanım durumları vardır. Kullanılması | olabilir orijinal sorunu çözmek, ancak sonuçlanır daha uzun ve daha karmaşık ve XPath ifadesini anlamak için zorlu. Kullanan bu cevap daha basit ifadesi, oroperatöre istenilen düğüm kümesi üretir ve edebilirsiniz bir "seç" özelliğinde belirtilmelidir <xsl:for-each>XSLT operasyonu. Sadece dene.
Dimitre Novatchev

4
@JonathanBenn, "İsim alanlarını umursamayan" aslında XML umursamayan ve XML kullanmayan herkes. Kullanımı local-name()elemanı olduğu ad bakılmaksızın, bunu yerel adıyla tüm unsurları seçmek istiyorsanız yalnızca doğru olan bu çok nadir bir durumdur - Genel kişilerde arasındaki farklar hakkında bakım yapın:. kitchen:tableVe sql:tableya arasındaki architecture:column, sql:column, array:column,military:column
Dimitre Novatchev

3
@DimitreNovatchev iyi bir noktaya değindin. HTML incelemesi için XPath kullanıyorum, bu ad alanının çok önemli olmadığı bir uç durumdur ...
Jonathan Benn

2
Bu süper. Bunu nereden buldun?
Keith Tyler

46

Bunun yerine bir öznitelik testi ile tekrarı önleyebilirsiniz:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

Dimitre'nin muhalif görüşünün aksine , OP'nin ad alanlarıyla etkileşimi belirlemediği bir boşlukta yukarıdakiler yanlış değildir. self::Eksen ad kısıtlayıcı, local-name()değil. OP'nin niyeti c|d|ead alanına bakılmaksızın yakalamaksa (sorunun OR niteliği göz önüne alındığında olası bir senaryo olduğunu bile öneriyorum), o zaman bu yanlış olan "hala bazı olumlu oylara sahip başka bir cevaptır".

Tanım olmadan kesin olamazsınız, ancak OP'nin sorusunu yanlış olduğum şekilde açıklığa kavuşturması durumunda cevabımı gerçekten yanlış olarak silmekten oldukça mutluyum.


3
Burada 3. taraf olarak konuşursak - şahsen, Dimitre'nin önerisinin, kullanıcının ad alanıyla ilgisi olmayan etiket adıyla ilgilenmek için açık (ve iyi) bir nedeni olduğu durumlar dışında daha iyi bir uygulama olduğunu düşünüyorum; Eğer birisi bunu farklı isim alanlı içeriğe karıştırdığım bir belgeye karşı yaparsa (muhtemelen farklı bir araç zinciri tarafından okunması amaçlanmıştır), davranışlarının çok uygunsuz olduğunu düşünürdüm. Bununla birlikte, argüman - önerdiğiniz gibi - biraz yakışıksızdır.
Charles Duffy

4
tam olarak aradığım şey. XML ad alanları, gerçek hayatta kullanılma biçimleri, kutsal olmayan bir karmaşa. / A / b / ( : c | : d | * e) gibi bir şeyi belirleyememe konusunda çözümünüz tam olarak gerekli olan şeydir. Purists istedikleri her şeyi tartışabilirler, ancak kullanıcılar uygulamanın bozulmasını umursamıyor çünkü giriş dosyalarını oluşturan şey ad alanlarını bozdu. Sadece çalışmasını istiyorlar.
Ghostrider

7
Bu iki cevap arasındaki farkın ne olacağına dair en ufak bir fikrim var ve kimse açıklama zahmetine girmedi. "Ad alanı kısıtlayıcı" ne anlama geliyor? Kullanırsam local-name(), bu herhangi bir ad alanıyla etiketlerle eşleşeceği anlamına mı gelir? Ben kullanırsanız self::ne ad o maç olurdu? Sadece nasıl eşleşirim OhMy:c?
meustrus

15

Neden olmasın a/b/(c|d|e)? Az önce Saxon XML kitaplığını denedim (Clojure iyiliğiyle güzelce sarılmış) ve işe yarıyor gibi görünüyor. abc.xmlOP tarafından açıklanan dokümandır.

(require '[saxon :as xml])
(def abc-doc (xml/compile-xml (slurp "abc.xml")))
(xml/query "a/b/(c|d|e)" abc-doc)
=> (#<XdmNode <c>C1</c>>
    #<XdmNode <d>D1</d>>
    #<XdmNode <e>E1</e>>
    #<XdmNode <c>C2</c>>
    #<XdmNode <d>D2</d>>
    #<XdmNode <e>E1</e>>)

8
Evet, ancak bu XPath 2.0

Bu benim için iyi çalıştı. Görünüşe göre XPath 2.0, Python 2'de lxml'de HTML ayrıştırması için varsayılan değerdir.
Martin Burch

-1

Bunun yardımcı olup olmadığından emin değilim, ancak XSL ile şöyle bir şey yapardım:

<xsl:for-each select="a/b">
    <xsl:value-of select="c"/>
    <xsl:value-of select="d"/>
    <xsl:value-of select="e"/>
</xsl:for-each>

ve bu XPath, B düğümlerinin tüm alt öğelerini seçmez:

a/b/*

Teşekkürler Calvin, ama XSL kullanmıyorum ve aslında B'nin altında seçmek istemediğim daha fazla öğe var. Daha net olması için örneğimi güncelleyeceğim.
nickf

Oh, bu durumda annakata'nın çözümü var gibi görünüyor.
Calvin
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.