yml2/yml2proc.py
changeset 58 a218553807ab
parent 57 2f4ad3800a3f
child 60 b19d0a86651b
equal deleted inserted replaced
57:2f4ad3800a3f 58:a218553807ab
     1 #!/usr/bin/env python
     1 #!/usr/bin/env python3
     2 # vim: set fileencoding=utf-8 :
     2 # vim: set fileencoding=utf-8 :
     3 
     3 
     4 """\
     4 """\
     5 YML/YSLT 2 processor version 5.10
     5 YML/YSLT 2 processor version 6.2
     6 Copyleft (c), 2009-2018 Volker Birk  http://fdik.org/yml/
     6 Copyleft (c), 2009-2019 Volker Birk  http://fdik.org/yml/
     7 
     7 
     8 """
     8 """
     9 
     9 
    10 import sys, os, codecs, locale
    10 import sys, os, codecs, locale
    11 import fileinput, unicodedata
    11 import fileinput, unicodedata
    30 def w(msg):
    30 def w(msg):
    31     if isinstance(msg, BaseException):
    31     if isinstance(msg, BaseException):
    32         try:
    32         try:
    33             msg = str(msg) + "\n"
    33             msg = str(msg) + "\n"
    34         except:
    34         except:
    35             msg = u(msg) + u"\n"
    35             msg = u(msg) + "\n"
    36     if type(msg) is unicode:
       
    37         msg = codecs.encode(msg, sys.stderr.encoding)
       
    38     sys.stderr.write(msg)
    36     sys.stderr.write(msg)
    39 
       
    40 
    37 
    41 def main():
    38 def main():
    42     optParser = OptionParser()
    39     optParser = OptionParser()
    43     optParser.add_option("-C", "--old-syntax", action="store_true", dest="old_syntax",
    40     optParser.add_option("-C", "--old-syntax", action="store_true", dest="old_syntax",
    44             help="syntax of YML 2 version 1.x (compatibility mode)", default=False)
    41             help="syntax of YML 2 version 1.x (compatibility mode)", default=False)
    76             help="execute YSLT script YSLTSCRIPT")
    73             help="execute YSLT script YSLTSCRIPT")
    77     optParser.add_option("-Y", "--xml2yml", action="store_true", default=False,
    74     optParser.add_option("-Y", "--xml2yml", action="store_true", default=False,
    78             help="convert XML to normalized YML code")
    75             help="convert XML to normalized YML code")
    79     optParser.add_option("-V", "--version", action="callback", callback=printInfo, help="show version info and exit")
    76     optParser.add_option("-V", "--version", action="callback", callback=printInfo, help="show version info and exit")
    80     (options, args) = optParser.parse_args()
    77     (options, args) = optParser.parse_args()
    81 
    78     
    82     if options.old_syntax:
    79     if options.old_syntax:
    83         oldSyntax()
    80         oldSyntax()
    84 
    81     
    85     if options.trace:
    82     if options.trace:
    86         backend.enable_tracing = True
    83         backend.enable_tracing = True
    87 
    84     
    88     if options.emitlinenumbers:
    85     if options.emitlinenumbers:
    89         backend.emitlinenumbers = True
    86         backend.emitlinenumbers = True
    90 
    87     
    91     if options.includePathText:
    88     if options.includePathText:
    92         backend.includePath = options.includePathText.split(':')
    89         backend.includePath = options.includePathText.split(':')
    93 
    90     
    94     backend.encoding = options.encoding
    91     backend.encoding = options.encoding
    95 
    92     
    96     dirs = os.environ.get('YML_PATH', '.').split(':')
    93     dirs = os.environ.get('YML_PATH', '.').split(':')
    97     backend.includePath.extend(dirs)
    94     backend.includePath.extend(dirs)
    98 
    95     
    99     if options.xml2yml:
    96     if options.xml2yml:
   100         for directory in backend.includePath:
    97         for directory in backend.includePath:
   101             try:
    98             try:
   102                 name = directory + "/xml2yml.ysl2"
    99                 name = directory + "/xml2yml.ysl2"
   103                 f = open(name, "r")
   100                 f = open(name, "r")
   104                 f.close()
   101                 f.close()
   105                 break
   102                 break
   106             except:
   103             except:
   107                 pass
   104                 pass
   108 
   105     
   109         options.yslt = name
   106         options.yslt = name
   110         options.xml = True
   107         options.xml = True
   111 
   108     
   112     if  (options.xslt and options.yslt) or (options.xslt and options.xpath) or (options.yslt and options.xpath):
   109     if  (options.xslt and options.yslt) or (options.xslt and options.xpath) or (options.yslt and options.xpath):
   113         sys.stderr.write("Cannot combine --xpath, --xslt and --yslt params\n")
   110         sys.stderr.write("Cannot combine --xpath, --xslt and --yslt params\n")
   114         sys.exit(1)
   111         sys.exit(1)
   115 
   112     
   116     try:
   113     try:
   117         ymlC = ymlCStyle()
   114         ymlC = ymlCStyle()
   118 
   115     
   119         rtext = u""
   116         rtext = ""
   120 
   117     
   121         if not options.emptyinput:
   118         if not options.emptyinput:
   122             files = fileinput.input(args, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   119             files = fileinput.input(args, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   123 
   120     
   124             if options.xml:
   121             if options.xml:
   125                 rtext = ""
   122                 rtext = ""
   126                 for line in files:
   123                 for line in files:
   127                     rtext += line
   124                     rtext += line
   128             else:
   125             else:
   130                 if options.parseonly:
   127                 if options.parseonly:
   131                     print(result)
   128                     print(result)
   132                     sys.exit(0)
   129                     sys.exit(0)
   133                 else:
   130                 else:
   134                     rtext = backend.finish(result)
   131                     rtext = backend.finish(result)
   135 
   132     
   136         if not rtext:
   133         if not rtext:
   137             rtext = u"<empty/>"
   134             rtext = "<empty/>"
   138 
   135     
   139         def ymldebug(context, text):
   136         def ymldebug(context, text):
   140             if options.trace:
   137             if options.trace:
   141                 sys.stderr.write("Debug: " + codecs.encode(u(text), options.encoding) + "\n")
   138                 sys.stderr.write("Debug: " + codecs.encode(u(text), options.encoding) + "\n")
   142             return ""
   139             return ""
   143 
   140     
   144         def ymlassert(context, value, msg):
   141         def ymlassert(context, value, msg):
   145             if options.trace:
   142             if options.trace:
   146                 if not value:
   143                 if not value:
   147                     raise YMLAssert(msg)
   144                     raise YMLAssert(msg)
   148             return ""
   145             return ""
   149 
   146     
   150         ymlns = etree.FunctionNamespace("http://fdik.org/yml")
   147         ymlns = etree.FunctionNamespace("http://fdik.org/yml")
   151         ymlns.prefix = "yml"
   148         ymlns.prefix = "yml"
   152         ymlns['debug'] = ymldebug
   149         ymlns['debug'] = ymldebug
   153         ymlns['assert'] = ymlassert
   150         ymlns['assert'] = ymlassert
   154 
   151     
   155         if options.xpath:
   152         if options.xpath:
   156             tree = etree.fromstring(rtext)
   153             tree = etree.fromstring(rtext)
   157             ltree = tree.xpath(codecs.decode(options.xpath, options.encoding))
   154             ltree = tree.xpath(codecs.decode(options.xpath, options.encoding))
   158             rtext = u""
   155             rtext = ""
   159             try:
   156             try:
   160                 for rtree in ltree:
   157                 for rtree in ltree:
   161                     rtext += etree.tostring(rtree, pretty_print=options.pretty, encoding=unicode)
   158                     rtext += etree.tostring(rtree, pretty_print=options.pretty, encoding=unicode)
   162             except:
   159             except:
   163                 rtext = ltree
   160                 rtext = ltree
   164 
   161     
   165         elif options.yslt or options.xslt:
   162         elif options.yslt or options.xslt:
   166             params = {}
   163             params = {}
   167 
   164     
   168             if options.yslt:
   165             if options.yslt:
   169                 backend.clearAll()
   166                 backend.clearAll()
   170                 yscript = fileinput.input(options.yslt, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   167                 yscript = fileinput.input(options.yslt, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   171                 yresult = parse(ymlC, yscript, True, comment)
   168                 yresult = parse(ymlC, yscript, True, comment)
   172                 ytext = backend.finish(yresult)
   169                 ytext = backend.finish(yresult)
   173             else:
   170             else:
   174                 yscript = fileinput.input(options.xslt, mode="rU")
   171                 yscript = fileinput.input(options.xslt, mode="rU")
   175                 ytext = ""
   172                 ytext = ""
   176                 for line in yscript:
   173                 for line in yscript:
   177                     ytext += line
   174                     ytext += line
   178 
   175     
   179             doc = etree.fromstring(rtext)
   176             doc = etree.fromstring(rtext)
   180 
   177     
   181             xsltree = etree.XML(ytext, base_url=os.path.abspath(yscript.filename()))
   178             xsltree = etree.XML(ytext, base_url=os.path.abspath(yscript.filename()))
   182             transform = etree.XSLT(xsltree)
   179             transform = etree.XSLT(xsltree)
   183             
   180             
   184             if options.params:
   181             if options.params:
   185                 params = eval(options.params)
   182                 params = eval(options.params)
   186                 for key, value in params.iteritems():
   183                 for key, value in params.iteritems():
   187                     if type(value) != unicode:
   184                     if type(value) is not str:
   188                         params[key] = u(value)
   185                         params[key] = u(value)
   189             if options.stringparams:
   186             if options.stringparams:
   190                 for key, value in eval(options.stringparams).iteritems():
   187                 for key, value in eval(options.stringparams).iteritems():
   191                     params[key] = u"'" + u(value) + u"'"
   188                     params[key] = "'" + u(value) + "'"
   192 
   189     
   193             rresult = transform(doc, **params)
   190             rresult = transform(doc, **params)
   194             # lxml is somewhat buggy
   191             # lxml is somewhat buggy
   195             try:
   192             try:
   196                 rtext = u(rresult)
   193                 rtext = u(rresult)
   197             except:
   194             except:
   198                 rtext = etree.tostring(rresult, encoding=unicode)
   195                 rtext = etree.tostring(rresult, encoding=unicode)
   199                 if not rtext:
   196                 if not rtext:
   200                     rtext = codecs.decode(str(rresult), "utf-8")
   197                     rtext = codecs.decode(str(rresult), "utf-8")
   201 
   198     
   202         if options.normalization != "none":
   199         if options.normalization != "none":
   203             rtext = unicodedata.normalize(options.normalization, rtext)
   200             rtext = unicodedata.normalize(options.normalization, rtext)
   204 
   201     
   205         if options.pretty:
   202         if options.pretty:
   206             plaintext = etree.tostring(etree.fromstring(rtext), pretty_print=True, xml_declaration=True, encoding=options.encoding)
   203             plaintext = etree.tostring(etree.fromstring(rtext), pretty_print=True, xml_declaration=True, encoding=options.encoding)
   207         else:
   204         else:
   208             if isinstance(rtext, unicode):
   205             if isinstance(rtext, str):
   209                 plaintext = codecs.encode(rtext, options.encoding)
   206                 plaintext = codecs.encode(rtext, options.encoding)
   210             else:
   207             else:
   211                 plaintext = str(rtext)
   208                 plaintext = rtext
   212 
   209     
   213         try:
   210         try:
   214             if plaintext[-1] == "\n":
   211             if plaintext[-1] == "\n":
   215                 plaintext = plaintext[:-1]
   212                 plaintext = plaintext[:-1]
   216         except: pass
   213         except: pass
   217 
   214     
   218         if options.outputFile and options.outputFile != "-":
   215         if options.outputFile and options.outputFile != "-":
   219             outfile = open(options.outputFile, "w")
   216             outfile = open(options.outputFile, "wb")
   220             outfile.write(plaintext)
   217             outfile.write(plaintext)
   221             outfile.close()
   218             outfile.close()
   222         else:
   219         else:
   223             print(plaintext)
   220             sys.stdout.buffer.write(plaintext)
   224 
   221             if not options.pretty:
       
   222                 print()
       
   223     
   225     except KeyboardInterrupt:
   224     except KeyboardInterrupt:
   226         w("\n")
   225         w("\n")
   227         sys.exit(1)
   226         sys.exit(1)
   228     except YMLAssert as msg:
   227     except YMLAssert as msg:
   229         w(u"YML Assertion failed: " + u(msg) + u"\n")
   228         w("YML Assertion failed: " + u(msg) + "\n")
   230         sys.exit(2)
   229         sys.exit(2)
   231     except KeyError as msg:
   230     except KeyError as msg:
   232         w(u"not found: " + u(msg) + u"\n")
   231         w("not found: " + u(msg) + "\n")
   233         sys.exit(4)
   232         sys.exit(4)
   234     except LookupError as msg:
   233     except LookupError as msg:
   235         w(u"not found: " + u(msg) + u"\n")
   234         w("not found: " + u(msg) + "\n")
   236         sys.exit(4)
   235         sys.exit(4)
   237     except etree.XMLSyntaxError as e:
   236     except etree.XMLSyntaxError as e:
   238         log = e.error_log.filter_from_level(etree.ErrorLevels.FATAL)
   237         log = e.error_log.filter_from_level(etree.ErrorLevels.FATAL)
   239         for entry in log:
   238         for entry in log:
   240             w(u"XML error: " + u(entry.message) + u"\n")
   239             w("XML error: " + u(entry.message) + "\n")
   241         sys.exit(5)
   240         sys.exit(5)
   242     except Exception as msg:
   241     except Exception as msg:
   243         w(msg)
   242         w(msg)
   244         sys.exit(5)
   243         sys.exit(5)
   245 
   244