summaryrefslogtreecommitdiffstats
path: root/lib/jython/Lib/xml/dom/html/GenerateHtml.py
blob: 07ea1fc90251bc90d433f41027cb88de0073837d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#!/usr/bin/env python
import string, os, sys
try:
    from xml.dom import Node
    from xml.dom.ext.reader import Sax
    Reader = Sax.FromXmlFile
except ImportError:
    print 'You need to have PyXML installed to run this program'
    sys.exit(1)


def Generate(fileName,
             output_dir=None,
             program_name=None
             ):
    output_dir = output_dir or '.'

    dom = Reader(fileName)

    header = CreateHeader(dom, program_name)
    classes = dom.getElementsByTagName('class')
    outfiles = []
    for klass in classes:
        outfiles.append(GenClassFile(klass, header, output_dir))
    return outfiles


def CreateHeader(dom, prog_name):
    result = ''
    header = dom.getElementsByTagName('header')
    if header:
        result = result + string.strip(header[0].childNodes[0].data)
        result = result + '\n\n'

    if prog_name:
        add_str = ' by ' + prog_name
    else:
        add_str = ''
    result = result + '### This file is automatically generated%s.\n' % add_str

    result = result + '### DO NOT EDIT!\n\n'

    copyright = dom.getElementsByTagName('copyright')
    if copyright:
        result = result + '"""\n'
        result = result + string.strip(copyright[0].childNodes[0].data) + '\n'
        result = result + '"""\n\n'

    return result

# Helper function for indenting Python
def indent(count, text, tab=' '*4):
    return tab*count + text

# Get/Set routines for DOMString attributes
def stringGetAttr(name, value):
    return indent(2, 'return self.getAttribute("%s")\n\n' % name)

def stringSetAttr(name):
    return indent(2, 'self.setAttribute("%s", value)\n\n' % name)

# Routines for boolean attributes
def boolGetAttr(name, value):
    return indent(2, 'return self.hasAttribute("%s")\n\n' % name)

def boolSetAttr(name):
    result =          indent(2, 'if value:\n')
    result = result + indent(3,   'self.setAttribute("%s", "%s")\n' % (name, name))
    result = result + indent(2, 'else:\n')
    result = result + indent(3,   'self.removeAttribute("%s")\n\n' % name)
    return result

# Routines for number attributes
def longGetAttr(name, value):
    result =          indent(2, 'value = self.getAttribute("%s")\n' % name)
    result = result + indent(2, 'if value:\n')
    result = result + indent(3,   'return int(value)\n')
    result = result + indent(2, 'return 0\n\n')
    return result

def longSetAttr(name):
    return indent(2, 'self.setAttribute("%s", str(value))\n\n' % name)

# Routines for value-list attributes
def listGetAttr(name, value):
    return indent(2, 'return string.capitalize(self.getAttribute("%s"))\n\n' % name)

# Routines for attributes mapped to Text nodes
def nodeGetAttr(dummy, value):
    result =          indent(2, 'if not self.firstChild:\n')
    result = result + indent(3,   'return ''\n')
    result = result + indent(2, 'if self.firstChild == self.lastChild:\n')
    result = result + indent(3,   'return self.firstChild.data\n')
    result = result + indent(2, 'self.normalize()\n')
    result = result + indent(2, 'text = filter(lambda x: x.nodeType == Node.TEXT_NODE, self.childNodes)\n')
    result = result + indent(2, 'return text[0].data\n\n')
    return result

def nodeSetAttr(dummy):
    result =          indent(2, 'text = None\n')
    result = result + indent(2, 'for node in self.childNodes:\n')
    result = result + indent(3,   'if not text and node.nodeType == Node.TEXT_NODE:\n')
    result = result + indent(4,     'text = node\n')
    result = result + indent(3,   'else:\n')
    result = result + indent(4,     'self.removeChild(node)\n')
    result = result + indent(2, 'if text:\n')
    result = result + indent(3,   'text.data = value\n')
    result = result + indent(2, 'else:\n')
    result = result + indent(3,   'text = self.ownerDocument.createTextNode(value)\n')
    result = result + indent(3,   'self.appendChild(text)\n\n')
    return result

#Routines for constant attributes
def constGetAttr(name, value):
    if not value:
        value = 'None'
    else:
        value = '"%s"' % value
    return indent(2, 'return %s\n\n' % value)

#Routines for form based classes
def formGetAttr(dummy,dummy2):
    result =          indent(2, 'parent = self.parentNode\n')
    result = result + indent(2, 'while parent:\n')
    result = result + indent(3,   'if parent.nodeName == "FORM":\n')
    result = result + indent(4,     'return parent\n')
    result = result + indent(3,   'parent = parent.parentNode\n')
    result = result + indent(2, 'return None\n\n')
    return result


g_valueTypeMap = {
    'bool' : (boolGetAttr, boolSetAttr),
    'long' : (longGetAttr, longSetAttr),
    'list' : (listGetAttr, stringSetAttr),
    'node' : (nodeGetAttr, nodeSetAttr),
    'string' : (stringGetAttr, stringSetAttr),
    'form' : (formGetAttr, None),
    'const' : (constGetAttr, None)
    }

