1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
#!/usr/bin/env python
"""
Usage: {prog} [OPTION] FILE1 FILE2
Compare two XML files, ignoring element and attribute order.
Any extra options are passed to the `diff' command.
Copyright (c) 2017, Johannes H. Jensen.
License: BSD, see LICENSE for more details.
"""
from __future__ import print_function, unicode_literals
import sys
import os
import io
import xml.etree.ElementTree as ET
from tempfile import NamedTemporaryFile
import subprocess
def attr_str(k, v):
return "{}=\"{}\"".format(k,v)
def node_str(n):
attrs = sorted(n.attrib.items())
astr = " ".join(attr_str(k,v) for k,v in attrs)
s = n.tag
if astr:
s += " " + astr
return s
def node_key(n):
return node_str(n)
def indent(s, level):
return " " * level + s
def write_sorted(stream, node, level=0):
children = node.getchildren()
text = (node.text or "").strip()
tail = (node.tail or "").strip()
if children or text:
children.sort(key=node_key)
stream.write(indent("<" + node_str(node) + ">\n", level))
if text:
stream.write(indent(text + "\n", level))
for child in children:
write_sorted(stream, child, level + 1)
stream.write(indent("</" + node.tag + ">\n", level))
else:
stream.write(indent("<" + node_str(node) + "/>\n", level))
if tail:
stream.write(indent(tail + "\n", level))
if sys.version_info < (3, 0):
# Python 2
import codecs
def unicode_writer(fp):
return codecs.getwriter('utf-8')(fp)
else:
# Python 3
def unicode_writer(fp):
return fp
def xmldiffs(file1, file2, diffargs=["-u"]):
tree = ET.parse(file1)
tmp1 = unicode_writer(NamedTemporaryFile('w'))
write_sorted(tmp1, tree.getroot())
tmp1.flush()
tree = ET.parse(file2)
tmp2 = unicode_writer(NamedTemporaryFile('w'))
write_sorted(tmp2, tree.getroot())
tmp2.flush()
args = [ "diff" ]
args += diffargs
args += [ "--label", file1, "--label", file2 ]
args += [ tmp1.name, tmp2.name ]
return subprocess.call(args)
def print_usage(prog):
print(__doc__.format(prog=prog).strip())
if __name__ == '__main__':
args = sys.argv
prog = os.path.basename(args.pop(0))
if '-h' in args or '--help' in args:
print_usage(prog)
exit(0)
if len(args) < 2:
print_usage(prog)
exit(1)
file2 = args.pop(-1)
file1 = args.pop(-1)
diffargs = args if args else ["-u"]
exit(xmldiffs(file1, file2, diffargs))
|