Mercurial > genshi > mirror
annotate genshi/builder.py @ 1016:38565f2ab970 trunk
Fix handling of case where a translation has text after a closing tag (fixes #566, thanks to jomae for the patch).
author | hodgestar |
---|---|
date | Thu, 09 Jan 2014 21:23:41 +0000 |
parents | 19ac5d8fd96c |
children |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
854
4d9bef447df9
More work on reducing the size of the diff produced by 2to3.
cmlenz
parents:
853
diff
changeset
|
3 # Copyright (C) 2006-2009 Edgewall Software |
1 | 4 # All rights reserved. |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
230 | 8 # are also available at http://genshi.edgewall.org/wiki/License. |
1 | 9 # |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
230 | 12 # history and logs, available at http://genshi.edgewall.org/log/. |
1 | 13 |
430 | 14 """Support for programmatically generating markup streams from Python code using |
15 a very simple syntax. The main entry point to this module is the `tag` object | |
16 (which is actually an instance of the ``ElementFactory`` class). You should | |
17 rarely (if ever) need to directly import and use any of the other classes in | |
18 this module. | |
19 | |
20 Elements can be created using the `tag` object using attribute access. For | |
21 example: | |
22 | |
23 >>> doc = tag.p('Some text and ', tag.a('a link', href='http://example.org/'), '.') | |
24 >>> doc | |
25 <Element "p"> | |
26 | |
27 This produces an `Element` instance which can be further modified to add child | |
28 nodes and attributes. This is done by "calling" the element: positional | |
29 arguments are added as child nodes (alternatively, the `Element.append` method | |
30 can be used for that purpose), whereas keywords arguments are added as | |
31 attributes: | |
32 | |
33 >>> doc(tag.br) | |
34 <Element "p"> | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
35 >>> print(doc) |
430 | 36 <p>Some text and <a href="http://example.org/">a link</a>.<br/></p> |
37 | |
38 If an attribute name collides with a Python keyword, simply append an underscore | |
39 to the name: | |
40 | |
41 >>> doc(class_='intro') | |
42 <Element "p"> | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
43 >>> print(doc) |
430 | 44 <p class="intro">Some text and <a href="http://example.org/">a link</a>.<br/></p> |
45 | |
46 As shown above, an `Element` can easily be directly rendered to XML text by | |
47 printing it or using the Python ``str()`` function. This is basically a | |
48 shortcut for converting the `Element` to a stream and serializing that | |
49 stream: | |
50 | |
51 >>> stream = doc.generate() | |
431
ad01564e87f2
* Don't allow `style` attributes by default in the `HTMLSanitizer`. Closes #97.
cmlenz
parents:
430
diff
changeset
|
52 >>> stream #doctest: +ELLIPSIS |
430 | 53 <genshi.core.Stream object at ...> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
54 >>> print(stream) |
430 | 55 <p class="intro">Some text and <a href="http://example.org/">a link</a>.<br/></p> |
56 | |
57 | |
58 The `tag` object also allows creating "fragments", which are basically lists | |
59 of nodes (elements or text) that don't have a parent element. This can be useful | |
60 for creating snippets of markup that are attached to a parent element later (for | |
61 example in a template). Fragments are created by calling the `tag` object, which | |
62 returns an object of type `Fragment`: | |
63 | |
64 >>> fragment = tag('Hello, ', tag.em('world'), '!') | |
65 >>> fragment | |
66 <Fragment> | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
67 >>> print(fragment) |
430 | 68 Hello, <em>world</em>! |
69 """ | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
410
diff
changeset
|
70 |
737
ca72e3dc443d
Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents:
735
diff
changeset
|
71 from genshi.core import Attrs, Markup, Namespace, QName, Stream, \ |
ca72e3dc443d
Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents:
735
diff
changeset
|
72 START, END, TEXT |
1 | 73 |
433 | 74 __all__ = ['Fragment', 'Element', 'ElementFactory', 'tag'] |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
410
diff
changeset
|
75 __docformat__ = 'restructuredtext en' |
1 | 76 |
77 | |
78 class Fragment(object): | |
28 | 79 """Represents a markup fragment, which is basically just a list of element |
80 or text nodes. | |
81 """ | |
1 | 82 __slots__ = ['children'] |
83 | |
84 def __init__(self): | |
433 | 85 """Create a new fragment.""" |
1 | 86 self.children = [] |
87 | |
65
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
88 def __add__(self, other): |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
89 return Fragment()(self, other) |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
90 |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
91 def __call__(self, *args): |
433 | 92 """Append any positional arguments as child nodes. |
93 | |
94 :see: `append` | |
95 """ | |
854
4d9bef447df9
More work on reducing the size of the diff produced by 2to3.
cmlenz
parents:
853
diff
changeset
|
96 for arg in args: |
4d9bef447df9
More work on reducing the size of the diff produced by 2to3.
cmlenz
parents:
853
diff
changeset
|
97 self.append(arg) |
65
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
98 return self |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
99 |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
100 def __iter__(self): |
98
44af12832c5a
Bugfix in `builder` module: attribute values need to be converted to strings when generating streams.
cmlenz
parents:
94
diff
changeset
|
101 return self._generate() |
65
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
102 |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
103 def __repr__(self): |
860
16d55698006a
A bit of cleanup of the `Markup` Python implementation.
cmlenz
parents:
854
diff
changeset
|
104 return '<%s>' % type(self).__name__ |
65
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
105 |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
106 def __str__(self): |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
107 return str(self.generate()) |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
108 |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
109 def __unicode__(self): |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
110 return unicode(self.generate()) |
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
111 |
737
ca72e3dc443d
Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents:
735
diff
changeset
|
112 def __html__(self): |
ca72e3dc443d
Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents:
735
diff
changeset
|
113 return Markup(self.generate()) |
ca72e3dc443d
Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents:
735
diff
changeset
|
114 |
1 | 115 def append(self, node): |
433 | 116 """Append an element or string as child node. |
117 | |
118 :param node: the node to append; can be an `Element`, `Fragment`, or a | |
119 `Stream`, or a Python string or number | |
120 """ | |
379
e1d659c87ddf
The builder API now accepts streams as children of elements and fragments.
cmlenz
parents:
345
diff
changeset
|
121 if isinstance(node, (Stream, Element, basestring, int, float, long)): |
1 | 122 # For objects of a known/primitive type, we avoid the check for |
123 # whether it is iterable for better performance | |
124 self.children.append(node) | |
125 elif isinstance(node, Fragment): | |
133
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
119
diff
changeset
|
126 self.children.extend(node.children) |
1 | 127 elif node is not None: |
128 try: | |
854
4d9bef447df9
More work on reducing the size of the diff produced by 2to3.
cmlenz
parents:
853
diff
changeset
|
129 for child in node: |
4d9bef447df9
More work on reducing the size of the diff produced by 2to3.
cmlenz
parents:
853
diff
changeset
|
130 self.append(child) |
1 | 131 except TypeError: |
132 self.children.append(node) | |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
133 |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
134 def _generate(self): |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
135 for child in self.children: |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
136 if isinstance(child, Fragment): |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
137 for event in child._generate(): |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
138 yield event |
379
e1d659c87ddf
The builder API now accepts streams as children of elements and fragments.
cmlenz
parents:
345
diff
changeset
|
139 elif isinstance(child, Stream): |
e1d659c87ddf
The builder API now accepts streams as children of elements and fragments.
cmlenz
parents:
345
diff
changeset
|
140 for event in child: |
e1d659c87ddf
The builder API now accepts streams as children of elements and fragments.
cmlenz
parents:
345
diff
changeset
|
141 yield event |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
142 else: |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
143 if not isinstance(child, basestring): |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
144 child = unicode(child) |
133
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
119
diff
changeset
|
145 yield TEXT, child, (None, -1, -1) |
1 | 146 |
147 def generate(self): | |
498 | 148 """Return a markup event stream for the fragment. |
149 | |
150 :rtype: `Stream` | |
151 """ | |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
152 return Stream(self._generate()) |
1 | 153 |
154 | |
345 | 155 def _kwargs_to_attrs(kwargs): |
735
7e428b22dbaa
Tweak to [854] to not change the ordering of attributes compared to how they were previously ordered, to avoid breaking any tests that rely on the order. See #216.
cmlenz
parents:
730
diff
changeset
|
156 attrs = [] |
7e428b22dbaa
Tweak to [854] to not change the ordering of attributes compared to how they were previously ordered, to avoid breaking any tests that rely on the order. See #216.
cmlenz
parents:
730
diff
changeset
|
157 names = set() |
730
5e9d250ad3ad
Fix for potential duplicate attributes making it through the builder API. Closes #216.
cmlenz
parents:
506
diff
changeset
|
158 for name, value in kwargs.items(): |
5e9d250ad3ad
Fix for potential duplicate attributes making it through the builder API. Closes #216.
cmlenz
parents:
506
diff
changeset
|
159 name = name.rstrip('_').replace('_', '-') |
735
7e428b22dbaa
Tweak to [854] to not change the ordering of attributes compared to how they were previously ordered, to avoid breaking any tests that rely on the order. See #216.
cmlenz
parents:
730
diff
changeset
|
160 if value is not None and name not in names: |
7e428b22dbaa
Tweak to [854] to not change the ordering of attributes compared to how they were previously ordered, to avoid breaking any tests that rely on the order. See #216.
cmlenz
parents:
730
diff
changeset
|
161 attrs.append((QName(name), unicode(value))) |
7e428b22dbaa
Tweak to [854] to not change the ordering of attributes compared to how they were previously ordered, to avoid breaking any tests that rely on the order. See #216.
cmlenz
parents:
730
diff
changeset
|
162 names.add(name) |
7e428b22dbaa
Tweak to [854] to not change the ordering of attributes compared to how they were previously ordered, to avoid breaking any tests that rely on the order. See #216.
cmlenz
parents:
730
diff
changeset
|
163 return Attrs(attrs) |
345 | 164 |
165 | |
1 | 166 class Element(Fragment): |
167 """Simple XML output generator based on the builder pattern. | |
168 | |
169 Construct XML elements by passing the tag name to the constructor: | |
170 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
171 >>> print(Element('strong')) |
1 | 172 <strong/> |
173 | |
174 Attributes can be specified using keyword arguments. The values of the | |
175 arguments will be converted to strings and any special XML characters | |
176 escaped: | |
177 | |
967
19ac5d8fd96c
Fix a number of tests which Python's new hash randomization is causing to fail randomly.
hodgestar
parents:
860
diff
changeset
|
178 >>> print(Element('textarea', rows=10)) |
19ac5d8fd96c
Fix a number of tests which Python's new hash randomization is causing to fail randomly.
hodgestar
parents:
860
diff
changeset
|
179 <textarea rows="10"/> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
180 >>> print(Element('span', title='1 < 2')) |
1 | 181 <span title="1 < 2"/> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
182 >>> print(Element('span', title='"baz"')) |
1 | 183 <span title=""baz""/> |
184 | |
185 The " character is escaped using a numerical entity. | |
186 The order in which attributes are rendered is undefined. | |
187 | |
188 If an attribute value evaluates to `None`, that attribute is not included | |
189 in the output: | |
190 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
191 >>> print(Element('a', name=None)) |
1 | 192 <a/> |
193 | |
194 Attribute names that conflict with Python keywords can be specified by | |
195 appending an underscore: | |
196 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
197 >>> print(Element('div', class_='warning')) |
1 | 198 <div class="warning"/> |
199 | |
200 Nested elements can be added to an element using item access notation. | |
201 The call notation can also be used for this and for adding attributes | |
202 using keyword arguments, as one would do in the constructor. | |
203 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
204 >>> print(Element('ul')(Element('li'), Element('li'))) |
1 | 205 <ul><li/><li/></ul> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
206 >>> print(Element('a')('Label')) |
1 | 207 <a>Label</a> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
208 >>> print(Element('a')('Label', href="target")) |
1 | 209 <a href="target">Label</a> |
210 | |
211 Text nodes can be nested in an element by adding strings instead of | |
212 elements. Any special characters in the strings are escaped automatically: | |
213 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
214 >>> print(Element('em')('Hello world')) |
1 | 215 <em>Hello world</em> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
216 >>> print(Element('em')(42)) |
1 | 217 <em>42</em> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
218 >>> print(Element('em')('1 < 2')) |
1 | 219 <em>1 < 2</em> |
220 | |
221 This technique also allows mixed content: | |
222 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
223 >>> print(Element('p')('Hello ', Element('b')('world'))) |
1 | 224 <p>Hello <b>world</b></p> |
225 | |
34 | 226 Quotes are not escaped inside text nodes: |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
227 >>> print(Element('p')('"Hello"')) |
34 | 228 <p>"Hello"</p> |
229 | |
1 | 230 Elements can also be combined with other elements or strings using the |
231 addition operator, which results in a `Fragment` object that contains the | |
232 operands: | |
233 | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
234 >>> print(Element('br') + 'some text' + Element('br')) |
1 | 235 <br/>some text<br/> |
236 | |
237 Elements with a namespace can be generated using the `Namespace` and/or | |
238 `QName` classes: | |
239 | |
230 | 240 >>> from genshi.core import Namespace |
1 | 241 >>> xhtml = Namespace('http://www.w3.org/1999/xhtml') |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
242 >>> print(Element(xhtml.html, lang='en')) |
410
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
408
diff
changeset
|
243 <html xmlns="http://www.w3.org/1999/xhtml" lang="en"/> |
1 | 244 """ |
245 __slots__ = ['tag', 'attrib'] | |
246 | |
247 def __init__(self, tag_, **attrib): | |
248 Fragment.__init__(self) | |
249 self.tag = QName(tag_) | |
730
5e9d250ad3ad
Fix for potential duplicate attributes making it through the builder API. Closes #216.
cmlenz
parents:
506
diff
changeset
|
250 self.attrib = _kwargs_to_attrs(attrib) |
1 | 251 |
252 def __call__(self, *args, **kwargs): | |
433 | 253 """Append any positional arguments as child nodes, and keyword arguments |
254 as attributes. | |
255 | |
498 | 256 :return: the element itself so that calls can be chained |
257 :rtype: `Element` | |
433 | 258 :see: `Fragment.append` |
259 """ | |
730
5e9d250ad3ad
Fix for potential duplicate attributes making it through the builder API. Closes #216.
cmlenz
parents:
506
diff
changeset
|
260 self.attrib |= _kwargs_to_attrs(kwargs) |
98
44af12832c5a
Bugfix in `builder` module: attribute values need to be converted to strings when generating streams.
cmlenz
parents:
94
diff
changeset
|
261 Fragment.__call__(self, *args) |
44af12832c5a
Bugfix in `builder` module: attribute values need to be converted to strings when generating streams.
cmlenz
parents:
94
diff
changeset
|
262 return self |
1 | 263 |
65
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
264 def __repr__(self): |
860
16d55698006a
A bit of cleanup of the `Markup` Python implementation.
cmlenz
parents:
854
diff
changeset
|
265 return '<%s "%s">' % (type(self).__name__, self.tag) |
65
b3fdf93057ab
Support the use of directives as elements to reduce the need for using `py:strip`.
cmlenz
parents:
34
diff
changeset
|
266 |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
267 def _generate(self): |
133
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
119
diff
changeset
|
268 yield START, (self.tag, self.attrib), (None, -1, -1) |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
269 for kind, data, pos in Fragment._generate(self): |
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
270 yield kind, data, pos |
133
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
119
diff
changeset
|
271 yield END, self.tag, (None, -1, -1) |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
272 |
1 | 273 def generate(self): |
498 | 274 """Return a markup event stream for the fragment. |
275 | |
276 :rtype: `Stream` | |
277 """ | |
94
0f8800c46e21
Some bugfixes and minor performance improvements for the builder module.
cmlenz
parents:
91
diff
changeset
|
278 return Stream(self._generate()) |
1 | 279 |
280 | |
281 class ElementFactory(object): | |
28 | 282 """Factory for `Element` objects. |
283 | |
284 A new element is created simply by accessing a correspondingly named | |
285 attribute of the factory object: | |
286 | |
287 >>> factory = ElementFactory() | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
288 >>> print(factory.foo) |
28 | 289 <foo/> |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
290 >>> print(factory.foo(id=2)) |
28 | 291 <foo id="2"/> |
292 | |
119
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
293 Markup fragments (lists of nodes without a parent element) can be created |
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
294 by calling the factory: |
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
295 |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
296 >>> print(factory('Hello, ', factory.em('world'), '!')) |
119
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
297 Hello, <em>world</em>! |
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
298 |
28 | 299 A factory can also be bound to a specific namespace: |
300 | |
301 >>> factory = ElementFactory('http://www.w3.org/1999/xhtml') | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
302 >>> print(factory.html(lang="en")) |
410
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
408
diff
changeset
|
303 <html xmlns="http://www.w3.org/1999/xhtml" lang="en"/> |
28 | 304 |
305 The namespace for a specific element can be altered on an existing factory | |
306 by specifying the new namespace using item access: | |
307 | |
308 >>> factory = ElementFactory() | |
853
f33ecf3c319e
Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents:
750
diff
changeset
|
309 >>> print(factory.html(factory['http://www.w3.org/2000/svg'].g(id=3))) |
410
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
408
diff
changeset
|
310 <html><g xmlns="http://www.w3.org/2000/svg" id="3"/></html> |
28 | 311 |
312 Usually, the `ElementFactory` class is not be used directly. Rather, the | |
313 `tag` instance should be used to create elements. | |
314 """ | |
1 | 315 |
19
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
316 def __init__(self, namespace=None): |
28 | 317 """Create the factory, optionally bound to the given namespace. |
318 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
410
diff
changeset
|
319 :param namespace: the namespace URI for any created elements, or `None` |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
410
diff
changeset
|
320 for no namespace |
28 | 321 """ |
20 | 322 if namespace and not isinstance(namespace, Namespace): |
19
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
323 namespace = Namespace(namespace) |
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
324 self.namespace = namespace |
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
325 |
119
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
326 def __call__(self, *args): |
433 | 327 """Create a fragment that has the given positional arguments as child |
328 nodes. | |
329 | |
330 :return: the created `Fragment` | |
498 | 331 :rtype: `Fragment` |
433 | 332 """ |
119
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
333 return Fragment()(*args) |
cc2aee07f53b
Allow creating fragments from the `tag` object in `markup.builder`.
cmlenz
parents:
98
diff
changeset
|
334 |
19
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
335 def __getitem__(self, namespace): |
433 | 336 """Return a new factory that is bound to the specified namespace. |
337 | |
338 :param namespace: the namespace URI or `Namespace` object | |
339 :return: an `ElementFactory` that produces elements bound to the given | |
340 namespace | |
498 | 341 :rtype: `ElementFactory` |
433 | 342 """ |
19
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
343 return ElementFactory(namespace) |
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
344 |
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
345 def __getattr__(self, name): |
433 | 346 """Create an `Element` with the given name. |
347 | |
348 :param name: the tag name of the element to create | |
349 :return: an `Element` with the specified name | |
498 | 350 :rtype: `Element` |
433 | 351 """ |
19
704f10b06507
Enable `ElementFactory` to create namespaced elements.
cmlenz
parents:
17
diff
changeset
|
352 return Element(self.namespace and self.namespace[name] or name) |
1 | 353 |
354 | |
355 tag = ElementFactory() | |
498 | 356 """Global `ElementFactory` bound to the default namespace. |
357 | |
358 :type: `ElementFactory` | |
359 """ |