root/livinglogic.python.xist/src/ll/xist/scripts/xml2xsc.py @ 4422:fe09ca906d4e

Revision 4422:fe09ca906d4e, 4.3 KB (checked in by Walter Doerwald <walter@…>, 8 years ago)

Bump copyright year. Change encoding of remaining files to UTF-8. Remove trailing whitespace.

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4## Copyright 1999-2011 by LivingLogic AG, Bayreuth/Germany
5## Copyright 1999-2011 by Walter Dörwald
6##
7## All Rights Reserved
8##
9## See ll/__init__.py for the license
10
11
12import sys, argparse, cStringIO
13
14from ll import misc, url
15from ll.xist import xsc, xnd, sims
16
17
18__docformat__ = "reStructuredText"
19
20
21def iterpath(node):
22    yield [node]
23    if hasattr(node, "text") and node.text:
24        yield [node, node.text]
25    if hasattr(node, "getchildren"):
26        for child in node:
27            for path in iterpath(child):
28                yield [node] + path
29    if hasattr(node, "tail") and node.tail:
30        yield [node, node.tail]
31
32
33def getelementname(node):
34    xmlns = None
35    name = node.tag
36    if name.startswith("{"):
37        (xmlns, sep, name) = name[1:].partition("}")
38    return (name, xmlns)
39
40
41def addetree2xnd(ns, node, elements):
42    # Iterate through the tree and collect which elements are encountered and how they are nested
43    for path in iterpath(node):
44        node = path[-1]
45        if "Element" in type(node).__name__:
46            (name, xmlns) = getelementname(node)
47            if (name, xmlns) in ns.elements:
48                xndnode = ns.elements[(name, xmlns)]
49            else:
50                xndnode = xnd.Element(name, xmlns=xmlns)
51                ns += xndnode
52                elements[(name, xmlns)] = set()
53            for attrname in node.keys():
54                if not attrname.startswith("{") and attrname not in xndnode.attrs:
55                    xndnode += xnd.Attr(attrname, type=xsc.TextAttr)
56        elif "ProcessingInstruction" in type(node).__name__:
57            name = node.target
58            if name not in ns.procinsts:
59                ns += xnd.ProcInst(name)
60        elif "Comment" in type(node).__name__:
61            xndnode = "#comment"
62        elif isinstance(node, basestring):
63            if node.isspace():
64                xndnode = "#whitespace"
65            else:
66                xndnode = "#text"
67        if len(path) >= 2:
68            parent = path[-2]
69            if "Element" in type(parent).__name__:
70                parententry = elements[getelementname(parent)]
71                parententry.add(xndnode)
72
73
74def makexnd(urls, parser="etree", shareattrs="dupes", model="simple", defaultxmlns=None):
75    elements = {} # maps (name, xmlns) to content set
76    ns = xnd.Module(defaultxmlns=defaultxmlns)
77    with url.Context():
78        for u in urls:
79            if isinstance(u, url.URL):
80                u = u.openread()
81            elif isinstance(u, str):
82                u = cStringIO.StringIO(u)
83            if parser == "etree":
84                from xml.etree import cElementTree
85                node = cElementTree.parse(u).getroot()
86            elif parser == "lxml":
87                from lxml import etree
88                node = etree.parse(u).getroot()
89            else:
90                raise ValueError("unknown parser {!r}".format(parser))
91            addetree2xnd(ns, node, elements)
92
93    # Put sims info into the element definitions
94    if model == "none":
95        pass
96    elif model == "simple":
97        for (fullname, modelset) in elements.iteritems():
98            ns.elements[fullname].modeltype = bool(modelset)
99    elif model in ("fullall", "fullonce"):
100        for (fullname, modelset) in elements.iteritems():
101            element = ns.elements[fullname]
102            if not modelset:
103                element.modeltype = "sims.Empty"
104            else:
105                elements = [el for el in modelset if isinstance(el, xnd.Element)]
106                if not elements:
107                    if "#text" in modelset:
108                        element.modeltype = "sims.NoElements"
109                    else:
110                        element.modeltype = "sims.NoElementsOrText"
111                else:
112                    if "#text" in modelset:
113                        element.modeltype = "sims.ElementsOrText"
114                    else:
115                        element.modeltype = "sims.Elements"
116                    element.modelargs = elements
117    else:
118        raise ValueError("unknown sims mode {!r}".format(model))
119
120    if shareattrs=="dupes":
121        ns.shareattrs(False)
122    elif shareattrs=="all":
123        ns.shareattrs(True)
124    return ns
125
126
127def main(args=None):
128    p = argparse.ArgumentParser(description="Convert XML files to XIST namespace (on stdout)")
129    p.add_argument("urls", metavar="urls", type=url.URL, help="ULRs of DTDs to be parsed", nargs="+")
130    p.add_argument("-p", "--parser", dest="parser", help="parser module to use for XML parsing (default: %(default)s)", choices=("etree", "lxml"), default="etree")
131    p.add_argument("-s", "--shareattrs", dest="shareattrs", help="Should identical attributes be shared among elements? (default: %(default)s)", choices=("none", "dupes", "all"), default="dupes")
132    p.add_argument("-m", "--model", dest="model", help="Create sims info? (default: %(default)s)", choices=("none", "simple", "fullall", "fullonce"), default="simple")
133    p.add_argument("-x", "--defaultxmlns", dest="defaultxmlns", metavar="NAME", help="Force elements without a namespace into this namespace")
134
135    args = p.parse_args(args)
136    print makexnd(**args.__dict__)
137
138
139if __name__ == "__main__":
140    sys.exit(main())
Note: See TracBrowser for help on using the browser.