root/livinglogic.python.xist/src/ll/xist/scripts/xml2xsc.py @ 4278:56852276638d

Revision 4278:56852276638d, 3.7 KB (checked in by Walter Doerwald <walter@…>, 9 years ago)

Enhance dtd2xsc so that it can put the content of more than one DTD into a xnd definition.

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4## Copyright 1999-2010 by LivingLogic AG, Bayreuth/Germany
5## Copyright 1999-2010 by Walter Dörwald
6##
7## All Rights Reserved
8##
9## See ll/__init__.py for the license
10
11
12import sys, argparse
13
14from ll.xist import xsc, xnd, sims
15
16
17__docformat__ = "reStructuredText"
18
19
20def iterpath(node):
21    yield [node]
22    if hasattr(node, "text") and node.text:
23        yield [node, node.text]
24    if hasattr(node, "getchildren"):
25        for child in node:
26            for path in iterpath(child):
27                yield [node] + path
28    if hasattr(node, "tail") and node.tail:
29        yield [node, node.tail]
30
31
32def getelementname(node):
33    xmlns = None
34    name = node.tag
35    if name.startswith("{"):
36        (xmlns, sep, name) = name[1:].partition("}")
37    return (name, xmlns)
38
39
40def 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
45    # Iterate through the tree and collect which elements are encountered and how they are nested
46    for path in iterpath(node):
47        node = path[-1]
48        if "Element" in type(node).__name__:
49            (name, xmlns) = getelementname(node)
50            try:
51                entry = elements[(name, xmlns)]
52            except KeyError:
53                xndnode = xnd.Element(name, xmlns=xmlns)
54                entry = elements[(name, xmlns)] = (xndnode, set())
55                ns(xndnode)
56            else:
57                xndnode = entry[0]
58            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))
61        elif "ProcessingInstruction" in type(node).__name__:
62            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)
70        elif "Comment" in type(node).__name__:
71            xndnode = "#comment"
72        elif isinstance(node, basestring):
73            if node.isspace():
74                xndnode = "#whitespace"
75            else:
76                xndnode = "#text"
77        if len(path) >= 2:
78            parent = path[-2]
79            if "Element" in type(parent).__name__:
80                parententry = elements[getelementname(parent)]
81                parententry[1].add(xndnode)
82
83    # Put sims info into the element definitions
84    if model == "none":
85        pass
86    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"
93            else:
94                elements = [el for el in entry[1] if isinstance(el, xnd.Element)]
95                if not elements:
96                    if "#text" in entry[1]:
97                        entry[0].modeltype = "sims.NoElements"
98                    else:
99                        entry[0].modeltype = "sims.NoElementsOrText"
100                else:
101                    if "#text" in entry[1]:
102                        entry[0].modeltype = "sims.ElementsOrText"
103                    else:
104                        entry[0].modeltype = "sims.Elements"
105                    entry[0].modelargs = elements
106    else:
107        raise ValueError("unknown sims mode {!r}".format(model))
108    return ns
109
110
111def 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
124def 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")
128
129    args = p.parse_args(args)
130    print stream2xnd(sys.stdin, model=args.model, parser=args.parser).aspy()
131
132
133if __name__ == "__main__":
134    sys.exit(main())
Note: See TracBrowser for help on using the browser.