yml2/yml2proc.py
changeset 62 00a196f8d14a
parent 60 b19d0a86651b
child 67 db1b6e9a6bb7
equal deleted inserted replaced
61:482106d33bf6 62:00a196f8d14a
     1 #!/usr/bin/env python3
     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 6.2
     5 YML/YSLT 2 processor version 6.2
     6 Copyleft (c), 2009-2019 Volker Birk  http://fdik.org/yml/
     6 Copyleft (c), 2009-2020 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
    20 if __name__ == "__main__":
    20 if __name__ == "__main__":
    21     sys.path.insert(0, os.path.dirname(__file__))
    21     sys.path.insert(0, os.path.dirname(__file__))
    22 
    22 
    23 from yml2.yml2 import ymlCStyle, comment, oldSyntax
    23 from yml2.yml2 import ymlCStyle, comment, oldSyntax
    24 from yml2.pyPEG import parse, u
    24 from yml2.pyPEG import parse, u
    25 from yml2 import backend
    25 import yml2.backend as backend
       
    26 
       
    27 YML_DEFAULT_PATH = [os.path.dirname(backend.__file__)]
    26 
    28 
    27 def printInfo(option, opt_str, value, parser):
    29 def printInfo(option, opt_str, value, parser):
    28     sys.stdout.write(__doc__)
    30     sys.stdout.write(__doc__)
    29     sys.exit(0)
    31     sys.exit(0)
    30 
    32 
    76             help="execute YSLT script YSLTSCRIPT")
    78             help="execute YSLT script YSLTSCRIPT")
    77     optParser.add_option("-Y", "--xml2yml", action="store_true", default=False,
    79     optParser.add_option("-Y", "--xml2yml", action="store_true", default=False,
    78             help="convert XML to normalized YML code")
    80             help="convert XML to normalized YML code")
    79     optParser.add_option("-V", "--version", action="callback", callback=printInfo, help="show version info and exit")
    81     optParser.add_option("-V", "--version", action="callback", callback=printInfo, help="show version info and exit")
    80     (options, args) = optParser.parse_args()
    82     (options, args) = optParser.parse_args()
    81     
    83 
    82     if options.old_syntax:
    84     if options.old_syntax:
    83         oldSyntax()
    85         oldSyntax()
    84     
    86 
    85     if options.trace:
    87     if options.trace:
    86         backend.enable_tracing = True
    88         backend.enable_tracing = True
    87     
    89 
    88     if options.emitlinenumbers:
    90     if options.emitlinenumbers:
    89         backend.emitlinenumbers = True
    91         backend.emitlinenumbers = True
    90     
    92 
    91     if options.includePathText:
    93     if options.includePathText:
    92         backend.includePath = options.includePathText.split(':')
    94         backend.includePath = options.includePathText.split(':')
    93     
    95 
    94     backend.encoding = options.encoding
    96     backend.encoding = options.encoding
    95     
    97 
    96     dirs = os.environ.get('YML_PATH', '.').split(':')
    98     dirs = os.environ.get('YML_PATH', '.').split(':') + YML_DEFAULT_PATH
    97     backend.includePath.extend(dirs)
    99     backend.includePath.extend(dirs)
    98     
   100 
    99     if options.xml2yml:
   101     if options.xml2yml:
   100         for directory in backend.includePath:
   102         for directory in backend.includePath:
   101             try:
   103             name = os.path.join(directory, "xml2yml.ysl2")
   102                 name = directory + "/xml2yml.ysl2"
   104             if os.path.isfile(name):
   103                 f = open(name, "r")
   105                 options.yslt = name
   104                 f.close()
   106                 options.xml = True
   105                 break
   107                 break
   106             except:
   108         else:
   107                 pass
   109             sys.stderr.write("Error: Stylesheet xml2yml.ysl2 required for --xml2yml not found\n")
   108     
   110             sys.stderr.write("Please check your YML_PATH\n")
   109         options.yslt = name
   111             sys.exit(1)
   110         options.xml = True
   112 
   111     
       
   112     if  (options.xslt and options.yslt) or (options.xslt and options.xpath) or (options.yslt and options.xpath):
   113     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")
   114         sys.stderr.write("Cannot combine --xpath, --xslt and --yslt params\n")
   114         sys.exit(1)
   115         sys.exit(1)
   115     
   116 
   116     try:
   117     try:
   117         ymlC = ymlCStyle()
   118         ymlC = ymlCStyle()
   118     
   119 
   119         rtext = ""
   120         rtext = ""
   120     
   121 
   121         if not options.emptyinput:
   122         if not options.emptyinput:
   122             files = fileinput.input(args, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   123             files = fileinput.input(args, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   123     
   124 
   124             if options.xml:
   125             if options.xml:
   125                 rtext = ""
   126                 rtext = ""
   126                 for line in files:
   127                 for line in files:
   127                     rtext += line
   128                     rtext += line
   128             else:
   129             else:
   130                 if options.parseonly:
   131                 if options.parseonly:
   131                     print(result)
   132                     print(result)
   132                     sys.exit(0)
   133                     sys.exit(0)
   133                 else:
   134                 else:
   134                     rtext = backend.finish(result)
   135                     rtext = backend.finish(result)
   135     
   136 
   136         if not rtext:
   137         if not rtext:
   137             rtext = "<empty/>"
   138             rtext = "<empty/>"
   138     
   139 
   139         def ymldebug(context, text):
   140         def ymldebug(context, text):
   140             if options.trace:
   141             if options.trace:
   141                 sys.stderr.write("Debug: " + codecs.encode(u(text), options.encoding) + "\n")
   142                 sys.stderr.write("Debug: " + codecs.encode(u(text), options.encoding) + "\n")
   142             return ""
   143             return ""
   143     
   144 
   144         def ymlassert(context, value, msg):
   145         def ymlassert(context, value, msg):
   145             if options.trace:
   146             if options.trace:
   146                 if not value:
   147                 if not value:
   147                     raise YMLAssert(msg)
   148                     raise YMLAssert(msg)
   148             return ""
   149             return ""
   149     
   150 
   150         ymlns = etree.FunctionNamespace("http://fdik.org/yml")
   151         ymlns = etree.FunctionNamespace("http://fdik.org/yml")
   151         ymlns.prefix = "yml"
   152         ymlns.prefix = "yml"
   152         ymlns['debug'] = ymldebug
   153         ymlns['debug'] = ymldebug
   153         ymlns['assert'] = ymlassert
   154         ymlns['assert'] = ymlassert
   154     
   155 
   155         if options.xpath:
   156         if options.xpath:
   156             tree = etree.fromstring(rtext)
   157             tree = etree.fromstring(rtext)
   157             ltree = tree.xpath(codecs.decode(options.xpath, options.encoding))
   158             ltree = tree.xpath(codecs.decode(options.xpath, options.encoding))
   158             rtext = ""
   159             rtext = ""
   159             try:
   160             try:
   160                 for rtree in ltree:
   161                 for rtree in ltree:
   161                     rtext += etree.tostring(rtree, pretty_print=options.pretty, encoding=unicode)
   162                     rtext += etree.tostring(rtree, pretty_print=options.pretty, encoding=unicode)
   162             except:
   163             except:
   163                 rtext = ltree
   164                 rtext = ltree
   164     
   165 
   165         elif options.yslt or options.xslt:
   166         elif options.yslt or options.xslt:
   166             params = {}
   167             params = {}
   167     
   168 
   168             if options.yslt:
   169             if options.yslt:
   169                 backend.clearAll()
   170                 backend.clearAll()
   170                 yscript = fileinput.input(options.yslt, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   171                 yscript = fileinput.input(options.yslt, mode="rU", openhook=fileinput.hook_encoded(options.encoding))
   171                 yresult = parse(ymlC, yscript, True, comment)
   172                 yresult = parse(ymlC, yscript, True, comment)
   172                 ytext = backend.finish(yresult)
   173                 ytext = backend.finish(yresult)
   173             else:
   174             else:
   174                 yscript = fileinput.input(options.xslt, mode="rU")
   175                 yscript = fileinput.input(options.xslt, mode="rU")
   175                 ytext = ""
   176                 ytext = ""
   176                 for line in yscript:
   177                 for line in yscript:
   177                     ytext += line
   178                     ytext += line
   178     
   179 
   179             doc = etree.fromstring(rtext)
   180             doc = etree.fromstring(rtext)
   180     
   181 
   181             xsltree = etree.XML(ytext, base_url=os.path.abspath(yscript.filename()))
   182             xsltree = etree.XML(ytext, base_url=os.path.abspath(yscript.filename()))
   182             transform = etree.XSLT(xsltree)
   183             transform = etree.XSLT(xsltree)
   183             
   184             
   184             if options.params:
   185             if options.params:
   185                 params = eval(options.params)
   186                 params = eval(options.params)
   187                     if type(value) is not str:
   188                     if type(value) is not str:
   188                         params[key] = u(value)
   189                         params[key] = u(value)
   189             if options.stringparams:
   190             if options.stringparams:
   190                 for key, value in eval(options.stringparams).iteritems():
   191                 for key, value in eval(options.stringparams).iteritems():
   191                     params[key] = "'" + u(value) + "'"
   192                     params[key] = "'" + u(value) + "'"
   192     
   193 
   193             rresult = transform(doc, **params)
   194             rresult = transform(doc, **params)
   194             # lxml is somewhat buggy
   195             # lxml is somewhat buggy
   195             try:
   196             try:
   196                 rtext = u(rresult)
   197                 rtext = u(rresult)
   197             except:
   198             except:
   198                 rtext = etree.tostring(rresult, encoding=unicode)
   199                 rtext = etree.tostring(rresult, encoding=unicode)
   199                 if not rtext:
   200                 if not rtext:
   200                     rtext = codecs.decode(str(rresult), "utf-8")
   201                     rtext = codecs.decode(str(rresult), "utf-8")
   201     
   202 
   202         if options.normalization != "none":
   203         if options.normalization != "none":
   203             rtext = unicodedata.normalize(options.normalization, rtext)
   204             rtext = unicodedata.normalize(options.normalization, rtext)
   204     
   205 
   205         if options.pretty:
   206         if options.pretty:
   206             plaintext = etree.tostring(etree.fromstring(rtext), pretty_print=True, xml_declaration=True, encoding=options.encoding)
   207             plaintext = etree.tostring(etree.fromstring(rtext), pretty_print=True, xml_declaration=True, encoding=options.encoding)
   207         else:
   208         else:
   208             if isinstance(rtext, str):
   209             if isinstance(rtext, str):
   209                 plaintext = codecs.encode(rtext, options.encoding)
   210                 plaintext = codecs.encode(rtext, options.encoding)
   210             else:
   211             else:
   211                 plaintext = rtext
   212                 plaintext = rtext
   212     
   213 
   213         try:
   214         try:
   214             if plaintext[-1] == "\n":
   215             if plaintext[-1] == "\n":
   215                 plaintext = plaintext[:-1]
   216                 plaintext = plaintext[:-1]
   216         except: pass
   217         except: pass
   217     
   218 
   218         if options.outputFile and options.outputFile != "-":
   219         if options.outputFile and options.outputFile != "-":
   219             outfile = open(options.outputFile, "wb")
   220             outfile = open(options.outputFile, "wb")
   220             outfile.write(plaintext)
   221             outfile.write(plaintext)
   221             outfile.close()
   222             outfile.close()
   222         else:
   223         else:
   223             sys.stdout.buffer.write(plaintext)
   224             sys.stdout.buffer.write(plaintext)
   224             if not options.pretty:
   225             if not options.pretty:
   225                 print()
   226                 print()
   226     
   227 
   227     except KeyboardInterrupt:
   228     except KeyboardInterrupt:
   228         w("\n")
   229         w("\n")
   229         sys.exit(1)
   230         sys.exit(1)
   230     except YMLAssert as msg:
   231     except YMLAssert as msg:
   231         w("YML Assertion failed: " + u(msg) + "\n")
   232         w("YML Assertion failed: " + u(msg) + "\n")
   246         sys.exit(5)
   247         sys.exit(5)
   247 
   248 
   248 
   249 
   249 if __name__ == "__main__":
   250 if __name__ == "__main__":
   250     sys.exit(main())
   251     sys.exit(main())
       
   252