Mercurial > hg > lxmldump
annotate lxmldump.py @ 8:ce07bb2a247b
More work.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 11 May 2021 02:08:30 +0300 |
parents | 4b4299b62f7f |
children | 2a8c65d22f86 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/python3 -B |
2 # coding=utf-8 | |
3 ### | |
4 | 4 ### lxmldump - Dump ISO/FDIS 1951 XML file data |
5 ### Programmed and designed by Matti 'ccr' Hämäläinen <ccr@tnsp.org> | |
6 ### (C) Copyright 2021 Tecnic Software productions (TNSP) | |
7 ### | |
8 ### Python 3.7+ required! | |
0 | 9 ### |
10 import sys | |
11 import signal | |
12 import re | |
13 from pathlib import Path | |
14 import xml.etree.ElementTree as xmlET | |
5
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
15 import unicodedata |
0 | 16 |
17 assert sys.version_info >= (3, 7) | |
18 | |
19 | |
20 ### | |
21 ### Default settings | |
22 ### | |
23 pkk_cfg = { | |
8 | 24 "verbosity": 3, |
25 | |
26 "annotate": False, | |
0 | 27 "dump": False, |
5
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
28 "normalize": False, |
7 | 29 |
30 "debug": False, | |
0 | 31 } |
32 | |
33 | |
7 | 34 pkk_str_fmap = { |
35 "Fragment" : ["<", ">"], | |
36 } | |
37 | |
38 | |
39 pkk_debug_list = [ | |
40 "ahas", | |
41 "ahavakkaine", | |
42 "ahavakala", | |
43 "ahavakoittuo", | |
44 "ahvaliha", | |
45 ] | |
46 | |
47 | |
0 | 48 ### |
49 ### Misc. helper functions, etc | |
50 ### | |
51 def pkk_cleanup(): | |
52 return 0 | |
53 | |
54 | |
55 ## Wrapper for print() | |
5
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
56 def pkk_print(smsg): |
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
57 if pkk_cfg["normalize"]: |
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
58 sys.stdout.write(unicodedata.normalize("NFC", smsg)) |
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
59 else: |
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
60 sys.stdout.write(smsg) |
0 | 61 |
7 | 62 def pkk_printi(indent, smsg): |
63 pkk_print((" " * indent) + smsg) | |
64 | |
0 | 65 |
8 | 66 def pkk_verbosity(lvl): |
67 return pkk_cfg["verbosity"] >= lvl | |
68 | |
69 | |
0 | 70 ## Fatal error handler |
71 def pkk_fatal(smsg): | |
72 print(u"ERROR: "+ smsg) | |
73 sys.exit(1) | |
74 | |
75 | |
76 ## Handler for SIGINT signals | |
77 def pkk_signal_handler(signal, frame): | |
78 pkk_cleanup() | |
79 print(u"\nQuitting due to SIGINT / Ctrl+C!") | |
80 sys.exit(1) | |
81 | |
82 | |
7 | 83 def pkk_get_text(lnode): |
84 stmp = "" | |
85 for pnode in lnode.iter(): | |
86 if isinstance(pnode.text, str): | |
8 | 87 if pkk_cfg["annotate"] and isinstance(pnode.tag, str) and pnode.tag in pkk_str_fmap: |
7 | 88 stmp += pkk_str_fmap[pnode.tag][0] + pnode.text + pkk_str_fmap[pnode.tag][1] |
89 else: | |
90 stmp += pnode.text | |
91 | |
92 if isinstance(pnode.tail, str): | |
93 stmp += pnode.tail | |
94 | |
95 return stmp.strip() | |
96 | |
97 | |
6 | 98 ## |
7 | 99 def pkk_dump_recursive(indent, lnode): |
100 if lnode.tag in ["Example"]: | |
101 stmp = pkk_get_text(lnode) | |
102 pkk_printi(indent, "{} \"{}\"".format(lnode.tag, stmp)) | |
6 | 103 else: |
7 | 104 if isinstance(lnode.text, str): |
105 stmp = lnode.text.strip() | |
106 if stmp != "": | |
107 stmp = " \""+ stmp +"\"" | |
108 else: | |
109 stmp = "" | |
6 | 110 |
111 if len(lnode.attrib) > 0: | |
112 atmp = " "+str(lnode.attrib) | |
113 else: | |
114 atmp = "" | |
115 | |
7 | 116 pkk_printi(indent, "{}{}{}\n".format(lnode.tag, atmp, stmp)) |
6 | 117 for qnode in lnode.findall("./*"): |
7 | 118 pkk_dump_recursive(indent + 1, qnode) |
6 | 119 |
120 | |
121 ## | |
7 | 122 def pkk_output_one(indent, dnode, dsub): |
123 for qnode in dnode.findall(dsub): | |
124 pkk_printi(indent, "{}\n".format(pkk_get_text(qnode))) | |
125 | |
126 def pkk_output_subs(indent, dnode, dsub, dname): | |
127 for qnode in dnode.findall(dsub): | |
128 pkk_printi(indent, "{} \"{}\"\n".format(dname, pkk_get_text(qnode))) | |
129 | |
130 | |
131 def pkk_output_sense(indent, dnode): | |
132 pkk_output_subs(indent, dnode, "./SearchForm", "srch") | |
133 pkk_output_subs(indent, dnode, "./Definition", "defn") | |
134 | |
135 for wnode in dnode.findall("./ExampleBlock/ExampleCtn"): | |
136 sstr = pkk_get_text(wnode.find("./Example")) | |
8 | 137 lstr = "" |
6 | 138 |
8 | 139 if pkk_verbosity(1): |
140 ltmp = [] | |
141 for qnode in wnode.findall("./FreeTopic[@type='levikki']/GeographicalUsage"): | |
142 ltmp.append("{} [{}]".format(pkk_get_text(qnode), qnode.attrib["class"])) | |
143 | |
144 if len(ltmp) > 0: | |
145 lstr = " ({})".format(", ".join(ltmp)) | |
7 | 146 |
147 pkk_printi(indent + 1, "{} \"{}\"{}\n".format("exmp", sstr, lstr)) | |
148 | |
149 | |
150 def pkk_output_node(indent, dnode): | |
6 | 151 |
7 | 152 for wnode in dnode.findall("./HeadwordCtn"): |
153 pkk_output_one (indent, wnode, "./Headword") | |
154 pkk_output_sense(indent + 1, wnode) | |
6 | 155 |
7 | 156 index = 1 |
157 for wnode in dnode.findall("./SenseGrp"): | |
8 | 158 pkk_printi(indent + 1, "sense #{}\n".format(index)) |
7 | 159 pkk_output_sense(indent + 2, wnode) |
160 index += 1 | |
6 | 161 |
162 | |
0 | 163 ### |
164 ### Main program starts | |
165 ### | |
166 signal.signal(signal.SIGINT, pkk_signal_handler) | |
167 | |
168 | |
169 ### Check if we have arguments | |
170 pkk_show_help = False | |
171 pkk_filenames = [] | |
172 argc = 1 | |
173 while argc < len(sys.argv): | |
174 arg = sys.argv[argc] | |
175 | |
176 needs_param = False | |
177 if argc + 1 < len(sys.argv): | |
178 param = sys.argv[argc + 1] | |
179 else: | |
180 param = None | |
181 | |
182 # Check for option type arg | |
183 if arg[0:1] == "-": | |
184 oarg = arg | |
185 arg = arg.lstrip("-") | |
186 | |
187 if arg == "help" or arg == "h": | |
188 pkk_show_help = True | |
189 elif arg == "dump" or arg == "d": | |
190 pkk_cfg["dump"] = True | |
5
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
191 elif arg == "normalize" or arg == "n": |
274b2091137c
Some more work on cleaning this up.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
192 pkk_cfg["normalize"] = True |
8 | 193 elif arg == "annotate" or arg == "a": |
194 pkk_cfg["annotate"] = True | |
7 | 195 elif arg == "p": |
196 pkk_cfg["debug"] = True | |
8 | 197 elif arg == "verbosity" or arg == "v": |
198 needs_param = True | |
199 pkk_cfg["verbosity"] = param | |
0 | 200 else: |
201 pkk_fatal(u"Invalid option argument '{0}'.".format(oarg)) | |
202 | |
203 if needs_param and param == None: | |
204 pkk_fatal(u"Option '{0}' requires an argument.".format(oarg)) | |
205 else: | |
206 # Non-option argument | |
207 pkk_filenames.append(arg) | |
208 | |
209 if needs_param: | |
210 argc += 2 | |
211 else: | |
212 argc += 1 | |
213 | |
214 | |
215 ### Show help if requested | |
216 if pkk_show_help or len(pkk_filenames) == 0: | |
217 print(u"lxmldump - Dump ISO/FDIS 1951 XML file data") | |
218 print(u"Usage: {0} <options> <input xml file(s)>". | |
219 format(str(Path(sys.argv[0]).name))) | |
220 print(u"") | |
221 print(u" --help Show this help") | |
222 print(u" -d, --dump Dump mode") | |
6 | 223 print(u" -n, --normalize Output NFC normalized Unicode") |
8 | 224 print(u" -a, --annotate Annotate strings") |
225 print(u" -v, --verbosity <n> Set verbosity level (0 - 3)") | |
0 | 226 print(u"") |
227 sys.exit(0) | |
228 | |
229 | |
8 | 230 ### Validate settings |
231 try: | |
232 pkk_cfg["verbosity"] = int(pkk_cfg["verbosity"]) | |
233 except Exception as e: | |
234 pkk_fatal(u"Verbosity level is not a valid integer.") | |
235 if pkk_cfg["verbosity"] < 0 or pkk_cfg["verbosity"] > 3: | |
236 pkk_fatal(u"Invalid verbosity level value {0}.".format(pkk_cfg["verbosity"])) | |
237 | |
238 | |
6 | 239 ### Handle each input file |
0 | 240 for filename in pkk_filenames: |
241 # Parse XML file into element tree | |
242 try: | |
243 uxml = xmlET.parse(filename) | |
244 except Exception as e: | |
245 pkk_fatal(u"SVG/XML parsing failed: {0}".format(str(e))) | |
246 | |
247 # Dump output | |
248 try: | |
249 xroot = uxml.getroot() | |
250 for dnode in xroot.findall("./DictionaryEntry"): | |
7 | 251 |
252 if pkk_cfg["debug"] and dnode.attrib["identifier"] not in pkk_debug_list: | |
253 continue | |
254 | |
0 | 255 if pkk_cfg["dump"]: |
7 | 256 pkk_dump_recursive(0, dnode) |
0 | 257 else: |
7 | 258 pkk_output_node(0, dnode) |
259 | |
260 print("\n") | |
0 | 261 |
262 except (BrokenPipeError, IOError) as e: | |
263 sys.stderr.close() | |
264 sys.exit(1) | |
265 | |
266 pkk_cleanup() | |
267 sys.exit(0) |