35 msg = str(msg) + "\n" |
35 msg = str(msg) + "\n" |
36 except: |
36 except: |
37 msg = u(msg) + "\n" |
37 msg = u(msg) + "\n" |
38 sys.stderr.write(msg) |
38 sys.stderr.write(msg) |
39 |
39 |
40 optParser = OptionParser() |
40 def main(): |
41 optParser.add_option("-C", "--old-syntax", action="store_true", dest="old_syntax", |
41 optParser = OptionParser() |
42 help="syntax of YML 2 version 1.x (compatibility mode)", default=False) |
42 optParser.add_option("-C", "--old-syntax", action="store_true", dest="old_syntax", |
43 optParser.add_option("-D", "--emit-linenumbers", action="store_true", dest="emitlinenumbers", |
43 help="syntax of YML 2 version 1.x (compatibility mode)", default=False) |
44 help="emit line numbers into the resulting XML for debugging purposes", default=False) |
44 optParser.add_option("-D", "--emit-linenumbers", action="store_true", dest="emitlinenumbers", |
45 optParser.add_option("--debug", action="store_true", dest="trace", |
45 help="emit line numbers into the resulting XML for debugging purposes", default=False) |
46 help="switch on tracing to stderr", default=False) |
46 optParser.add_option("--debug", action="store_true", dest="trace", |
47 optParser.add_option("-d", "--paramdict", dest="params", metavar="PARAMS", |
47 help="switch on tracing to stderr", default=False) |
48 help="call X/YSLT script with dictionary PARAMS as parameters") |
48 optParser.add_option("-d", "--paramdict", dest="params", metavar="PARAMS", |
49 optParser.add_option("-e", "--xpath", dest="xpath", metavar="XPATH", |
49 help="call X/YSLT script with dictionary PARAMS as parameters") |
50 help="execute XPath expression XPATH and print result") |
50 optParser.add_option("-e", "--xpath", dest="xpath", metavar="XPATH", |
51 optParser.add_option("-E", "--encoding", dest="encoding", metavar="ENCODING", default=locale.getdefaultlocale()[1], |
51 help="execute XPath expression XPATH and print result") |
52 help="encoding of input files (default to locale)") |
52 optParser.add_option("-E", "--encoding", dest="encoding", metavar="ENCODING", default=locale.getdefaultlocale()[1], |
53 optParser.add_option("-I", "--include", dest="includePathText", metavar="INCLUDE_PATH", |
53 help="encoding of input files (default to locale)") |
54 help="precede YML_PATH by a colon separated INCLUDE_PATH to search for include files") |
54 optParser.add_option("-I", "--include", dest="includePathText", metavar="INCLUDE_PATH", |
55 optParser.add_option("-m", "--omit-empty-parm-tags", action="store_true", dest="omitemptyparm", |
55 help="precede YML_PATH by a colon separated INCLUDE_PATH to search for include files") |
56 help="does nothing (only there for compatibility reasons)", default=False) |
56 optParser.add_option("-m", "--omit-empty-parm-tags", action="store_true", dest="omitemptyparm", |
57 optParser.add_option("-M", "--empty-input-document", action="store_true", dest="emptyinput", |
57 help="does nothing (only there for compatibility reasons)", default=False) |
58 help="use an empty input document", default=False) |
58 optParser.add_option("-M", "--empty-input-document", action="store_true", dest="emptyinput", |
59 optParser.add_option("-n", "--normalization", dest="normalization", metavar="NORMALIZATION", default="NFC", |
59 help="use an empty input document", default=False) |
60 help="Unicode normalization (none, NFD, NFKD, NFC, NFKC, FCD, default is NFC)") |
60 optParser.add_option("-n", "--normalization", dest="normalization", metavar="NORMALIZATION", default="NFC", |
61 optParser.add_option("-o", "--output", dest="outputFile", metavar="FILE", |
61 help="Unicode normalization (none, NFD, NFKD, NFC, NFKC, FCD, default is NFC)") |
62 help="place output in file FILE") |
62 optParser.add_option("-o", "--output", dest="outputFile", metavar="FILE", |
63 optParser.add_option("-p", "--parse-only", action="store_true", dest="parseonly", |
63 help="place output in file FILE") |
64 help="parse only, then output pyAST as text to stdout", default=False) |
64 optParser.add_option("-p", "--parse-only", action="store_true", dest="parseonly", |
65 optParser.add_option("-P", "--pretty", action="store_true", default=False, |
65 help="parse only, then output pyAST as text to stdout", default=False) |
66 help="pretty print output adding whitespace") |
66 optParser.add_option("-P", "--pretty", action="store_true", default=False, |
67 optParser.add_option("-s", "--stringparamdict", dest="stringparams", metavar="STRINGPARAMS", |
67 help="pretty print output adding whitespace") |
68 help="call X/YSLT script with dictionary STRINGPARAMS as string parameters") |
68 optParser.add_option("-s", "--stringparamdict", dest="stringparams", metavar="STRINGPARAMS", |
69 optParser.add_option("-x", "--xml", action="store_true", default=False, |
69 help="call X/YSLT script with dictionary STRINGPARAMS as string parameters") |
70 help="input document is XML already") |
70 optParser.add_option("-x", "--xml", action="store_true", default=False, |
71 optParser.add_option("-X", "--xslt", dest="xslt", metavar="XSLTSCRIPT", |
71 help="input document is XML already") |
72 help="execute XSLT script XSLTSCRIPT") |
72 optParser.add_option("-X", "--xslt", dest="xslt", metavar="XSLTSCRIPT", |
73 optParser.add_option("-y", "--yslt", dest="yslt", metavar="YSLTSCRIPT", |
73 help="execute XSLT script XSLTSCRIPT") |
74 help="execute YSLT script YSLTSCRIPT") |
74 optParser.add_option("-y", "--yslt", dest="yslt", metavar="YSLTSCRIPT", |
75 optParser.add_option("-Y", "--xml2yml", action="store_true", default=False, |
75 help="execute YSLT script YSLTSCRIPT") |
76 help="convert XML to normalized YML code") |
76 optParser.add_option("-Y", "--xml2yml", action="store_true", default=False, |
77 optParser.add_option("-V", "--version", action="callback", callback=printInfo, help="show version info and exit") |
77 help="convert XML to normalized YML code") |
78 (options, args) = optParser.parse_args() |
78 optParser.add_option("-V", "--version", action="callback", callback=printInfo, help="show version info and exit") |
79 |
79 (options, args) = optParser.parse_args() |
80 if options.old_syntax: |
80 |
81 oldSyntax() |
81 if options.old_syntax: |
82 |
82 oldSyntax() |
83 if options.trace: |
83 |
84 backend.enable_tracing = True |
84 if options.trace: |
85 |
85 backend.enable_tracing = True |
86 if options.emitlinenumbers: |
86 |
87 backend.emitlinenumbers = True |
87 if options.emitlinenumbers: |
88 |
88 backend.emitlinenumbers = True |
89 if options.includePathText: |
89 |
90 backend.includePath = options.includePathText.split(':') |
90 if options.includePathText: |
91 |
91 backend.includePath = options.includePathText.split(':') |
92 backend.encoding = options.encoding |
92 |
93 |
93 backend.encoding = options.encoding |
94 dirs = os.environ.get('YML_PATH', '.').split(':') + YML_DEFAULT_PATH |
94 |
95 backend.includePath.extend(dirs) |
95 dirs = os.environ.get('YML_PATH', '.').split(':') + YML_DEFAULT_PATH |
96 |
96 backend.includePath.extend(dirs) |
97 if options.xml2yml: |
97 |
98 for directory in backend.includePath: |
98 if options.xml2yml: |
99 name = os.path.join(directory, "xml2yml.ysl2") |
99 for directory in backend.includePath: |
100 if os.path.isfile(name): |
100 name = os.path.join(directory, "xml2yml.ysl2") |
101 options.yslt = name |
101 if os.path.isfile(name): |
102 options.xml = True |
102 options.yslt = name |
103 break |
103 options.xml = True |
104 else: |
104 break |
105 sys.stderr.write("Error: Stylesheet xml2yml.ysl2 required for --xml2yml not found\n") |
105 else: |
106 sys.stderr.write("Please check your YML_PATH\n") |
106 sys.stderr.write("Error: Stylesheet xml2yml.ysl2 required for --xml2yml not found\n") |
|
107 sys.stderr.write("Please check your YML_PATH\n") |
|
108 sys.exit(1) |
|
109 |
|
110 if (options.xslt and options.yslt) or (options.xslt and options.xpath) or (options.yslt and options.xpath): |
|
111 sys.stderr.write("Cannot combine --xpath, --xslt and --yslt params\n") |
107 sys.exit(1) |
112 sys.exit(1) |
108 |
113 |
109 if (options.xslt and options.yslt) or (options.xslt and options.xpath) or (options.yslt and options.xpath): |
114 try: |
110 sys.stderr.write("Cannot combine --xpath, --xslt and --yslt params\n") |
115 ymlC = ymlCStyle() |
111 sys.exit(1) |
116 |
112 |
117 rtext = "" |
113 try: |
118 |
114 ymlC = ymlCStyle() |
119 if not options.emptyinput: |
115 |
120 files = fileinput.input(args, mode="rU", openhook=fileinput.hook_encoded(options.encoding)) |
116 rtext = "" |
121 |
117 |
122 if options.xml: |
118 if not options.emptyinput: |
123 rtext = "" |
119 files = fileinput.input(args, mode="rU", openhook=fileinput.hook_encoded(options.encoding)) |
124 for line in files: |
120 |
125 rtext += line |
121 if options.xml: |
126 else: |
|
127 result = parse(ymlC, files, True, comment) |
|
128 if options.parseonly: |
|
129 print(result) |
|
130 sys.exit(0) |
|
131 else: |
|
132 rtext = backend.finish(result) |
|
133 |
|
134 if not rtext: |
|
135 rtext = "<empty/>" |
|
136 |
|
137 def ymldebug(context, text): |
|
138 if options.trace: |
|
139 sys.stderr.write("Debug: " + codecs.encode(u(text), options.encoding) + "\n") |
|
140 return "" |
|
141 |
|
142 def ymlassert(context, value, msg): |
|
143 if options.trace: |
|
144 if not value: |
|
145 raise YMLAssert(msg) |
|
146 return "" |
|
147 |
|
148 ymlns = etree.FunctionNamespace("http://fdik.org/yml") |
|
149 ymlns.prefix = "yml" |
|
150 ymlns['debug'] = ymldebug |
|
151 ymlns['assert'] = ymlassert |
|
152 |
|
153 if options.xpath: |
|
154 tree = etree.fromstring(rtext) |
|
155 ltree = tree.xpath(codecs.decode(options.xpath, options.encoding)) |
122 rtext = "" |
156 rtext = "" |
123 for line in files: |
157 try: |
124 rtext += line |
158 for rtree in ltree: |
|
159 rtext += etree.tostring(rtree, pretty_print=options.pretty, encoding=unicode) |
|
160 except: |
|
161 rtext = ltree |
|
162 |
|
163 elif options.yslt or options.xslt: |
|
164 params = {} |
|
165 |
|
166 if options.yslt: |
|
167 backend.clearAll() |
|
168 yscript = fileinput.input(options.yslt, mode="rU", openhook=fileinput.hook_encoded(options.encoding)) |
|
169 yresult = parse(ymlC, yscript, True, comment) |
|
170 ytext = backend.finish(yresult) |
|
171 else: |
|
172 yscript = fileinput.input(options.xslt, mode="rU") |
|
173 ytext = "" |
|
174 for line in yscript: |
|
175 ytext += line |
|
176 |
|
177 doc = etree.fromstring(rtext) |
|
178 |
|
179 xsltree = etree.XML(ytext, base_url=os.path.abspath(yscript.filename())) |
|
180 transform = etree.XSLT(xsltree) |
|
181 |
|
182 if options.params: |
|
183 params = eval(options.params) |
|
184 for key, value in params.iteritems(): |
|
185 if type(value) is not str: |
|
186 params[key] = u(value) |
|
187 if options.stringparams: |
|
188 for key, value in eval(options.stringparams).iteritems(): |
|
189 params[key] = "'" + u(value) + "'" |
|
190 |
|
191 rresult = transform(doc, **params) |
|
192 # lxml is somewhat buggy |
|
193 try: |
|
194 rtext = u(rresult) |
|
195 except: |
|
196 rtext = etree.tostring(rresult, encoding=unicode) |
|
197 if not rtext: |
|
198 rtext = codecs.decode(str(rresult), "utf-8") |
|
199 |
|
200 if options.normalization != "none": |
|
201 rtext = unicodedata.normalize(options.normalization, rtext) |
|
202 |
|
203 if options.pretty: |
|
204 plaintext = etree.tostring(etree.fromstring(rtext), pretty_print=True, xml_declaration=True, encoding=options.encoding) |
125 else: |
205 else: |
126 result = parse(ymlC, files, True, comment) |
206 if isinstance(rtext, str): |
127 if options.parseonly: |
207 plaintext = codecs.encode(rtext, options.encoding) |
128 print(result) |
|
129 sys.exit(0) |
|
130 else: |
208 else: |
131 rtext = backend.finish(result) |
209 plaintext = rtext |
132 |
210 |
133 if not rtext: |
|
134 rtext = "<empty/>" |
|
135 |
|
136 def ymldebug(context, text): |
|
137 if options.trace: |
|
138 sys.stderr.write("Debug: " + codecs.encode(u(text), options.encoding) + "\n") |
|
139 return "" |
|
140 |
|
141 def ymlassert(context, value, msg): |
|
142 if options.trace: |
|
143 if not value: |
|
144 raise YMLAssert(msg) |
|
145 return "" |
|
146 |
|
147 ymlns = etree.FunctionNamespace("http://fdik.org/yml") |
|
148 ymlns.prefix = "yml" |
|
149 ymlns['debug'] = ymldebug |
|
150 ymlns['assert'] = ymlassert |
|
151 |
|
152 if options.xpath: |
|
153 tree = etree.fromstring(rtext) |
|
154 ltree = tree.xpath(codecs.decode(options.xpath, options.encoding)) |
|
155 rtext = "" |
|
156 try: |
211 try: |
157 for rtree in ltree: |
212 if plaintext[-1] == "\n": |
158 rtext += etree.tostring(rtree, pretty_print=options.pretty, encoding=unicode) |
213 plaintext = plaintext[:-1] |
159 except: |
214 except: pass |
160 rtext = ltree |
215 |
161 |
216 if options.outputFile and options.outputFile != "-": |
162 elif options.yslt or options.xslt: |
217 outfile = open(options.outputFile, "wb") |
163 params = {} |
218 outfile.write(plaintext) |
164 |
219 outfile.close() |
165 if options.yslt: |
|
166 backend.clearAll() |
|
167 yscript = fileinput.input(options.yslt, mode="rU", openhook=fileinput.hook_encoded(options.encoding)) |
|
168 yresult = parse(ymlC, yscript, True, comment) |
|
169 ytext = backend.finish(yresult) |
|
170 else: |
220 else: |
171 yscript = fileinput.input(options.xslt, mode="rU") |
221 sys.stdout.buffer.write(plaintext) |
172 ytext = "" |
222 if not options.pretty: |
173 for line in yscript: |
223 print() |
174 ytext += line |
224 |
175 |
225 except KeyboardInterrupt: |
176 doc = etree.fromstring(rtext) |
226 w("\n") |
177 |
227 sys.exit(1) |
178 xsltree = etree.XML(ytext, base_url=os.path.abspath(yscript.filename())) |
228 except YMLAssert as msg: |
179 transform = etree.XSLT(xsltree) |
229 w("YML Assertion failed: " + u(msg) + "\n") |
180 |
230 sys.exit(2) |
181 if options.params: |
231 except KeyError as msg: |
182 params = eval(options.params) |
232 w("not found: " + u(msg) + "\n") |
183 for key, value in params.iteritems(): |
233 sys.exit(4) |
184 if type(value) is not str: |
234 except LookupError as msg: |
185 params[key] = u(value) |
235 w("not found: " + u(msg) + "\n") |
186 if options.stringparams: |
236 sys.exit(4) |
187 for key, value in eval(options.stringparams).iteritems(): |
237 except etree.XMLSyntaxError as e: |
188 params[key] = "'" + u(value) + "'" |
238 log = e.error_log.filter_from_level(etree.ErrorLevels.FATAL) |
189 |
239 for entry in log: |
190 rresult = transform(doc, **params) |
240 w("XML error: " + u(entry.message) + "\n") |
191 # lxml is somewhat buggy |
241 sys.exit(5) |
192 try: |
242 except Exception as msg: |
193 rtext = u(rresult) |
243 w(msg) |
194 except: |
244 sys.exit(5) |
195 rtext = etree.tostring(rresult, encoding=unicode) |
245 |
196 if not rtext: |
246 |
197 rtext = codecs.decode(str(rresult), "utf-8") |
247 if __name__ == "__main__": |
198 |
248 sys.exit(main()) |
199 if options.normalization != "none": |
249 |
200 rtext = unicodedata.normalize(options.normalization, rtext) |
|
201 |
|
202 if options.pretty: |
|
203 plaintext = etree.tostring(etree.fromstring(rtext), pretty_print=True, xml_declaration=True, encoding=options.encoding) |
|
204 else: |
|
205 if isinstance(rtext, str): |
|
206 plaintext = codecs.encode(rtext, options.encoding) |
|
207 else: |
|
208 plaintext = rtext |
|
209 |
|
210 try: |
|
211 if plaintext[-1] == "\n": |
|
212 plaintext = plaintext[:-1] |
|
213 except: pass |
|
214 |
|
215 if options.outputFile and options.outputFile != "-": |
|
216 outfile = open(options.outputFile, "wb") |
|
217 outfile.write(plaintext) |
|
218 outfile.close() |
|
219 else: |
|
220 sys.stdout.buffer.write(plaintext) |
|
221 if not options.pretty: |
|
222 print() |
|
223 |
|
224 except KeyboardInterrupt: |
|
225 w("\n") |
|
226 sys.exit(1) |
|
227 except YMLAssert as msg: |
|
228 w("YML Assertion failed: " + u(msg) + "\n") |
|
229 sys.exit(2) |
|
230 except KeyError as msg: |
|
231 w("not found: " + u(msg) + "\n") |
|
232 sys.exit(4) |
|
233 except LookupError as msg: |
|
234 w("not found: " + u(msg) + "\n") |
|
235 sys.exit(4) |
|
236 except etree.XMLSyntaxError as e: |
|
237 log = e.error_log.filter_from_level(etree.ErrorLevels.FATAL) |
|
238 for entry in log: |
|
239 w("XML error: " + u(entry.message) + "\n") |
|
240 sys.exit(5) |
|
241 except Exception as msg: |
|
242 w(msg) |
|
243 sys.exit(5) |
|