annotate markup/output.py @ 112:a834a6669681

Docstring typo fix.
author cmlenz
date Mon, 31 Jul 2006 22:08:32 +0000
parents 2de3f9d84a1c
children 93bbdcf9428b
rev   line source
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
2 #
66
822089ae65ce Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents: 27
diff changeset
3 # Copyright (C) 2006 Edgewall Software
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
4 # All rights reserved.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
5 #
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
66
822089ae65ce Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents: 27
diff changeset
8 # are also available at http://markup.edgewall.org/wiki/License.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
9 #
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
66
822089ae65ce Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents: 27
diff changeset
12 # history and logs, available at http://markup.edgewall.org/log/.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
13
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
14 """This module provides different kinds of serialization methods for XML event
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
15 streams.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
16 """
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
17
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
18 try:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
19 frozenset
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
20 except NameError:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
21 from sets import ImmutableSet as frozenset
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
22 from itertools import chain
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
23
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
24 from markup.core import escape, Markup, Namespace, QName
105
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
25 from markup.core import DOCTYPE, START, END, START_NS, END_NS, TEXT, COMMENT, PI
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
26
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
27 __all__ = ['Serializer', 'XMLSerializer', 'HTMLSerializer']
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
28
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
29
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
30 class Serializer(object):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
31 """Base class for serializers."""
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
32
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
33 def serialize(self, stream):
26
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
34 """Must be implemented by concrete subclasses to serialize the given
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
35 stream.
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
36
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
37 This method must be implemented as a generator, producing the
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
38 serialized output incrementally as unicode strings.
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
39 """
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
40 raise NotImplementedError
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
41
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
42
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
43 class DocType(object):
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
44 """Defines a number of commonly used DOCTYPE declarations as constants."""
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
45
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
46 HTML_STRICT = ('html', '-//W3C//DTD HTML 4.01//EN',
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
47 'http://www.w3.org/TR/html4/strict.dtd')
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
48 HTML_TRANSITIONAL = ('html', '-//W3C//DTD HTML 4.01 Transitional//EN',
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
49 'http://www.w3.org/TR/html4/loose.dtd')
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
50 HTML = HTML_STRICT
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
51
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
52 XHTML_STRICT = ('html', '-//W3C//DTD XHTML 1.0 Strict//EN',
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
53 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
54 XHTML_TRANSITIONAL = ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
55 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
56 XHTML = XHTML_STRICT
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
57
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
58
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
59 class XMLSerializer(Serializer):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
60 """Produces XML text from an event stream.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
61
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
62 >>> from markup.builder import tag
20
e3d3c1d8c98a Fix tests broken in [20].
cmlenz
parents: 19
diff changeset
63 >>> elem = tag.div(tag.a(href='foo'), tag.br, tag.hr(noshade=True))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
64 >>> print ''.join(XMLSerializer().serialize(elem.generate()))
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
65 <div><a href="foo"/><br/><hr noshade="True"/></div>
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
66 """
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
67 def __init__(self, doctype=None):
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
68 """Initialize the XML serializer.
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
69
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
70 @param doctype: a `(name, pubid, sysid)` tuple that represents the
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
71 DOCTYPE declaration that should be included at the top of the
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
72 generated output
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
73 """
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
74 self.preamble = []
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
75 if doctype:
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
76 self.preamble.append((DOCTYPE, doctype, (None, -1, -1)))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
77
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
78 def serialize(self, stream):
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
79 have_doctype = False
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
80 ns_attrib = []
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
81 ns_mapping = {}
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
82
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
83 stream = _PushbackIterator(chain(self.preamble, stream))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
84 for kind, data, pos in stream:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
85
109
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
86 if kind is START:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
87 tag, attrib = data
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
88
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
89 tagname = tag.localname
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
90 if tag.namespace:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
91 try:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
92 prefix = ns_mapping[tag.namespace]
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
93 if prefix:
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
94 tagname = '%s:%s' % (prefix, tag.localname)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
95 except KeyError:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
96 ns_attrib.append((QName('xmlns'), tag.namespace))
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
97 buf = ['<%s' % tagname]
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
98
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
99 if ns_attrib:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
100 attrib.extend(ns_attrib)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
101 ns_attrib = []
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
102 for attr, value in attrib:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
103 attrname = attr.localname
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
104 if attr.namespace:
26
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
105 prefix = ns_mapping.get(attr.namespace)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
106 if prefix:
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
107 attrname = '%s:%s' % (prefix, attrname)
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
108 buf.append(' %s="%s"' % (attrname, escape(value)))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
109
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
110 kind, data, pos = stream.next()
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
111 if kind is END:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
112 buf.append('/>')
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
113 else:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
114 buf.append('>')
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
115 stream.pushback((kind, data, pos))
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
116
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
117 yield Markup(''.join(buf))
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
118
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
119 elif kind is END:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
120 tag = data
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
121 tagname = tag.localname
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
122 if tag.namespace:
26
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
123 prefix = ns_mapping.get(tag.namespace)
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
124 if prefix:
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
125 tagname = '%s:%s' % (prefix, tag.localname)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
126 yield Markup('</%s>' % tagname)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
127
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
128 elif kind is TEXT:
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
129 yield escape(data, quotes=False)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
130
89
d4c7617900e3 Support comments in templates that are not included in the output, in the same way Kid does: if the comment text starts with a `!` character, it is stripped from the output.
cmlenz
parents: 85
diff changeset
131 elif kind is COMMENT:
d4c7617900e3 Support comments in templates that are not included in the output, in the same way Kid does: if the comment text starts with a `!` character, it is stripped from the output.
cmlenz
parents: 85
diff changeset
132 yield Markup('<!--%s-->' % data)
d4c7617900e3 Support comments in templates that are not included in the output, in the same way Kid does: if the comment text starts with a `!` character, it is stripped from the output.
cmlenz
parents: 85
diff changeset
133
109
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
134 elif kind is DOCTYPE:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
135 if not have_doctype:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
136 name, pubid, sysid = data
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
137 buf = ['<!DOCTYPE %s']
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
138 if pubid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
139 buf.append(' PUBLIC "%s"')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
140 elif sysid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
141 buf.append(' SYSTEM')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
142 if sysid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
143 buf.append(' "%s"')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
144 buf.append('>\n')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
145 yield Markup(''.join(buf), *filter(None, data))
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
146 have_doctype = True
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
147
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
148 elif kind is START_NS:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
149 prefix, uri = data
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
150 if uri not in ns_mapping:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
151 ns_mapping[uri] = prefix
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
152 if not prefix:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
153 ns_attrib.append((QName('xmlns'), uri))
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
154 else:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
155 ns_attrib.append((QName('xmlns:%s' % prefix), uri))
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
156
105
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
157 elif kind is PI:
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
158 yield Markup('<?%s %s?>' % data)
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
159
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
160
96
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
161 class XHTMLSerializer(XMLSerializer):
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
162 """Produces XHTML text from an event stream.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
163
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
164 >>> from markup.builder import tag
20
e3d3c1d8c98a Fix tests broken in [20].
cmlenz
parents: 19
diff changeset
165 >>> elem = tag.div(tag.a(href='foo'), tag.br, tag.hr(noshade=True))
96
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
166 >>> print ''.join(XHTMLSerializer().serialize(elem.generate()))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
167 <div><a href="foo"></a><br /><hr noshade="noshade" /></div>
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
168 """
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
169
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 1
diff changeset
170 NAMESPACE = Namespace('http://www.w3.org/1999/xhtml')
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
171
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
172 _EMPTY_ELEMS = frozenset(['area', 'base', 'basefont', 'br', 'col', 'frame',
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
173 'hr', 'img', 'input', 'isindex', 'link', 'meta',
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
174 'param'])
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
175 _BOOLEAN_ATTRS = frozenset(['selected', 'checked', 'compact', 'declare',
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
176 'defer', 'disabled', 'ismap', 'multiple',
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
177 'nohref', 'noresize', 'noshade', 'nowrap'])
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
178
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
179 def serialize(self, stream):
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
180 have_doctype = False
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
181 ns_mapping = {}
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
182
85
db8f2958c670 Improve handling of DOCTYPE declarations.
cmlenz
parents: 73
diff changeset
183 stream = _PushbackIterator(chain(self.preamble, stream))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
184 for kind, data, pos in stream:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
185
109
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
186 if kind is START:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
187 tag, attrib = data
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 1
diff changeset
188 if tag.namespace and tag not in self.NAMESPACE:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
189 continue # not in the HTML namespace, so don't emit
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
190 buf = ['<', tag.localname]
96
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
191
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
192 for attr, value in attrib:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
193 if attr.namespace and attr not in self.NAMESPACE:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
194 continue # not in the HTML namespace, so don't emit
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
195 if attr.localname in self._BOOLEAN_ATTRS:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
196 if value:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
197 buf.append(' %s="%s"' % (attr.localname, attr.localname))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
198 else:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
199 buf.append(' %s="%s"' % (attr.localname, escape(value)))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
200
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
201 if tag.localname in self._EMPTY_ELEMS:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
202 kind, data, pos = stream.next()
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
203 if kind is END:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
204 buf.append(' />')
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
205 else:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
206 buf.append('>')
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
207 stream.pushback((kind, data, pos))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
208 else:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
209 buf.append('>')
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
210
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
211 yield Markup(''.join(buf))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
212
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
213 elif kind is END:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
214 tag = data
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
215 if tag.namespace and tag not in self.NAMESPACE:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
216 continue # not in the HTML namespace, so don't emit
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
217 yield Markup('</%s>' % tag.localname)
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
218
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
219 elif kind is TEXT:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
220 yield escape(data, quotes=False)
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
221
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
222 elif kind is COMMENT:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
223 yield Markup('<!--%s-->' % data)
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
224
109
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
225 elif kind is DOCTYPE:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
226 if not have_doctype:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
227 name, pubid, sysid = data
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
228 buf = ['<!DOCTYPE %s']
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
229 if pubid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
230 buf.append(' PUBLIC "%s"')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
231 elif sysid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
232 buf.append(' SYSTEM')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
233 if sysid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
234 buf.append(' "%s"')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
235 buf.append('>\n')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
236 yield Markup(''.join(buf), *filter(None, data))
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
237 have_doctype = True
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
238
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
239 elif kind is START_NS:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
240 prefix, uri = data
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
241 if uri not in ns_mapping:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
242 ns_mapping[uri] = prefix
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
243
105
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
244 elif kind is PI:
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
245 yield Markup('<?%s %s?>' % data)
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
246
96
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
247
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
248 class HTMLSerializer(XHTMLSerializer):
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
249 """Produces HTML text from an event stream.
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
250
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
251 >>> from markup.builder import tag
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
252 >>> elem = tag.div(tag.a(href='foo'), tag.br, tag.hr(noshade=True))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
253 >>> print ''.join(HTMLSerializer().serialize(elem.generate()))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
254 <div><a href="foo"></a><br><hr noshade></div>
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
255 """
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
256
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
257 def serialize(self, stream):
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
258 have_doctype = False
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
259 ns_mapping = {}
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
260
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
261 stream = _PushbackIterator(chain(self.preamble, stream))
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
262 for kind, data, pos in stream:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
263
109
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
264 if kind is START:
96
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
265 tag, attrib = data
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
266 if tag.namespace and tag not in self.NAMESPACE:
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
267 continue # not in the HTML namespace, so don't emit
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
268 buf = ['<', tag.localname]
35d681a94763 Add an XHTML serialization method. Now really need to get rid of some code duplication in the `markup.output` module.
cmlenz
parents: 89
diff changeset
269
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
270 for attr, value in attrib:
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 1
diff changeset
271 if attr.namespace and attr not in self.NAMESPACE:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
272 continue # not in the HTML namespace, so don't emit
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
273 if attr.localname in self._BOOLEAN_ATTRS:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
274 if value:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
275 buf.append(' %s' % attr.localname)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
276 else:
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
277 buf.append(' %s="%s"' % (attr.localname, escape(value)))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
278
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
279 if tag.localname in self._EMPTY_ELEMS:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
280 kind, data, pos = stream.next()
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
281 if kind is not END:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
282 stream.pushback((kind, data, pos))
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
283
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
284 yield Markup(''.join(buf + ['>']))
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
285
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
286 elif kind is END:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
287 tag = data
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 1
diff changeset
288 if tag.namespace and tag not in self.NAMESPACE:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
289 continue # not in the HTML namespace, so don't emit
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
290 yield Markup('</%s>' % tag.localname)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
291
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
292 elif kind is TEXT:
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
293 yield escape(data, quotes=False)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
294
89
d4c7617900e3 Support comments in templates that are not included in the output, in the same way Kid does: if the comment text starts with a `!` character, it is stripped from the output.
cmlenz
parents: 85
diff changeset
295 elif kind is COMMENT:
d4c7617900e3 Support comments in templates that are not included in the output, in the same way Kid does: if the comment text starts with a `!` character, it is stripped from the output.
cmlenz
parents: 85
diff changeset
296 yield Markup('<!--%s-->' % data)
d4c7617900e3 Support comments in templates that are not included in the output, in the same way Kid does: if the comment text starts with a `!` character, it is stripped from the output.
cmlenz
parents: 85
diff changeset
297
109
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
298 elif kind is DOCTYPE:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
299 if not have_doctype:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
300 name, pubid, sysid = data
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
301 buf = ['<!DOCTYPE %s']
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
302 if pubid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
303 buf.append(' PUBLIC "%s"')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
304 elif sysid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
305 buf.append(' SYSTEM')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
306 if sysid:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
307 buf.append(' "%s"')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
308 buf.append('>\n')
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
309 yield Markup(''.join(buf), *filter(None, data))
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
310 have_doctype = True
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
311
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
312 elif kind is START_NS:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
313 prefix, uri = data
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
314 if uri not in ns_mapping:
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
315 ns_mapping[uri] = prefix
2de3f9d84a1c Reorder the conditional branches in the serializers so that the more common event kinds are on top.
cmlenz
parents: 105
diff changeset
316
105
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
317 elif kind is PI:
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
318 yield Markup('<?%s %s?>' % data)
334a338847af Include processing instructions in serialized streams.
cmlenz
parents: 96
diff changeset
319
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
320
26
039fc5b87405 * Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents: 20
diff changeset
321 class _PushbackIterator(object):
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
322 """A simple wrapper for iterators that allows pushing items back on the
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
323 queue via the `pushback()` method.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
324
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
325 That can effectively be used to peek at the next item."""
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
326 __slots__ = ['iterable', 'buf']
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
327
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
328 def __init__(self, iterable):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
329 self.iterable = iter(iterable)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
330 self.buf = []
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
331
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
332 def __iter__(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
333 return self
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
334
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
335 def next(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
336 if self.buf:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
337 return self.buf.pop(0)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
338 return self.iterable.next()
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
339
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
340 def pushback(self, item):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
341 self.buf.append(item)
Copyright (C) 2012-2017 Edgewall Software