def _compare_node(expected, actual, state, idx):
<EOL>if expected.tag != actual.tag:<EOL><INDENT>raise AssertionError("<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(state, idx, expected.tag, actual.tag))<EOL><DEDENT>with state.node(expected.tag, idx):<EOL><INDENT>expected_attrs = set(expected.attrib.keys())<EOL>actual_attrs = set(actual.attrib.keys())<EOL>if expected_attrs != actual_attrs:<EOL><INDENT>expected = '<STR_LIT:U+002CU+0020>'.join(sorted(expected_attrs - actual_attrs))<EOL>actual = '<STR_LIT:U+002CU+0020>'.join(sorted(actual_attrs - expected_attrs))<EOL>raise AssertionError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(state, expected, actual))<EOL><DEDENT>for key in expected_attrs:<EOL><INDENT>expected_value = expected.attrib[key]<EOL>actual_value = actual.attrib[key]<EOL>if '<STR_LIT>' in (expected_value, actual_value):<EOL><INDENT>continue<EOL><DEDENT>elif expected_value != actual_value:<EOL><INDENT>raise AssertionError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(state, key, expected_value,<EOL>actual_value))<EOL><DEDENT><DEDENT>if len(expected) == <NUM_LIT:0> and len(actual) == <NUM_LIT:0>:<EOL><INDENT>if ('<STR_LIT>' not in (expected.text, actual.text) and<EOL>expected.text != actual.text):<EOL><INDENT>raise AssertionError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(state, expected.text, actual.text))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>expected_idx = <NUM_LIT:0><EOL>actual_idx = <NUM_LIT:0><EOL>while (expected_idx < len(expected) and<EOL>actual_idx < len(actual)):<EOL><INDENT>if (expected[expected_idx].tag in<EOL>(etree.Comment, etree.ProcessingInstruction)):<EOL><INDENT>expected_idx += <NUM_LIT:1><EOL>continue<EOL><DEDENT>result = _compare_node(expected[expected_idx],<EOL>actual[actual_idx], state,<EOL>actual_idx)<EOL>if result is not True:<EOL><INDENT>return result<EOL><DEDENT>expected_idx += <NUM_LIT:1><EOL>actual_idx += <NUM_LIT:1><EOL><DEDENT>if actual_idx < len(actual):<EOL><INDENT>raise AssertionError("<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(state, actual[actual_idx].tag,<EOL>actual_idx))<EOL><DEDENT>if expected_idx < len(expected):<EOL><INDENT>for node in expected[expected_idx:]:<EOL><INDENT>if (node.tag in<EOL>(etree.Comment, etree.ProcessingInstruction)):<EOL><INDENT>continue<EOL><DEDENT>raise AssertionError("<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(state, node.tag, actual_idx))<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return True<EOL>
Recursively compares nodes within the XML tree.