annotate roundup/cgi/TAL/HTMLTALParser.py @ 8478:ed4ef394d5d6

doc: initial attempt to document setup of pgp support for email. Used an AI assistant to help write this. Basic gpg commands seem to work, but I have not tested this totally. Docs basically follow the setup used for pgp testing in the test suite. It looks like roundup accepts signed emails as well as encrypted and signed emails. But it does not generate signed emails. Also it looks like there is no PGP support for alternate email addresses. Only primary addresses can do PGP emails.
author John Rouillard <rouilj@ieee.org>
date Sat, 15 Nov 2025 16:59:24 -0500
parents 23b8e6067f7c
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
1 ##############################################################################
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
2 #
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
3 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
4 # All Rights Reserved.
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
5 #
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
6 # This software is subject to the provisions of the Zope Public License,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
7 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
11 # FOR A PARTICULAR PURPOSE.
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
12 #
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
13 ##############################################################################
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
14 """
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
15 Parse HTML and compile to TALInterpreter intermediate code.
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
16 """
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
17
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
18 import sys
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
19
5388
d26921b851c3 Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5381
diff changeset
20 from .TALGenerator import TALGenerator
d26921b851c3 Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5381
diff changeset
21 from .HTMLParser import HTMLParser, HTMLParseError
d26921b851c3 Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5381
diff changeset
22 from .TALDefs import \
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
23 ZOPE_METAL_NS, ZOPE_TAL_NS, ZOPE_I18N_NS, METALError, TALError, I18NError
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
24
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
25 BOOLEAN_HTML_ATTRS = [
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
26 # List of Boolean attributes in HTML that may be given in
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
27 # minimized form (e.g. <img ismap> rather than <img ismap="">)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
28 # From http://www.w3.org/TR/xhtml1/#guidelines (C.10)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
29 "compact", "nowrap", "ismap", "declare", "noshade", "checked",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
30 "disabled", "readonly", "multiple", "selected", "noresize",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
31 "defer"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
32 ]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
33
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
34 EMPTY_HTML_TAGS = [
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
35 # List of HTML tags with an empty content model; these are
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
36 # rendered in minimized form, e.g. <img />.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
37 # From http://www.w3.org/TR/xhtml1/#dtds
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
38 "base", "meta", "link", "hr", "br", "param", "img", "area",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
39 "input", "col", "basefont", "isindex", "frame",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
40 ]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
41
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
42 PARA_LEVEL_HTML_TAGS = [
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
43 # List of HTML elements that close open paragraph-level elements
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
44 # and are themselves paragraph-level.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
45 "h1", "h2", "h3", "h4", "h5", "h6", "p",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
46 ]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
47
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
48 BLOCK_CLOSING_TAG_MAP = {
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
49 "tr": ("tr", "td", "th"),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
50 "td": ("td", "th"),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
51 "th": ("td", "th"),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
52 "li": ("li",),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
53 "dd": ("dd", "dt"),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
54 "dt": ("dd", "dt"),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
55 }
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
56
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
57 BLOCK_LEVEL_HTML_TAGS = [
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
58 # List of HTML tags that denote larger sections than paragraphs.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
59 "blockquote", "table", "tr", "th", "td", "thead", "tfoot", "tbody",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
60 "noframe", "ul", "ol", "li", "dl", "dt", "dd", "div",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
61 ]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
62
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
63 TIGHTEN_IMPLICIT_CLOSE_TAGS = (PARA_LEVEL_HTML_TAGS
5395
23b8e6067f7c Python 3 preparation: update calls to dict methods.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5388
diff changeset
64 + list(BLOCK_CLOSING_TAG_MAP.keys()))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
65
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
66
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
67 class NestingError(HTMLParseError):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
68 """Exception raised when elements aren't properly nested."""
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
69
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
70 def __init__(self, tagstack, endtag, position=(None, None)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
71 self.endtag = endtag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
72 if tagstack:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
73 if len(tagstack) == 1:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
74 msg = ('Open tag <%s> does not match close tag </%s>'
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
75 % (tagstack[0], endtag))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
76 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
77 msg = ('Open tags <%s> do not match close tag </%s>'
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
78 % ('>, <'.join(tagstack), endtag))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
79 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
80 msg = 'No tags are open to match </%s>' % endtag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
81 HTMLParseError.__init__(self, msg, position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
82
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
83 class EmptyTagError(NestingError):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
84 """Exception raised when empty elements have an end tag."""
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
85
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
86 def __init__(self, tag, position=(None, None)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
87 self.tag = tag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
88 msg = 'Close tag </%s> should be removed' % tag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
89 HTMLParseError.__init__(self, msg, position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
90
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
91 class OpenTagError(NestingError):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
92 """Exception raised when a tag is not allowed in another tag."""
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
93
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
94 def __init__(self, tagstack, tag, position=(None, None)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
95 self.tag = tag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
96 msg = 'Tag <%s> is not allowed in <%s>' % (tag, tagstack[-1])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
97 HTMLParseError.__init__(self, msg, position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
98
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
99 class HTMLTALParser(HTMLParser):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
100
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
101 # External API
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
102
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
103 def __init__(self, gen=None):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
104 HTMLParser.__init__(self)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
105 if gen is None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
106 gen = TALGenerator(xml=0)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
107 self.gen = gen
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
108 self.tagstack = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
109 self.nsstack = []
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
110 self.nsdict = {'tal': ZOPE_TAL_NS,
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
111 'metal': ZOPE_METAL_NS,
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
112 'i18n': ZOPE_I18N_NS,
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
113 }
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
114
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
115 def parseFile(self, file):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
116 f = open(file)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
117 data = f.read()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
118 f.close()
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
119 try:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
120 self.parseString(data)
5248
198b6e810c67 Use Python-3-compatible 'as' syntax for except statements
Eric S. Raymond <esr@thyrsus.com>
parents: 2348
diff changeset
121 except TALError as e:
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
122 e.setFile(file)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
123 raise
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
124
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
125 def parseString(self, data):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
126 self.feed(data)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
127 self.close()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
128 while self.tagstack:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
129 self.implied_endtag(self.tagstack[-1], 2)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
130 assert self.nsstack == [], self.nsstack
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
131
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
132 def getCode(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
133 return self.gen.getCode()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
134
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
135 def getWarnings(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
136 return ()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
137
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
138 # Overriding HTMLParser methods
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
139
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
140 def handle_starttag(self, tag, attrs):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
141 self.close_para_tags(tag)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
142 self.scan_xmlns(attrs)
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
143 tag, attrlist, taldict, metaldict, i18ndict \
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
144 = self.process_ns(tag, attrs)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
145 if tag in EMPTY_HTML_TAGS and taldict.get("content"):
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
146 raise TALError(
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5248
diff changeset
147 "empty HTML tags cannot use tal:content: %s" % repr(tag),
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
148 self.getpos())
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
149 self.tagstack.append(tag)
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
150 self.gen.emitStartElement(tag, attrlist, taldict, metaldict, i18ndict,
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
151 self.getpos())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
152 if tag in EMPTY_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
153 self.implied_endtag(tag, -1)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
154
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
155 def handle_startendtag(self, tag, attrs):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
156 self.close_para_tags(tag)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
157 self.scan_xmlns(attrs)
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
158 tag, attrlist, taldict, metaldict, i18ndict \
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
159 = self.process_ns(tag, attrs)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
160 if taldict.get("content"):
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
161 if tag in EMPTY_HTML_TAGS:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
162 raise TALError(
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5248
diff changeset
163 "empty HTML tags cannot use tal:content: %s" % repr(tag),
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
164 self.getpos())
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
165 self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
166 i18ndict, self.getpos())
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
167 self.gen.emitEndElement(tag, implied=-1)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
168 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
169 self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
170 i18ndict, self.getpos(), isend=1)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
171 self.pop_xmlns()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
172
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
173 def handle_endtag(self, tag):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
174 if tag in EMPTY_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
175 # </img> etc. in the source is an error
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
176 raise EmptyTagError(tag, self.getpos())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
177 self.close_enclosed_tags(tag)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
178 self.gen.emitEndElement(tag)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
179 self.pop_xmlns()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
180 self.tagstack.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
181
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
182 def close_para_tags(self, tag):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
183 if tag in EMPTY_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
184 return
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
185 close_to = -1
5381
0942fe89e82e Python 3 preparation: change "x.has_key(y)" to "y in x".
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
186 if tag in BLOCK_CLOSING_TAG_MAP:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
187 blocks_to_close = BLOCK_CLOSING_TAG_MAP[tag]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
188 for i in range(len(self.tagstack)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
189 t = self.tagstack[i]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
190 if t in blocks_to_close:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
191 if close_to == -1:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
192 close_to = i
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
193 elif t in BLOCK_LEVEL_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
194 close_to = -1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
195 elif tag in PARA_LEVEL_HTML_TAGS + BLOCK_LEVEL_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
196 i = len(self.tagstack) - 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
197 while i >= 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
198 closetag = self.tagstack[i]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
199 if closetag in BLOCK_LEVEL_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
200 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
201 if closetag in PARA_LEVEL_HTML_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
202 if closetag != "p":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
203 raise OpenTagError(self.tagstack, tag, self.getpos())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
204 close_to = i
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
205 i = i - 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
206 if close_to >= 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
207 while len(self.tagstack) > close_to:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
208 self.implied_endtag(self.tagstack[-1], 1)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
209
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
210 def close_enclosed_tags(self, tag):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
211 if tag not in self.tagstack:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
212 raise NestingError(self.tagstack, tag, self.getpos())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
213 while tag != self.tagstack[-1]:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
214 self.implied_endtag(self.tagstack[-1], 1)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
215 assert self.tagstack[-1] == tag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
216
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
217 def implied_endtag(self, tag, implied):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
218 assert tag == self.tagstack[-1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
219 assert implied in (-1, 1, 2)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
220 isend = (implied < 0)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
221 if tag in TIGHTEN_IMPLICIT_CLOSE_TAGS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
222 # Pick out trailing whitespace from the program, and
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
223 # insert the close tag before the whitespace.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
224 white = self.gen.unEmitWhitespace()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
225 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
226 white = None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
227 self.gen.emitEndElement(tag, isend=isend, implied=implied)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
228 if white:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
229 self.gen.emitRawText(white)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
230 self.tagstack.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
231 self.pop_xmlns()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
232
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
233 def handle_charref(self, name):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
234 self.gen.emitRawText("&#%s;" % name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
235
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
236 def handle_entityref(self, name):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
237 self.gen.emitRawText("&%s;" % name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
238
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
239 def handle_data(self, data):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
240 self.gen.emitRawText(data)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
241
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
242 def handle_comment(self, data):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
243 self.gen.emitRawText("<!--%s-->" % data)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
244
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
245 def handle_decl(self, data):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
246 self.gen.emitRawText("<!%s>" % data)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
247
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
248 def handle_pi(self, data):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
249 self.gen.emitRawText("<?%s>" % data)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
250
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
251 # Internal thingies
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
252
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
253 def scan_xmlns(self, attrs):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
254 nsnew = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
255 for key, value in attrs:
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
256 if key.startswith("xmlns:"):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
257 nsnew[key[6:]] = value
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
258 if nsnew:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
259 self.nsstack.append(self.nsdict)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
260 self.nsdict = self.nsdict.copy()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
261 self.nsdict.update(nsnew)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
262 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
263 self.nsstack.append(self.nsdict)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
264
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
265 def pop_xmlns(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
266 self.nsdict = self.nsstack.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
267
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
268 def fixname(self, name):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
269 if ':' in name:
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
270 prefix, suffix = name.split(':', 1)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
271 if prefix == 'xmlns':
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
272 nsuri = self.nsdict.get(suffix)
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
273 if nsuri in (ZOPE_TAL_NS, ZOPE_METAL_NS, ZOPE_I18N_NS):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
274 return name, name, prefix
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
275 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
276 nsuri = self.nsdict.get(prefix)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
277 if nsuri == ZOPE_TAL_NS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
278 return name, suffix, 'tal'
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
279 elif nsuri == ZOPE_METAL_NS:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
280 return name, suffix, 'metal'
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
281 elif nsuri == ZOPE_I18N_NS:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
282 return name, suffix, 'i18n'
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
283 return name, name, 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
284
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
285 def process_ns(self, name, attrs):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
286 attrlist = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
287 taldict = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
288 metaldict = {}
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
289 i18ndict = {}
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
290 name, namebase, namens = self.fixname(name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
291 for item in attrs:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
292 key, value = item
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
293 key, keybase, keyns = self.fixname(key)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
294 ns = keyns or namens # default to tag namespace
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
295 if ns and ns != 'unknown':
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
296 item = (key, value, ns)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
297 if ns == 'tal':
5381
0942fe89e82e Python 3 preparation: change "x.has_key(y)" to "y in x".
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
298 if keybase in taldict:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
299 raise TALError("duplicate TAL attribute " +
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5248
diff changeset
300 repr(keybase), self.getpos())
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
301 taldict[keybase] = value
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
302 elif ns == 'metal':
5381
0942fe89e82e Python 3 preparation: change "x.has_key(y)" to "y in x".
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
303 if keybase in metaldict:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
304 raise METALError("duplicate METAL attribute " +
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5248
diff changeset
305 repr(keybase), self.getpos())
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
306 metaldict[keybase] = value
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
307 elif ns == 'i18n':
5381
0942fe89e82e Python 3 preparation: change "x.has_key(y)" to "y in x".
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
308 if keybase in i18ndict:
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
309 raise I18NError("duplicate i18n attribute " +
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5248
diff changeset
310 repr(keybase), self.getpos())
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
311 i18ndict[keybase] = value
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
312 attrlist.append(item)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
313 if namens in ('metal', 'tal'):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
314 taldict['tal tag'] = namens
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
315 return name, attrlist, taldict, metaldict, i18ndict

Roundup Issue Tracker: http://roundup-tracker.org/