def GenClassFile(klass, header, output_dir):
    class_name = 'HTML%sElement' % klass.getAttribute('name')
    fileName = os.path.join(output_dir,class_name + '.py')
    file = open(fileName, 'w')

    # General header stuff
    file.write(string.replace(header, '$FILE$', class_name))

    # Import statements
    file.write('import string\n')
    file.write('from xml.dom import Node\n')
    baseclass = klass.getElementsByTagName('baseclass')[0].getAttribute('name')
    base_name = string.split(baseclass, '.')[-1]
    file.write('from %s import %s\n' % (baseclass, base_name))
    file.write('\n')

    # Class declaration
    file.write('class %s(%s):\n\n' % (class_name, base_name))

    # Constructor
    file.write(indent(1, 'def __init__(self, ownerDocument, nodeName'))
    multiple = klass.getAttribute('multiple')
    tag_name = klass.getAttribute('tagname')
    if not multiple:
        if not tag_name:
            tag_name = string.upper(klass.getAttribute('name'))
        file.write('="%s"' % tag_name)
    file.write('):\n')
    file.write(indent(2, '%s.__init__(self, ownerDocument, nodeName)\n\n' % base_name))

    # Attributes
    file.write(indent(1, '### Attribute Methods ###\n\n'))
    attrs = klass.getElementsByTagName('attribute')
    read_attrs = []
    write_attrs = []
    for attr in attrs:
        dom_name = attr.getAttribute('name')
        value_type = attr.getAttribute('type')
        html_name = attr.getAttribute('htmlname')
        if not html_name:
            html_name = string.upper(dom_name)
        value = attr.getAttribute('value')    # for const value-type
        permissions = attr.getElementsByTagName('permissions')[0]
        readable = int(permissions.getAttribute('readable'))
        writeable = int(permissions.getAttribute('writeable'))

        if readable:
            file.write(indent(1, 'def _get_%s(self):\n' % dom_name))
            get_func = g_valueTypeMap[value_type][0]
            file.write(get_func(html_name, value))
            read_attrs.append(dom_name)

        if writeable:
            file.write(indent(1, 'def _set_%s(self, value):\n' % dom_name))
            set_func = g_valueTypeMap[value_type][1]
            try:
                file.write(set_func(html_name or value))
            except:
                raise "Set function '%s' in class %s, attribute %s" % (value_type, class_name, dom_name)
            write_attrs.append(dom_name)

    # Methods
    methods = klass.getElementsByTagName('method')
    if methods:
        file.write(indent(1, '### Methods ###\n\n'))
    for method in methods:
        method_name = method.getAttribute('name')
        params = method.getElementsByTagName('params')[0].childNodes
        param_list = []
        for param in params:
            arg = param.getAttribute('name')
            default = param.firstChild
            param_list.append((arg,default))
        file.write(indent(1, 'def %s(self' % method_name))
        for arg,default in param_list:
            file.write(', %s' % arg)
            if default:
                file.write('=%s' % default.data)
        file.write('):\n')

        # The function code
        code = method.getElementsByTagName('code')[0].firstChild
        if code:
            lines = string.split(string.strip(code.data), '\n')
            for line in lines:
                writeTab(file, 2, line)
        else:
            file.write(indent(2, 'pass\n'))
        file.write('\n')

    # Attribute access control
    file.write(indent(1, '### Attribute Access Mappings ###\n\n'))

    file.write(indent(1, '_readComputedAttrs = %s._readComputedAttrs.copy()\n' % base_name))
    if len(read_attrs):
        file.write(indent(1, '_readComputedAttrs.update({\n'))
        for attr in read_attrs[:-1]:
            file.write(indent(2, '"%s" : _get_%s,\n' % (attr, attr)))
        attr = read_attrs[-1]
        file.write(indent(2, '"%s" : _get_%s\n' % (attr, attr)))
        file.write(indent(2, '})\n\n'))

    file.write(indent(1, '_writeComputedAttrs = %s._writeComputedAttrs.copy()\n' % base_name))
    if len(write_attrs):
        file.write(indent(1, '_writeComputedAttrs.update({\n'))
        for attr in write_attrs[:-1]:
            file.write(indent(2, '"%s" : _set_%s,\n' % (attr, attr)))
        attr = write_attrs[-1]
        file.write(indent(2, '"%s" : _set_%s\n' % (attr, attr)))
        file.write(indent(2, '})\n\n'))

    file.write(indent(1, '_readOnlyAttrs = filter(lambda k,m=_writeComputedAttrs: not m.has_key(k),\n'))
    file.write(indent(1, '                 %s._readOnlyAttrs + _readComputedAttrs.keys())\n\n' % base_name))

    return fileName

if __name__ == '__main__':
    program_name = os.path.basename(sys.argv[0])
    output_dir = None

    if len(sys.argv) < 2:
        print 'Usage:  %s input_file [output_dir]' % program_name
        sys.exit(1)
    elif len(sys.argv) == 3:
        output_dir = sys.argv[2]

    input_file = sys.argv[1]

    Generate(input_file,output_dir,program_name)