1##############################################################################
2#
3# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
4# All Rights Reserved.
5#
6# This software is subject to the provisions of the Zope Public License,
7# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11# FOR A PARTICULAR PURPOSE.
12#
13##############################################################################
14"""
15Parse XML and compile to TALInterpreter intermediate code.
16"""
17
18from XMLParser import XMLParser
19from TALDefs import XML_NS, ZOPE_I18N_NS, ZOPE_METAL_NS, ZOPE_TAL_NS
20from TALGenerator import TALGenerator
21
22class TALParser(XMLParser):
23
24    ordered_attributes = 1
25
26    def __init__(self, gen=None): # Override
27        XMLParser.__init__(self)
28        if gen is None:
29            gen = TALGenerator()
30        self.gen = gen
31        self.nsStack = []
32        self.nsDict = {XML_NS: 'xml'}
33        self.nsNew = []
34
35    def getCode(self):
36        return self.gen.getCode()
37
38    def getWarnings(self):
39        return ()
40
41    def StartNamespaceDeclHandler(self, prefix, uri):
42        self.nsStack.append(self.nsDict.copy())
43        self.nsDict[uri] = prefix
44        self.nsNew.append((prefix, uri))
45
46    def EndNamespaceDeclHandler(self, prefix):
47        self.nsDict = self.nsStack.pop()
48
49    def StartElementHandler(self, name, attrs):
50        if self.ordered_attributes:
51            # attrs is a list of alternating names and values
52            attrlist = []
53            for i in range(0, len(attrs), 2):
54                key = attrs[i]
55                value = attrs[i+1]
56                attrlist.append((key, value))
57        else:
58            # attrs is a dict of {name: value}
59            attrlist = attrs.items()
60            attrlist.sort() # For definiteness
61        name, attrlist, taldict, metaldict, i18ndict \
62              = self.process_ns(name, attrlist)
63        attrlist = self.xmlnsattrs() + attrlist
64        self.gen.emitStartElement(name, attrlist, taldict, metaldict, i18ndict)
65
66    def process_ns(self, name, attrlist):
67        taldict = {}
68        metaldict = {}
69        i18ndict = {}
70        fixedattrlist = []
71        name, namebase, namens = self.fixname(name)
72        for key, value in attrlist:
73            key, keybase, keyns = self.fixname(key)
74            ns = keyns or namens # default to tag namespace
75            item = key, value
76            if ns == 'metal':
77                metaldict[keybase] = value
78                item = item + ("metal",)
79            elif ns == 'tal':
80                taldict[keybase] = value
81                item = item + ("tal",)
82            elif ns == 'i18n':
83                assert 0, "dealing with i18n: " + `(keybase, value)`
84                i18ndict[keybase] = value
85                item = item + ('i18n',)
86            fixedattrlist.append(item)
87        if namens in ('metal', 'tal', 'i18n'):
88            taldict['tal tag'] = namens
89        return name, fixedattrlist, taldict, metaldict, i18ndict
90
91    def xmlnsattrs(self):
92        newlist = []
93        for prefix, uri in self.nsNew:
94            if prefix:
95                key = "xmlns:" + prefix
96            else:
97                key = "xmlns"
98            if uri in (ZOPE_METAL_NS, ZOPE_TAL_NS, ZOPE_I18N_NS):
99                item = (key, uri, "xmlns")
100            else:
101                item = (key, uri)
102            newlist.append(item)
103        self.nsNew = []
104        return newlist
105
106    def fixname(self, name):
107        if ' ' in name:
108            uri, name = name.split(' ')
109            prefix = self.nsDict[uri]
110            prefixed = name
111            if prefix:
112                prefixed = "%s:%s" % (prefix, name)
113            ns = 'x'
114            if uri == ZOPE_TAL_NS:
115                ns = 'tal'
116            elif uri == ZOPE_METAL_NS:
117                ns = 'metal'
118            elif uri == ZOPE_I18N_NS:
119                ns = 'i18n'
120            return (prefixed, name, ns)
121        return (name, name, None)
122
123    def EndElementHandler(self, name):
124        name = self.fixname(name)[0]
125        self.gen.emitEndElement(name)
126
127    def DefaultHandler(self, text):
128        self.gen.emitRawText(text)
129
130def test():
131    import sys
132    p = TALParser()
133    file = "tests/input/test01.xml"
134    if sys.argv[1:]:
135        file = sys.argv[1]
136    p.parseFile(file)
137    program, macros = p.getCode()
138    from TALInterpreter import TALInterpreter
139    from DummyEngine import DummyEngine
140    engine = DummyEngine(macros)
141    TALInterpreter(program, macros, engine, sys.stdout, wrap=0)()
142
143if __name__ == "__main__":
144    test()
145