Pertanyaan Membandingkan XML dalam tes unit dengan Python


Saya memiliki objek yang dapat membangun dirinya sendiri dari string XML, dan menulis sendiri ke string XML. Saya ingin menulis tes unit untuk menguji putaran tersandung melalui XML, tapi saya mengalami kesulitan membandingkan dua versi XML. Whitespace dan urutan atribut tampaknya menjadi masalah. Ada saran untuk cara melakukan ini? Ini dengan Python, dan saya menggunakan ElementTree (bukan itu yang benar-benar penting di sini karena saya hanya berurusan dengan XML dalam string pada level ini).


32
2017-11-26 19:09


asal


Jawaban:


Pertama menormalkan 2 XML, lalu Anda dapat membandingkannya. Saya telah menggunakan yang berikut menggunakan lxml

obj1 = objectify.fromstring(expect)
expect = etree.tostring(obj1)
obj2 = objectify.fromstring(xml)
result = etree.tostring(obj2)
self.assertEquals(expect, result)

12
2017-11-26 19:35



Ini adalah pertanyaan lama, tetapi yang diterima Jawaban Kozyarchuk tidak berfungsi untuk saya karena pesanan atribut, dan solusi minidom tidak berfungsi apa adanya (tidak tahu mengapa, saya belum men-debug-nya).

Inilah yang akhirnya saya temukan:

from doctest import Example
from lxml.doctestcompare import LXMLOutputChecker

class XmlTest(TestCase):
    def assertXmlEqual(self, got, want):
        checker = LXMLOutputChecker()
        if not checker.check_output(want, got, 0):
            message = checker.output_difference(Example("", want), got, 0)
            raise AssertionError(message)

Ini juga menghasilkan diff yang dapat membantu dalam kasus file xml besar.


15
2017-08-14 23:05



Jika masalahnya benar-benar hanya urutan whitespace dan atribut, dan Anda tidak memiliki konstruksi lain selain teks dan elemen yang perlu dikhawatirkan, Anda dapat mengurai string menggunakan parser XML standar dan membandingkan node secara manual. Berikut ini contoh menggunakan minidom, tetapi Anda bisa menulis hal yang sama dalam cukup sederhana:

def isEqualXML(a, b):
    da, db= minidom.parseString(a), minidom.parseString(b)
    return isEqualElement(da.documentElement, db.documentElement)

def isEqualElement(a, b):
    if a.tagName!=b.tagName:
        return False
    if sorted(a.attributes.items())!=sorted(b.attributes.items()):
        return False
    if len(a.childNodes)!=len(b.childNodes):
        return False
    for ac, bc in zip(a.childNodes, b.childNodes):
        if ac.nodeType!=bc.nodeType:
            return False
        if ac.nodeType==ac.TEXT_NODE and ac.data!=bc.data:
            return False
        if ac.nodeType==ac.ELEMENT_NODE and not isEqualElement(ac, bc):
            return False
    return True

Jika Anda memerlukan perbandingan ekuivalen yang lebih menyeluruh, yang mencakup kemungkinan jenis node lain termasuk CDATA, PI, referensi entitas, komentar, doctypes, ruang nama dan sebagainya, Anda bisa menggunakan metode DOM Level 3 Core yaitu EqualNode. Baik minidom maupun etree memiliki itu, tetapi pxdom adalah salah satu implementasi yang mendukungnya:

def isEqualXML(a, b):
    da, db= pxdom.parseString(a), pxdom.parseString(a)
    return da.isEqualNode(db)

(Anda mungkin ingin mengubah beberapa opsi konfigurasi DOM pada parse jika Anda perlu menentukan apakah referensi entitas dan bagian CDATA cocok dengan ekuivalen yang diganti.)

Cara yang sedikit lebih bundar untuk melakukannya adalah dengan mem-parsing, kemudian re-serialisasi ke bentuk kanonik dan melakukan perbandingan string. Sekali lagi, pxdom mendukung opsi DOM Level 3 LS ‘canonical-form’ yang dapat Anda gunakan untuk melakukan ini; cara alternatif menggunakan implementasi mindom stdlib adalah menggunakan c14n. Namun Anda harus menginstal ekstensi PyXML untuk ini sehingga Anda masih tidak bisa melakukannya di dalam stdlib:

from xml.dom.ext import c14n

def isEqualXML(a, b):
    da, bd= minidom.parseString(a), minidom.parseString(b)
    a, b= c14n.Canonicalize(da), c14n.Canonicalize(db)
    return a==b

7
2017-11-26 19:56



Menggunakan xmldiff, alat python yang menghitung perbedaan antara dua file XML yang serupa, sama seperti diff.


5
2017-11-26 19:19



Mengapa Anda memeriksa data XML sama sekali?

Cara untuk menguji serialisasi objek adalah dengan membuat sebuah instance objek, membuat serial, deserialize menjadi objek baru, dan membandingkan dua objek. Ketika Anda membuat perubahan yang merusak serialisasi atau deserialization, tes ini akan gagal.

Satu-satunya hal yang memeriksa data XML akan menemukan untuk Anda adalah jika serializer Anda memancarkan superset dari apa deserializer membutuhkan, dan deserializer diam-diam mengabaikan hal-hal yang tidak diharapkan.

Tentu saja, jika sesuatu yang lain akan memakan data serial, itu masalah lain. Tetapi dalam hal ini, Anda harus berpikir tentang membangun skema untuk XML dan memvalidasinya.


2
2017-11-26 20:46



Saya juga memiliki masalah ini dan melakukan beberapa penggalian di sekitarnya hari ini. Itu doctestcompare pendekatan mungkin sudah cukup, tapi saya menemukan via Ian Bicking bahwa itu didasarkan pada formencode.doctest_xml_compare. Yang tampaknya sekarang menjadi sini. Seperti yang Anda lihat itu adalah fungsi yang cukup sederhana, tidak seperti doctestcompare (meskipun saya kira doctestcompare mengumpulkan semua kegagalan dan mungkin pemeriksaan yang lebih canggih). Pokoknya menyalin / mengimpor xml_compare dari formencode bisa menjadi solusi yang baik.


1
2017-11-18 07:05



Komponen Java dbUnit melakukan banyak perbandingan XML, sehingga Anda mungkin merasa berguna untuk melihat pendekatan mereka (terutama untuk menemukan gotcha yang mungkin sudah mereka tuju).


0
2017-11-27 00:20