2011-10-26 31 views
18

İki xml öğesinin eşdeğeriyle ilgileniyorum; ve ben elemanların işlerinin tostringini test ettim; Ancak, bu hacky görünüyor. İki etri unsurunun denkliğini test etmek için daha iyi bir yol var mı? Örnek:xml.etree.ElementTree'nin Eşdeğerliğini Test Etme

import xml.etree.ElementTree as etree 
h1 = etree.Element('hat',{'color':'red'}) 
h2 = etree.Element('hat',{'color':'red'}) 

h1 == h2 

Yanlış

etree.tostring(h1) == etree.tostring(h2) 

Gerçek

+0

iki Element karşılaştırmak için bir fonksiyon bulunabilir [Itamar cevabı] (http://stackoverflow.com/a/24349916/2371522) altına . – One

cevap

0

altın değildir plaka yapın. Sahip olduğun şey iyi bir karşılaştırma. Sonunda XML bu METİN.

+0

Evet, ve biçimlendirmeyle ilgili endişeleriniz varsa, ET'ye dönüştürün, ardından dizeye dökün ve karşılaştırın. – Wyrmwood

2

Karmaşık yapıları karşılaştırmak için genel bir yol, bunları ortak bir metinsel sunumda bırakmak ve sonuçta ortaya çıkan dizeleri eşitlikle karşılaştırmaktır.

Alınan iki json dizesini karşılaştırmak için, bunları json nesnelerine dönüştürür ve ardından bunları (aynı dönüştürücü ile) dizelere dönüştürür ve karşılaştırırsınız. Json beslemelerini kontrol etmek için yaptım, iyi çalışıyor.

XML için hemen hemen aynıdır, ancak ".text" parçalarını (etiketlerin dışında bulunan veya bulunmayan metin) işlemek zorunda kalabilirsiniz (şerit çıkarmak?).

Kısacası, iki eşdeğer XML'lerin (içeriğinize göre) aynı dize gösterimine sahip olduğundan emin olduğunuz sürece çözümünüz bir kesmek değildir.

3

İster inanın ister inanmayın, ya da kaç tane çocuğun sahip olabileceğini bilmiyorsanız ve iki çocuğu araştırmaya dahil etmek istiyorsanız, iki düğümün karşılaştırılmasının en iyi yoludur. Tabii

, sadece sen sergilediklerini gibi çocuksuz bir düğüm varsa, sadece etiket, attrib karşılaştırabilirsiniz ve kuyruk özellikleri:

if h1.tag == h2.tag and h1.attrib == h2.attrib and h1.tail == h2.tail: 
    print("h1 and h2 are the same") 
else 
    print("h1 and h2 are the different") 

ben hiçbirinde önemli bir fayda görmüyorum Ancak bu, tostring kullanarak.

+0

İhtiyaçlarınıza göre metin de atabilirsiniz: 'h1.text == h2.text' – bmaupin

+0

Bu elemanlar öğeleri karşılaştırmaz ... – drevicko

7

Dizeleri karşılaştırma her zaman çalışmaz. Niteliklerin sırası, iki düğüm eşdeğerini dikkate almak için önemli olmamalıdır. Ancak, dize karşılaştırması yaparsanız, sipariş açıkça önemlidir.

>>> from lxml import etree 
>>> h1 = etree.XML('<hat color="blue" price="39.90"/>') 
>>> h2 = etree.XML('<hat price="39.90" color="blue"/>') 
>>> etree.tostring(h1) == etree.tostring(h2) 
False 

Bu:

Bunun bir sorun ya da bir özelliktir, ancak bir dosya veya bir dizesinden ayrıştırılır eğer lxml.etree benim sürümü niteliklerini sırasını korur olmadığından emin değilim sürüm bağımlı olabilir (Ubuntu üzerinde lxml.etree 2.3.2 ile Python 2.7.3 kullanıyorum); Anladığım kadarıyla, bir yıl önce özniteliklerin sırasını kontrol etmenin bir yolunu bulamadım (okunabilirlik nedenleriyle).

Farklı serileştiriciler tarafından üretilen XML dosyalarını karşılaştırmak gerektiğinden, her düğümün etiketini, metnini, niteliklerini ve çocuklarını yinelemeli olarak karşılaştırmaktan başka bir yol görmüyorum. Ve elbette kuyruğun, eğer ilginç bir şey varsa. LXML ve xml.etree.ElementTree

gerçeği ait

Karşılaştırılması o uygulama bağımlı olabileceğidir. Görünüşe göre, lxml, standart xml.etree gibi sipariş edilen bir dict veya bir şey kullanır.Elementtree niteliklerin düzeni korumak değildir: (. Evet, yeni satırlar eksik Ama küçük bir sorundur.)

Python 2.7.1 (r271:86832, Nov 27 2010, 17:19:03) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> from lxml import etree >>> h1 = etree.XML('<hat color="blue" price="39.90"/>') >>> h2 = etree.XML('<hat price="39.90" color="blue"/>') >>> etree.tostring(h1) == etree.tostring(h2) False >>> etree.tostring(h1) '<hat color="blue" price="39.90"/>' >>> etree.tostring(h2) '<hat price="39.90" color="blue"/>' >>> etree.dump(h1) <hat color="blue" price="39.90"/>>>> etree.dump(h2) <hat price="39.90" color="blue"/>>>> 

>>> import xml.etree.ElementTree as ET 
>>> h1 = ET.XML('<hat color="blue" price="39.90"/>') 
>>> h1 
<Element 'hat' at 0x2858978> 
>>> h2 = ET.XML('<hat price="39.90" color="blue"/>') 
>>> ET.dump(h1) 
<hat color="blue" price="39.90" /> 
>>> ET.dump(h2) 
<hat color="blue" price="39.90" /> 
>>> ET.tostring(h1) == ET.tostring(h2) 
True 
>>> ET.dump(h1) == ET.dump(h2) 
<hat color="blue" price="39.90" /> 
<hat color="blue" price="39.90" /> 
True 

başka soru karşılaştıran önemsiz whan kabul edilen olabilir. Örneğin, bazı fragmanlar fazladan boşluk içerebilir ve umursamamak istemeyiz. Bu şekilde, tam olarak ihtiyacımız olan bazı serileştirme fonksiyonları yazmak her zaman daha iyidir.

+1

' .dump (...) '' None' döndürür ET.dump (h1) == ET.dump (h2) 'aslında 'Yok' ile 'Hiçbiri'ni karşılaştırıyor. –

4

Serileştirme ve serileştirme XML için çalışmaz çünkü öznitelikler siparişe bağlı değildir (ve diğer nedenler).

<THING a="foo" b="bar"></THING> 
<THING b="bar" a="foo" /> 

Tam bir eleman karşılaştırma zor olduğunu nasıl yapılacağı: Bu iki element mantıksal olarak aynı, ancak farklı dizelerdir. Anlayabildiğim kadarıyla, bunu sizin için yapmak için Eleman Ağacına yerleşik hiçbir şey yoktur. Bunu kendim yapmalıydım ve aşağıdaki kodu kullandım. İhtiyaçlarım için çalışır, ancak büyük XML yapıları için uygun değildir ve hızlı veya verimli değildir! Bu bir eşitlik işlevinden ziyade bir sıralama işlevidir, bu yüzden 0 sonucu eşittir ve başka bir şey değildir. Doğru veya Yanlış geri dönen bir işlevle sarma, okuyucu için bir egzersiz olarak bırakılır!

def cmp_el(a,b): 
    if a.tag < b.tag: 
     return -1 
    elif a.tag > b.tag: 
     return 1 
    elif a.tail < b.tail: 
     return -1 
    elif a.tail > b.tail: 
     return 1 

    #compare attributes 
    aitems = a.attrib.items() 
    aitems.sort() 
    bitems = b.attrib.items() 
    bitems.sort() 
    if aitems < bitems: 
     return -1 
    elif aitems > bitems: 
     return 1 

    #compare child nodes 
    achildren = list(a) 
    achildren.sort(cmp=cmp_el) 
    bchildren = list(b) 
    bchildren.sort(cmp=cmp_el) 

    for achild, bchild in zip(achildren, bchildren): 
     cmpval = cmp_el(achild, bchild) 
     if cmpval < 0: 
      return -1 
     elif cmpval > 0: 
      return 1  

    #must be equal 
    return 0 
+0

İki XML dosyasını karşılaştırırken ana sorunun nedeni, yukarıda söyledikleri gibi farklı biçimlendirmelerdir. Ve çoğu zaman, pronlem kuyruk bölümünde boşluklarda veya yeni hatlarda yatar. Test için iki mantıksal XML dosyası vardı ve kod aynı olduklarını anlamadı. Ancak, kodtan .tail karşılaştırmasını kaldırdım ve bir cazibe gibi çalıştı! – PMN

18

Bu karşılaştırma işlevi benim için çalışıyor:

def elements_equal(e1, e2): 
    if e1.tag != e2.tag: return False 
    if e1.text != e2.text: return False 
    if e1.tail != e2.tail: return False 
    if e1.attrib != e2.attrib: return False 
    if len(e1) != len(e2): return False 
    return all(elements_equal(c1, c2) for c1, c2 in zip(e1, e2)) 
+3

Bu bir çözümdür. Beyaz boşluğun etkilemediğinden emin olun, örn. etree.XMLParser (remove_blank_text = True) 'kullanarak. Listeyi all() 'de oluşturmaktan kaçınarak geliştirin. Zip() 'nin, len()' nin daha önce test edildiğinden çalıştığını unutmayın. – One

+1

Temiz! Bu, aynı tagnamesine sahip elemanlar için bile, öğe düzeninden bağımsız olarak çalışır gibi görünüyor. – Fredrik