Try to do a 'xml-comparison' of want and got. Plain string comparison doesn't always work because, for example, attribute ordering should not be important. Ignore comment nodes, processing instructions, document type node, and leading and trailing whitespaces. Based on http
(want, got)
| 647 | |
| 648 | |
| 649 | def compare_xml(want, got): |
| 650 | """ |
| 651 | Try to do a 'xml-comparison' of want and got. Plain string comparison |
| 652 | doesn't always work because, for example, attribute ordering should not be |
| 653 | important. Ignore comment nodes, processing instructions, document type |
| 654 | node, and leading and trailing whitespaces. |
| 655 | |
| 656 | Based on |
| 657 | https://github.com/lxml/lxml/blob/master/src/lxml/doctestcompare.py |
| 658 | """ |
| 659 | _norm_whitespace_re = re.compile(r"[ \t\n][ \t\n]+") |
| 660 | |
| 661 | def norm_whitespace(v): |
| 662 | return _norm_whitespace_re.sub(" ", v) |
| 663 | |
| 664 | def child_text(element): |
| 665 | return "".join( |
| 666 | c.data for c in element.childNodes if c.nodeType == Node.TEXT_NODE |
| 667 | ) |
| 668 | |
| 669 | def children(element): |
| 670 | return [c for c in element.childNodes if c.nodeType == Node.ELEMENT_NODE] |
| 671 | |
| 672 | def norm_child_text(element): |
| 673 | return norm_whitespace(child_text(element)) |
| 674 | |
| 675 | def attrs_dict(element): |
| 676 | return dict(element.attributes.items()) |
| 677 | |
| 678 | def check_element(want_element, got_element): |
| 679 | if want_element.tagName != got_element.tagName: |
| 680 | return False |
| 681 | if norm_child_text(want_element) != norm_child_text(got_element): |
| 682 | return False |
| 683 | if attrs_dict(want_element) != attrs_dict(got_element): |
| 684 | return False |
| 685 | want_children = children(want_element) |
| 686 | got_children = children(got_element) |
| 687 | if len(want_children) != len(got_children): |
| 688 | return False |
| 689 | return all( |
| 690 | check_element(want, got) for want, got in zip(want_children, got_children) |
| 691 | ) |
| 692 | |
| 693 | def first_node(document): |
| 694 | for node in document.childNodes: |
| 695 | if node.nodeType not in ( |
| 696 | Node.COMMENT_NODE, |
| 697 | Node.DOCUMENT_TYPE_NODE, |
| 698 | Node.PROCESSING_INSTRUCTION_NODE, |
| 699 | ): |
| 700 | return node |
| 701 | |
| 702 | want = want.strip().replace("\\n", "\n") |
| 703 | got = got.strip().replace("\\n", "\n") |
| 704 | |
| 705 | # If the string is not a complete xml document, we may need to add a |
| 706 | # root element. This allow us to compare fragments, like "<foo/><bar/>" |