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