root/livinglogic.python.xist/src/ll/xist/scripts/dtd2xsc.py @ 2989:b46e34472b05

Revision 2989:b46e34472b05, 4.4 KB (checked in by Walter Doerwald <walter@…>, 12 years ago)

Move xnd.fromdtd() to dtd2xsc script. Change script to work with stdin/stdout.

Line 
1#! /usr/bin/env python
2# -*- coding: utf-8 -*-
3
4## Copyright 1999-2007 by LivingLogic AG, Bayreuth/Germany.
5## Copyright 1999-2007 by Walter Dörwald
6##
7## All Rights Reserved
8##
9## See xist/__init__.py for the license
10
11
12"""
13<par>Module that helps to create &xist; namespace modules from &dtd;s.
14Needs <app>xmlproc</app> from the <app>PyXML</app> package.
15For usage information type:</par>
16<prog>
17dtd2xsc --help
18</prog>
19"""
20
21
22import sys, os.path, optparse
23
24from xml.parsers.xmlproc import dtdparser
25
26from ll import url
27from ll.xist import xsc, parsers, xnd
28
29
30def dtd2xnd(dtd, xmlns=None):
31    """
32    Convert &dtd; information from the &url; <arg>dtdurl</arg> to an &xist; &dom;
33    using the <pyref module="ll.xist.xnd"><module>xnd</module></pyref> functionality.
34    """
35
36    dtd = dtdparser.load_dtd_string(dtd)
37
38    ns = xnd.Module()
39
40    foundxmlns = set() # collects all the values of fixed xmlns attributes
41
42    # Add element info
43    elements = dtd.get_elements()
44    elements.sort()
45    for elemname in elements:
46        dtd_e = dtd.get_elem(elemname)
47        e = xnd.Element(elemname, xmlns=xmlns)
48
49        # Add attribute info for this element
50        attrs = dtd_e.get_attr_list()
51        if len(attrs):
52            attrs.sort()
53            for attrname in attrs:
54                dtd_a = dtd_e.get_attr(attrname)
55                if attrname=="xmlns":
56                    if dtd_a.decl=="#FIXED":
57                        foundxmlns.add(dtd_a.default)
58                    continue # skip a namespace declaration
59                elif u":" in attrname:
60                    continue # skip global attributes
61                values = []
62                if dtd_a.type == "ID":
63                    type = "xsc.IDAttr"
64                else:
65                    type = "xsc.TextAttr"
66                    if isinstance(dtd_a.type, list):
67                        if len(dtd_a.type)>1:
68                            values = dtd_a.type
69                        else:
70                            type = "xsc.BoolAttr"
71                default = dtd_a.default
72                if dtd_a.decl=="#REQUIRED":
73                    required = True
74                else:
75                    required = None
76                a = xnd.Attr(name=attrname, type=type, default=default, required=required)
77                for v in values:
78                    a.values.append(v)
79                e.attrs.append(a)
80        ns.content.append(e)
81
82    # Iterate through the elements a second time and add model information
83    for elemname in elements:
84        e = dtd.get_elem(elemname)
85        model = e.get_content_model()
86        if model is None:
87            modeltype = "sims.Any"
88            modelargs = None
89        elif model == ("", [], ""):
90            modeltype = "sims.Empty"
91            modelargs = None
92        else:
93            def extractcont(model):
94                if len(model) == 3:
95                    result = {}
96                    for cont in model[1]:
97                        result.update(extractcont(cont))
98                    return result
99                else:
100                    return {model[0]: None}
101            model = extractcont(model)
102            modeltype = "sims.Elements"
103            modelargs = []
104            for cont in model:
105                if cont == "#PCDATA":
106                    modeltype = "sims.ElementsOrText"
107                elif cont == "EMPTY":
108                    modeltype = "sims.Empty"
109                else:
110                    modelargs.append(ns.element(cont))
111            if not modelargs:
112                if modeltype == "sims.ElementsOrText":
113                    modeltype = "sims.NoElements"
114                else:
115                    modeltype = "sims.NoElementsOrText"
116        e = ns.element(elemname)
117        e.modeltype = modeltype
118        e.modelargs = modelargs
119
120    # Add entities
121    ents = dtd.get_general_entities()
122    ents.sort()
123    for entname in ents:
124        if entname not in ("quot", "apos", "gt", "lt", "amp"):
125            ent = parsers.parsestring(dtd.resolve_ge(entname).value)
126            ns.content.append(xnd.CharRef(entname, codepoint=ord(unicode(ent[0])[0])))
127
128    # if the DTD has exactly one value for all fixed "xmlns" attributes and the user didn't specify xmlns, use this one
129    if xmlns is None and len(foundxmlns)==1:
130        ns.xmlns = foundxmlns.pop()
131    return ns
132
133
134def stream2xnd(stream, xmlns, shareattrs):
135    xnd = dtd2xnd(stream.read(), xmlns)
136
137    if shareattrs=="dupes":
138        xnd.shareattrs(False)
139    elif shareattrs=="all":
140        xnd.shareattrs(True)
141    return xnd
142
143
144def main():
145    p = optparse.OptionParser(usage="usage: %prog [options] <input.dtd >output_xmlns.py")
146    p.add_option("-x", "--xmlns", dest="xmlns", help="the namespace name for this module")
147    p.add_option("-s", "--shareattrs", dest="shareattrs", help="Should identical attributes be shared among elements?", choices=("none", "dupes", "all"), default="dupes")
148    p.add_option("-m", "--model", dest="model", default="once", help="Add sims information to the namespace", choices=("no", "all", "once"))
149    p.add_option("-d", "--defaults", action="store_true", dest="defaults", help="Output default values for attributes")
150
151    (options, args) = p.parse_args()
152    if len(args) != 0:
153        p.error("incorrect number of arguments")
154        return 1
155    print stream2xnd(sys.stdin, options.xmlns, options.shareattrs).aspy(model=options.model, defaults=options.defaults)
156
157
158if __name__ == "__main__":
159    sys.exit(main())
Note: See TracBrowser for help on using the browser.