سؤال

أنا كائن التي يمكن أن تبني نفسها من سلسلة XML و الكتابة نفسها إلى سلسلة XML.أود أن أكتب وحدة اختبار لاختبار تنطلق الجولة من خلال XML, ولكن أواجه صعوبة في المقارنة بين اثنين XML الإصدارات.بيضاء و سمة النظام يبدو أن القضايا.أي اقتراحات عن كيفية القيام بذلك ؟ هذا هو في بيثون ، و أنا باستخدام ElementTree (لا يهم حقا هنا منذ أنا فقط التعامل مع XML في السلاسل في هذا المستوى).

هل كانت مفيدة؟

المحلول

أولا تطبيع 2 XML، ثم يمكنك مقارنتها. لقد استعملت lxml باستخدام التالية

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

نصائح أخرى

وهذا هو السؤال القديم، ولكن قبلت Kozyarchuk في الإجابة لا تعمل بالنسبة لي بسبب سمات النظام، و الحل minidom لا يعمل كما هو وإما (لا فكرة لماذا، وأنا لم تصحيحه ذلك).

وهذا ما جئت أخيرا مع:

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)

وهذا ينتج أيضا فرق التي يمكن أن تكون مفيدة في حالة ملفات XML كبيرة.

إذا كانت المشكلة هي حقا مجرد بيضاء والسمة النظام، وليس لديك بنيات أخرى من النص وعناصر ما يدعو للقلق، يمكنك تحليل السلاسل باستخدام محلل XML القياسية ومقارنة العقد يدويا. وهنا مثال باستخدام minidom، ولكن هل يمكن أن يكتب نفسه في يتري ببساطة جدا:

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

إذا كنت في حاجة الى مقارنة التكافؤ أكثر شمولا، وتغطي الاحتمالات أنواع أخرى من العقد بما في ذلك CDATA، حزب القانون والعدالة، والمراجع كيان، والتعليقات، doctypes، بمساحات وهلم جرا، هل يمكن استخدام DOM المستوى 3 طريقة كور isEqualNode. لا minidom ولا يتري يكون ذلك، ولكن pxdom هو تطبيق واحد الذي يدعم فيه:

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

و(قد تحتاج إلى تغيير بعض الخيارات DOMConfiguration على تحليل إذا كنت بحاجة إلى تحديد ما إذا كان المراجع كيان والمقاطع CDATA تطابق ما يعادلها استبداله.)

وهناك أكثر قليلا دوار طريقة للقيام بذلك سيكون تحليل، ثم إعادة serialise إلى شكل قانوني والقيام مقارنة السلسلة. مرة أخرى pxdom يدعم DOM المستوى 3 LS خيار "الكنسي شكل" التي يمكن استخدامها للقيام بذلك. طريقة بديلة باستخدام تنفيذ minidom وstdlib هو استخدام c14n. ولكن هل يجب أن يكون PyXML ملحقات تثبيت لهذا لذلك كنت لا تزال لا تستطيع أن تفعل ذلك تماما داخل 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

استخدم xmldiff أو أداة الثعبان الذي يتوصل الى الخلافات بين اثنين من ملفات XML مماثلة، وبنفس الطريقة أن فرق يفعل ذلك.

لماذا فحص بيانات XML في كل شيء؟

والطريقة لاختبار التسلسل الكائن هو إنشاء مثيل من الكائن، تسلسل ذلك، إلغاء تسلسل قبل أن تتحول إلى كائن جديد، والمقارنة بين الكائنين. عند إجراء التغيير الذي يكسر التسلسل أو إلغاء التسلسل، ستفشل هذا الاختبار.

والشيء الوحيد التحقق من البيانات XML سوف تجد لك هو إذا كان مسلسل بك والتي ينبعث منها مجموعة شاملة من ما يتطلب deserializer، وdeserializer يتجاهل بصمت الاشياء انها لا تتوقع.

وبطبيعة الحال، إذا كان هناك شيء آخر سوف يتم استهلاك البيانات المتسلسلة، فهذا موضوع آخر. ولكن في هذه الحالة، يجب عليك أن تفكر في إنشاء مخطط لXML والتحقق من صحة ذلك.

أنا أيضا عانيت من هذه المشكلة و قمت ببعض البحث حول ذلك اليوم.على doctestcompare النهج قد تكفي, ولكن وجدت عبر إيان Bicking أنه يستند إلى formencode.doctest_xml_compare.الذي يظهر إلى الآن هنا.كما ترون هذا هو بسيط جدا وظيفة ، على عكس doctestcompare (على الرغم من أنني أعتقد doctestcompare هو جمع كل فشل و ربما أكثر تطورا التحقق).على أي حال نسخ/استيراد xml_compare من formencode قد يكون حلا جيدا.

والمكون dbUnit جافا يفعل الكثير من المقارنات XML، لذلك قد تجد أنه من المفيد أن ننظر إلى نهجها (وخصوصا في العثور على أي gotchas ان تكون قد تناولت بالفعل).

def xml_to_json(self, xml):
    """Receive 1 lxml etree object and return a json string"""
    def recursive_dict(element):
        return (element.tag.split('}')[1],
                dict(map(recursive_dict, element.getchildren()),
                     **element.attrib))
    return json.dumps(dict([recursive_dict(xml)]),
                      default=lambda x: str(x))

def assertEqualXML(self, xml_real, xml_expected):
    """Receive 2 objectify objects and show a diff assert if exists."""
    xml_expected_str = json.loads(self.xml_to_json(xml_expected))
    xml_real_str = json.loads(self.xml_to_json(xml_real))
    self.maxDiff = None
    self.assertEqual(xml_real_str, xml_expected_str)

هل يمكن أن نرى الانتاج مثل ما يلي:

                u'date': u'2016-11-22T19:55:02',
                u'item2': u'MX-INV0007',
         -      u'item3': u'Payments',
         ?                  ^^^
         +      u'item3': u'OAYments',
         ?                  ^^^ +

ويمكن القيام به بسهولة مع minidom:

class XmlTest(TestCase):
    def assertXmlEqual(self, got, want):
        return self.assertEqual(parseString(got).toxml(), parseString(want).toxml())
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top