Changeset 4289:e40f5dc756bf in livinglogic.python.xist for src/ll/xist/scripts/xml2xsc.py

Show
Ignore:
Timestamp:
01/20/11 17:23:12 (9 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Enhance xml2xsc.py so it can read multiple XML files.

xnd genating function can now read source from URLs, strings and streams.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • src/ll/xist/scripts/xml2xsc.py

    r4278 r4289  
    1010 
    1111 
    12 import sys, argparse 
     12import sys, argparse, cStringIO 
    1313 
     14from ll import misc, url 
    1415from ll.xist import xsc, xnd, sims 
    1516 
     
    3839 
    3940 
    40 def etree2xnd(model, node): 
    41     ns = xnd.Module() 
    42     elements = {} # maps (name, xmlns) to (xnd.Element, content set) 
    43     procinsts = {} # maps name to xnd.ProcInst 
    44  
     41def addetree2xnd(ns, node, elements): 
    4542    # Iterate through the tree and collect which elements are encountered and how they are nested 
    4643    for path in iterpath(node): 
     
    4845        if "Element" in type(node).__name__: 
    4946            (name, xmlns) = getelementname(node) 
    50             try: 
    51                 entry = elements[(name, xmlns)] 
    52             except KeyError: 
     47            if (name, xmlns) in ns.elements: 
     48                xndnode = ns.elements[(name, xmlns)] 
     49            else: 
    5350                xndnode = xnd.Element(name, xmlns=xmlns) 
    54                 entry = elements[(name, xmlns)] = (xndnode, set()) 
    55                 ns(xndnode) 
    56             else: 
    57                 xndnode = entry[0] 
     51                xndnode.add(ns) 
     52                elements[(name, xmlns)] = set() 
    5853            for attrname in node.keys(): 
    59                 if not attrname.startswith("{") and attrname not in entry[0].attrs: 
    60                     entry[0](xnd.Attr(attrname, type=xsc.TextAttr)) 
     54                if not attrname.startswith("{") and attrname not in xndnode.attrs: 
     55                    xndnode(xnd.Attr(attrname, type=xsc.TextAttr)) 
    6156        elif "ProcessingInstruction" in type(node).__name__: 
    6257            name = node.target 
    63             try: 
    64                 xndnode = procinsts[name] 
    65             except KeyError: 
    66                 procinst = xnd.ProcInst(name) 
    67                 procinsts[name] = procinst 
    68                 xndnode = procinst 
    69             ns(xndnode) 
     58            if name not in ns.procinsts: 
     59                xndnode = xnd.ProcInst(name) 
     60                xndnode.add(ns) 
    7061        elif "Comment" in type(node).__name__: 
    7162            xndnode = "#comment" 
     
    7970            if "Element" in type(parent).__name__: 
    8071                parententry = elements[getelementname(parent)] 
    81                 parententry[1].add(xndnode) 
     72                parententry.add(xndnode) 
     73 
     74 
     75def makexnd(streams, parser="etree", shareattrs="dupes", model="simple"): 
     76    elements = {} # maps (name, xmlns) to content set 
     77    ns = xnd.Module() 
     78    with url.Context(): 
     79        for stream in streams: 
     80            if isinstance(stream, url.URL): 
     81                stream = stream.openread() 
     82            elif isinstance(stream, str): 
     83                stream = cStringIO.StringIO(stream) 
     84            if parser == "etree": 
     85                from xml.etree import cElementTree 
     86                node = cElementTree.parse(stream).getroot() 
     87            elif parser == "lxml": 
     88                from lxml import etree 
     89                node = etree.parse(stream).getroot() 
     90            else: 
     91                raise ValueError("unknown parser {!r}".format(parser)) 
     92            stream.close() 
     93            addetree2xnd(ns, node, elements) 
    8294 
    8395    # Put sims info into the element definitions 
     
    8597        pass 
    8698    elif model == "simple": 
    87         for entry in elements.itervalues(): 
    88             entry[0].modeltype = bool(entry[1]) 
    89     elif model == "full": 
    90         for entry in elements.itervalues(): 
    91             if not entry[1]: 
    92                 entry[0].modeltype = "sims.Empty" 
     99        for (fullname, modelset) in elements.iteritems(): 
     100            ns.elements[fullname].modeltype = bool(modelset) 
     101    elif model in ("fullall", "fullonce"): 
     102        for (fullname, modelset) in elements.iteritems(): 
     103            element = ns.elements[fullname] 
     104            if not modelset: 
     105                element.modeltype = "sims.Empty" 
    93106            else: 
    94                 elements = [el for el in entry[1] if isinstance(el, xnd.Element)] 
     107                elements = [el for el in modelset if isinstance(el, xnd.Element)] 
    95108                if not elements: 
    96                     if "#text" in entry[1]: 
    97                         entry[0].modeltype = "sims.NoElements" 
     109                    if "#text" in modelset: 
     110                        element.modeltype = "sims.NoElements" 
    98111                    else: 
    99                         entry[0].modeltype = "sims.NoElementsOrText" 
     112                        element.modeltype = "sims.NoElementsOrText" 
    100113                else: 
    101                     if "#text" in entry[1]: 
    102                         entry[0].modeltype = "sims.ElementsOrText" 
     114                    if "#text" in modelset: 
     115                        element.modeltype = "sims.ElementsOrText" 
    103116                    else: 
    104                         entry[0].modeltype = "sims.Elements" 
    105                     entry[0].modelargs = elements 
     117                        element.modeltype = "sims.Elements" 
     118                    element.modelargs = elements 
    106119    else: 
    107120        raise ValueError("unknown sims mode {!r}".format(model)) 
     121 
     122    if shareattrs=="dupes": 
     123        ns.shareattrs(False) 
     124    elif shareattrs=="all": 
     125        ns.shareattrs(True) 
    108126    return ns 
    109127 
    110128 
    111 def stream2xnd(stream, model="simple", parser="etree"): 
    112     if parser == "etree": 
    113         from xml.etree import cElementTree 
    114         node = cElementTree.parse(stream).getroot() 
    115     elif parser == "lxml": 
    116         from lxml import etree 
    117         node = etree.parse(stream).getroot() 
    118     else: 
    119         raise ValueError("unknown parser {!r}".format(parser)) 
    120  
    121     return etree2xnd(model, node) 
    122  
    123  
    124129def main(args=None): 
    125     p = argparse.ArgumentParser(description="Convert XML (on stdin) to XIST namespace (on stdout)") 
    126     p.add_argument("-p", "--parser", dest="parser", help="parser module to use for XML parsing (etree or lxml)", choices=("etree", "lxml"), default="etree") 
    127     p.add_argument("-m", "--model", dest="model", help="Create sims info?", choices=("none", "simple", "full"), default="simple") 
     130    p = argparse.ArgumentParser(description="Convert XML files to XIST namespace (on stdout)") 
     131    p.add_argument("urls", metavar="urls", type=url.URL, help="ULRs of DTDs to be parsed", nargs="+") 
     132    p.add_argument("-p", "--parser", dest="parser", help="parser module to use for XML parsing (default: %(default)s)", choices=("etree", "lxml"), default="etree") 
     133    p.add_argument("-s", "--shareattrs", dest="shareattrs", help="Should identical attributes be shared among elements? (default: %(default)s)", choices=("none", "dupes", "all"), default="dupes") 
     134    p.add_argument("-m", "--model", dest="model", help="Create sims info? (default: %(default)s)", choices=("none", "simple", "fullall", "fullonce"), default="simple") 
    128135 
    129136    args = p.parse_args(args) 
    130     print stream2xnd(sys.stdin, model=args.model, parser=args.parser).aspy() 
     137    print makexnd(args.urls, parser=args.parser, shareattrs=args.shareattrs, model=args.model).aspy(model=args.model) 
    131138 
    132139