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 """
15 Parse XML and compile to TALInterpreter intermediate code.
16 """
18 from XMLParser import XMLParser
19 from TALDefs import XML_NS, ZOPE_I18N_NS, ZOPE_METAL_NS, ZOPE_TAL_NS
20 from TALGenerator import TALGenerator
22 class TALParser(XMLParser):
24 ordered_attributes = 1
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 = []
35 def getCode(self):
36 return self.gen.getCode()
38 def getWarnings(self):
39 return ()
41 def StartNamespaceDeclHandler(self, prefix, uri):
42 self.nsStack.append(self.nsDict.copy())
43 self.nsDict[uri] = prefix
44 self.nsNew.append((prefix, uri))
46 def EndNamespaceDeclHandler(self, prefix):
47 self.nsDict = self.nsStack.pop()
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)
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
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
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)
123 def EndElementHandler(self, name):
124 name = self.fixname(name)[0]
125 self.gen.emitEndElement(name)
127 def DefaultHandler(self, text):
128 self.gen.emitRawText(text)
130 def 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)()
143 if __name__ == "__main__":
144 test()