root/livinglogic.python.xist/src/ll/xist/scripts/dtd2xsc.py @ 4014:6aaa2efe668b

Revision 4014:6aaa2efe668b, 4.8 KB (checked in by Walter Doerwald <walter@…>, 9 years ago)

Change the parsing interface so that pipeline object don't know their input.

Instead the wiring of the pipeline is done by tree() or iterparse() (or the
new events() function).

Drop the old module global parse functions.

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
12"""
13Module that helps to create XIST namespace modules from DTDs. Needs xmlproc__
14
15__http://www.garshol.priv.no/download/software/xmlproc/
16
17For usage information type::
18
19    $ dtd2xsc --help
20
21"""
22
23
24__docformat__ = "reStructuredText"
25
26
27import sys, os.path, optparse
28
29try:
30    from xml.parsers.xmlproc import dtdparser
31except ImportError:
32    from xmlproc import dtdparser
33
34from ll import url
35from ll.xist import xsc, parsers, xnd
36
37
38__docformat__ = "reStructuredText"
39
40
41def getxmlns(dtd):
42    """
43    Extract the value of all fixed ``xmlns`` attributes
44    """
45    found = set()
46    for elemname in dtd.get_elements():
47        element = dtd.get_elem(elemname)
48        for attrname in element.get_attr_list():
49            attr = element.get_attr(attrname)
50            if attrname=="xmlns" or u":" in attrname:
51                if attr.decl=="#FIXED":
52                    found.add(attr.default)
53                    continue # skip a namespace declaration
54    return found
55
56
57def dtd2xnd(dtd, xmlns=None):
58    """
59    Convert DTD information from the URL :var:`dtdurl` to an XIST DOM using the
60    :mod:`ll.xist.xnd` functionality.
61    """
62
63    dtd = dtdparser.load_dtd_string(dtd)
64
65    ns = xnd.Module()
66
67    if xmlns is None:
68        # try to guess the namespace name from the dtd
69        xmlns = getxmlns(dtd)
70        if len(xmlns) == 1:
71            xmlns = iter(xmlns).next()
72        else:
73            xmlns = None
74
75    # Add element info
76    elements = dtd.get_elements()
77    elements.sort()
78    for elemname in elements:
79        dtd_e = dtd.get_elem(elemname)
80        e = xnd.Element(elemname, xmlns=xmlns)
81
82        # Add attribute info for this element
83        attrs = dtd_e.get_attr_list()
84        if len(attrs):
85            attrs.sort()
86            for attrname in attrs:
87                dtd_a = dtd_e.get_attr(attrname)
88                if attrname=="xmlns" or u":" in attrname:
89                    continue # skip namespace declarations and global attributes
90                values = []
91                if dtd_a.type == "ID":
92                    type = "xsc.IDAttr"
93                else:
94                    type = "xsc.TextAttr"
95                    if isinstance(dtd_a.type, list):
96                        if len(dtd_a.type)>1:
97                            values = dtd_a.type
98                        else:
99                            type = "xsc.BoolAttr"
100                default = dtd_a.default
101                if dtd_a.decl=="#REQUIRED":
102                    required = True
103                else:
104                    required = None
105                a = xnd.Attr(name=attrname, type=type, default=default, required=required)
106                for v in values:
107                    a.values.append(v)
108                e.attrs.append(a)
109        ns.content.append(e)
110
111    # Iterate through the elements a second time and add model information
112    for elemname in elements:
113        e = dtd.get_elem(elemname)
114        model = e.get_content_model()
115        if model is None:
116            modeltype = "sims.Any"
117            modelargs = None
118        elif model == ("", [], ""):
119            modeltype = "sims.Empty"
120            modelargs = None
121        else:
122            def extractcont(model):
123                if len(model) == 3:
124                    result = {}
125                    for cont in model[1]:
126                        result.update(extractcont(cont))
127                    return result
128                else:
129                    return {model[0]: None}
130            model = extractcont(model)
131            modeltype = "sims.Elements"
132            modelargs = []
133            for cont in model:
134                if cont == "#PCDATA":
135                    modeltype = "sims.ElementsOrText"
136                elif cont == "EMPTY":
137                    modeltype = "sims.Empty"
138                else:
139                    modelargs.append(ns.element(cont))
140            if not modelargs:
141                if modeltype == "sims.ElementsOrText":
142                    modeltype = "sims.NoElements"
143                else:
144                    modeltype = "sims.NoElementsOrText"
145        e = ns.element(elemname)
146        e.modeltype = modeltype
147        e.modelargs = modelargs
148
149    # Add entities
150    ents = dtd.get_general_entities()
151    ents.sort()
152    for entname in ents:
153        if entname not in ("quot", "apos", "gt", "lt", "amp"):
154            ent = parsers.tree(dtd.resolve_ge(entname).value, parsers.Encoder("utf-8"), parsers.SGMLOP(encoding="utf-8"), parsers.NS(), parsers.Instantiate())
155            ns.content.append(xnd.CharRef(entname, codepoint=ord(unicode(ent[0])[0])))
156
157    return ns
158
159
160def stream2xnd(stream, xmlns, shareattrs):
161    xnd = dtd2xnd(stream.read(), xmlns)
162
163    if shareattrs=="dupes":
164        xnd.shareattrs(False)
165    elif shareattrs=="all":
166        xnd.shareattrs(True)
167    return xnd
168
169
170def main(args=None):
171    p = optparse.OptionParser(usage="usage: %prog [options] <input.dtd >output_xmlns.py")
172    p.add_option("-x", "--xmlns", dest="xmlns", help="the namespace name for this module")
173    p.add_option("-s", "--shareattrs", dest="shareattrs", help="Should identical attributes be shared among elements?", choices=("none", "dupes", "all"), default="dupes")
174    p.add_option("-m", "--model", dest="model", default="once", help="Add sims information to the namespace", choices=("no", "all", "once"))
175    p.add_option("-d", "--defaults", action="store_true", dest="defaults", help="Output default values for attributes")
176
177    (options, args) = p.parse_args(args)
178    if len(args) != 0:
179        p.error("incorrect number of arguments")
180        return 1
181    print stream2xnd(sys.stdin, options.xmlns, options.shareattrs).aspy(model=options.model, defaults=options.defaults)
182
183
184if __name__ == "__main__":
185    sys.exit(main())
Note: See TracBrowser for help on using the browser.