def _validate_xml(spec, data, xmltext): """Validate the decoded xml. We don't just use the internal xml and compare it against the external xm; there may be differences in whitespace, and some fields can be represented in multiple ways (eg: 5.0 vs 5.00000 vs 5). """ xml_entries = xml.etree.ElementTree.iterparse(StringIO.StringIO(xmltext), ['start', 'end']) child_tail=None for (is_starting, name, entry, data, expected), (a_event, a_elem) in itertools.izip(_decode_visible(spec, data), xml_entries): if is_starting and a_event != 'start': raise Exception ("Expected '%s' to be starting, but got '%s' ending" % (name, a_elem.tag)) if not is_starting and a_event != 'end': raise Exception ("Expected '%s' to be ending, but got '%s' starting" % (name, a_elem.tag)) if xmlout.escape_name(name) != a_elem.tag: raise Exception("expected '%s', got '%s'" % (xmlout.escape_name(name), a_elem.tag)) if not is_starting: text = a_elem.text if not text or not text.strip() and child_tail is not None: # We don't have a text node for this child; try using its # child's trailing text. text = child_tail if not text or not text.strip(): # This node doesn't have data; it's possible that it has an # expected value, so wasn't printed. Get the expected value # from the constraint. try: text = _get_expected(entry) except _NoExpectedError: # We don't have an expected value; stick with the existing # text. pass except _ComplexExpectedError: # We have an expected value that is difficult to evaluate. # Just use the existing expected... this effectively short # circuits the test. text = expected if text is None: text = '' if expected is not None: if isinstance(entry, fld.Field): actual = convert_value(entry, text, len(data)) else: actual = int(text) if expected != actual: # If the value is different, it may be that the data cannot # be represented in xml (eg: a string with a binary # character). Encode and decode the expected value to see if # matches now (being escaped itself...) expected_text = xmlout.xml_strip(unicode(expected)) escaped_expected = convert_value(entry, expected_text, len(data)) constraint = Equals(escaped_expected) constraint.check(entry, actual, {}) elif a_elem.text is not None and a_elem.text.strip(): raise Exception("Expected empty text in entry '%s', got '%s'!" % (a_elem.tag, a_elem.text)) child_tail=a_elem.tail else: child_tail=None