Mercurial > genshi > mirror
annotate genshi/core.py @ 666:050657e221d4 trunk
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
author | cmlenz |
---|---|
date | Tue, 11 Dec 2007 21:01:10 +0000 |
parents | 2910e2532a60 |
children | e45862282b7c 8ce1a80c8843 |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
408 | 3 # Copyright (C) 2006-2007 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 |
14 """Core classes for markup processing.""" | |
15 | |
634
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
16 from itertools import chain |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
17 import operator |
397
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
18 |
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
19 from genshi.util import plaintext, stripentities, striptags |
1 | 20 |
377
9aa6aa18fa35
Add `Attrs` class to `genshi.core.__all__`, so that it can be imported directly from the `genshi` package.
cmlenz
parents:
345
diff
changeset
|
21 __all__ = ['Stream', 'Markup', 'escape', 'unescape', 'Attrs', 'Namespace', |
9aa6aa18fa35
Add `Attrs` class to `genshi.core.__all__`, so that it can be imported directly from the `genshi` package.
cmlenz
parents:
345
diff
changeset
|
22 'QName'] |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
23 __docformat__ = 'restructuredtext en' |
1 | 24 |
25 | |
17
74cc70129d04
Refactoring to address #6: all match templates are now processed by a single filter, which means that match templates added by included templates are properly applied. A side effect of this refactoring is that `Context` objects may not be reused across multiple template processing runs.
cmlenz
parents:
10
diff
changeset
|
26 class StreamEventKind(str): |
397
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
27 """A kind of event on a markup stream.""" |
279
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
28 __slots__ = [] |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
29 _instances = {} |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
30 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
31 def __new__(cls, val): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
32 return cls._instances.setdefault(val, str.__new__(cls, val)) |
1 | 33 |
34 | |
35 class Stream(object): | |
36 """Represents a stream of markup events. | |
37 | |
38 This class is basically an iterator over the events. | |
39 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
40 Stream events are tuples of the form:: |
397
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
41 |
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
42 (kind, data, position) |
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
43 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
44 where ``kind`` is the event kind (such as `START`, `END`, `TEXT`, etc), |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
45 ``data`` depends on the kind of event, and ``position`` is a |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
46 ``(filename, line, offset)`` tuple that contains the location of the |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
47 original element or text in the input. If the original location is unknown, |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
48 ``position`` is ``(None, -1, -1)``. |
397
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
49 |
1 | 50 Also provided are ways to serialize the stream to text. The `serialize()` |
51 method will return an iterator over generated strings, while `render()` | |
52 returns the complete generated text at once. Both accept various parameters | |
53 that impact the way the stream is serialized. | |
54 """ | |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
55 __slots__ = ['events', 'serializer'] |
1 | 56 |
427 | 57 START = StreamEventKind('START') #: a start tag |
58 END = StreamEventKind('END') #: an end tag | |
59 TEXT = StreamEventKind('TEXT') #: literal text | |
460
75425671b437
Apply patch by Alec Thomas for processing XML declarations (#111). Thanks!
cmlenz
parents:
438
diff
changeset
|
60 XML_DECL = StreamEventKind('XML_DECL') #: XML declaration |
427 | 61 DOCTYPE = StreamEventKind('DOCTYPE') #: doctype declaration |
62 START_NS = StreamEventKind('START_NS') #: start namespace mapping | |
63 END_NS = StreamEventKind('END_NS') #: end namespace mapping | |
64 START_CDATA = StreamEventKind('START_CDATA') #: start CDATA section | |
65 END_CDATA = StreamEventKind('END_CDATA') #: end CDATA section | |
66 PI = StreamEventKind('PI') #: processing instruction | |
67 COMMENT = StreamEventKind('COMMENT') #: comment | |
1 | 68 |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
69 def __init__(self, events, serializer=None): |
1 | 70 """Initialize the stream with a sequence of markup events. |
71 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
72 :param events: a sequence or iterable providing the events |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
73 :param serializer: the default serialization method to use for this |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
74 stream |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
75 |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
76 :note: Changed in 0.5: added the `serializer` argument |
1 | 77 """ |
498 | 78 self.events = events #: The underlying iterable producing the events |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
79 self.serializer = serializer #: The default serializion method |
1 | 80 |
81 def __iter__(self): | |
82 return iter(self.events) | |
83 | |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
84 def __or__(self, function): |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
85 """Override the "bitwise or" operator to apply filters or serializers |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
86 to the stream, providing a syntax similar to pipes on Unix shells. |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
87 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
88 Assume the following stream produced by the `HTML` function: |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
89 |
230 | 90 >>> from genshi.input import HTML |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
91 >>> html = HTML('''<p onclick="alert('Whoa')">Hello, world!</p>''') |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
92 >>> print html |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
93 <p onclick="alert('Whoa')">Hello, world!</p> |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
94 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
95 A filter such as the HTML sanitizer can be applied to that stream using |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
96 the pipe notation as follows: |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
97 |
230 | 98 >>> from genshi.filters import HTMLSanitizer |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
99 >>> sanitizer = HTMLSanitizer() |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
100 >>> print html | sanitizer |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
101 <p>Hello, world!</p> |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
102 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
103 Filters can be any function that accepts and produces a stream (where |
397
31742fe6d47e
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
104 a stream is anything that iterates over events): |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
105 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
106 >>> def uppercase(stream): |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
107 ... for kind, data, pos in stream: |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
108 ... if kind is TEXT: |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
109 ... data = data.upper() |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
110 ... yield kind, data, pos |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
111 >>> print html | sanitizer | uppercase |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
112 <p>HELLO, WORLD!</p> |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
113 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
114 Serializers can also be used with this notation: |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
115 |
230 | 116 >>> from genshi.output import TextSerializer |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
117 >>> output = TextSerializer() |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
118 >>> print html | sanitizer | uppercase | output |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
119 HELLO, WORLD! |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
120 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
121 Commonly, serializers should be used at the end of the "pipeline"; |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
122 using them somewhere in the middle may produce unexpected results. |
498 | 123 |
124 :param function: the callable object that should be applied as a filter | |
125 :return: the filtered stream | |
126 :rtype: `Stream` | |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
127 """ |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
128 return Stream(_ensure(function(self)), serializer=self.serializer) |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
129 |
123
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
130 def filter(self, *filters): |
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
131 """Apply filters to the stream. |
113
d10fbba1d5e0
Removed the `sanitize()` method from the `Markup` class, and migrate the existing unit tests to `markup.tests.filters`. Provide a `Stream.filter()` method instead which can be used to conveniently apply a filter to a stream.
cmlenz
parents:
111
diff
changeset
|
132 |
123
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
133 This method returns a new stream with the given filters applied. The |
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
134 filters must be callables that accept the stream object as parameter, |
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
135 and return the filtered stream. |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
136 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
137 The call:: |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
138 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
139 stream.filter(filter1, filter2) |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
140 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
141 is equivalent to:: |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
142 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
143 stream | filter1 | filter2 |
498 | 144 |
145 :param filters: one or more callable objects that should be applied as | |
146 filters | |
147 :return: the filtered stream | |
148 :rtype: `Stream` | |
113
d10fbba1d5e0
Removed the `sanitize()` method from the `Markup` class, and migrate the existing unit tests to `markup.tests.filters`. Provide a `Stream.filter()` method instead which can be used to conveniently apply a filter to a stream.
cmlenz
parents:
111
diff
changeset
|
149 """ |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
150 return reduce(operator.or_, (self,) + filters) |
113
d10fbba1d5e0
Removed the `sanitize()` method from the `Markup` class, and migrate the existing unit tests to `markup.tests.filters`. Provide a `Stream.filter()` method instead which can be used to conveniently apply a filter to a stream.
cmlenz
parents:
111
diff
changeset
|
151 |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
152 def render(self, method=None, encoding='utf-8', **kwargs): |
1 | 153 """Return a string representation of the stream. |
154 | |
498 | 155 Any additional keyword arguments are passed to the serializer, and thus |
156 depend on the `method` parameter value. | |
157 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
158 :param method: determines how the stream is serialized; can be either |
200
5861f4446c26
Add serialization to plain text, based on cboos' patch. Closes #41.
cmlenz
parents:
182
diff
changeset
|
159 "xml", "xhtml", "html", "text", or a custom serializer |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
160 class; if `None`, the default serialization method of |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
161 the stream is used |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
162 :param encoding: how the output string should be encoded; if set to |
1 | 163 `None`, this method returns a `unicode` object |
498 | 164 :return: a `str` or `unicode` object |
165 :rtype: `basestring` | |
166 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer | |
1 | 167 """ |
462 | 168 from genshi.output import encode |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
169 if method is None: |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
170 method = self.serializer or 'xml' |
123
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
171 generator = self.serialize(method=method, **kwargs) |
462 | 172 return encode(generator, method=method, encoding=encoding) |
1 | 173 |
278
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
174 def select(self, path, namespaces=None, variables=None): |
1 | 175 """Return a new stream that contains the events matching the given |
176 XPath expression. | |
177 | |
576 | 178 >>> from genshi import HTML |
179 >>> stream = HTML('<doc><elem>foo</elem><elem>bar</elem></doc>') | |
180 >>> print stream.select('elem') | |
181 <elem>foo</elem><elem>bar</elem> | |
182 >>> print stream.select('elem/text()') | |
183 foobar | |
184 | |
185 Note that the outermost element of the stream becomes the *context | |
186 node* for the XPath test. That means that the expression "doc" would | |
187 not match anything in the example above, because it only tests against | |
188 child elements of the outermost element: | |
189 | |
190 >>> print stream.select('doc') | |
191 <BLANKLINE> | |
192 | |
193 You can use the "." expression to match the context node itself | |
194 (although that usually makes little sense): | |
195 | |
196 >>> print stream.select('.') | |
197 <doc><elem>foo</elem><elem>bar</elem></doc> | |
198 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
199 :param path: a string containing the XPath expression |
435 | 200 :param namespaces: mapping of namespace prefixes used in the path |
201 :param variables: mapping of variable names to values | |
202 :return: the selected substream | |
498 | 203 :rtype: `Stream` |
435 | 204 :raises PathSyntaxError: if the given path expression is invalid or not |
205 supported | |
1 | 206 """ |
230 | 207 from genshi.path import Path |
278
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
208 return Path(path).select(self, namespaces, variables) |
1 | 209 |
123
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
210 def serialize(self, method='xml', **kwargs): |
1 | 211 """Generate strings corresponding to a specific serialization of the |
212 stream. | |
213 | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
214 Unlike the `render()` method, this method is a generator that returns |
1 | 215 the serialized output incrementally, as opposed to returning a single |
216 string. | |
217 | |
498 | 218 Any additional keyword arguments are passed to the serializer, and thus |
219 depend on the `method` parameter value. | |
220 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
221 :param method: determines how the stream is serialized; can be either |
200
5861f4446c26
Add serialization to plain text, based on cboos' patch. Closes #41.
cmlenz
parents:
182
diff
changeset
|
222 "xml", "xhtml", "html", "text", or a custom serializer |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
223 class; if `None`, the default serialization method of |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
224 the stream is used |
498 | 225 :return: an iterator over the serialization results (`Markup` or |
226 `unicode` objects, depending on the serialization method) | |
227 :rtype: ``iterator`` | |
228 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer | |
1 | 229 """ |
462 | 230 from genshi.output import get_serializer |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
231 if method is None: |
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
593
diff
changeset
|
232 method = self.serializer or 'xml' |
462 | 233 return get_serializer(method, **kwargs)(_ensure(self)) |
1 | 234 |
235 def __str__(self): | |
236 return self.render() | |
237 | |
238 def __unicode__(self): | |
239 return self.render(encoding=None) | |
240 | |
241 | |
69 | 242 START = Stream.START |
243 END = Stream.END | |
244 TEXT = Stream.TEXT | |
460
75425671b437
Apply patch by Alec Thomas for processing XML declarations (#111). Thanks!
cmlenz
parents:
438
diff
changeset
|
245 XML_DECL = Stream.XML_DECL |
69 | 246 DOCTYPE = Stream.DOCTYPE |
247 START_NS = Stream.START_NS | |
248 END_NS = Stream.END_NS | |
143
3d4c214c979a
CDATA sections in XML input now appear as CDATA sections in the output. This should address the problem with escaping the contents of `<style>` and `<script>` elements, which would only get interpreted correctly if the output was served as `application/xhtml+xml`. Closes #24.
cmlenz
parents:
141
diff
changeset
|
249 START_CDATA = Stream.START_CDATA |
3d4c214c979a
CDATA sections in XML input now appear as CDATA sections in the output. This should address the problem with escaping the contents of `<style>` and `<script>` elements, which would only get interpreted correctly if the output was served as `application/xhtml+xml`. Closes #24.
cmlenz
parents:
141
diff
changeset
|
250 END_CDATA = Stream.END_CDATA |
69 | 251 PI = Stream.PI |
252 COMMENT = Stream.COMMENT | |
253 | |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
254 def _ensure(stream): |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
255 """Ensure that every item on the stream is actually a markup event.""" |
634
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
256 stream = iter(stream) |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
257 event = stream.next() |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
258 |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
259 # Check whether the iterable is a real markup event stream by examining the |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
260 # first item it yields; if it's not we'll need to do some conversion |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
261 if type(event) is not tuple or len(event) != 3: |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
262 for event in chain([event], stream): |
145
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
143
diff
changeset
|
263 if hasattr(event, 'totuple'): |
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
143
diff
changeset
|
264 event = event.totuple() |
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
143
diff
changeset
|
265 else: |
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
143
diff
changeset
|
266 event = TEXT, unicode(event), (None, -1, -1) |
634
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
267 yield event |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
268 return |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
269 |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
270 # This looks like a markup event stream, so we'll just pass it through |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
271 # unchanged |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
272 yield event |
2910e2532a60
Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents:
605
diff
changeset
|
273 for event in stream: |
145
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
143
diff
changeset
|
274 yield event |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
275 |
69 | 276 |
345 | 277 class Attrs(tuple): |
278 """Immutable sequence type that stores the attributes of an element. | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
279 |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
280 Ordering of the attributes is preserved, while access by name is also |
345 | 281 supported. |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
282 |
182
2f30ce3fb85e
Renamed `Attributes` to `Attrs` to reduce the verbosity.
cmlenz
parents:
172
diff
changeset
|
283 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')]) |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
284 >>> attrs |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
285 Attrs([('href', '#'), ('title', 'Foo')]) |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
286 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
287 >>> 'href' in attrs |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
288 True |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
289 >>> 'tabindex' in attrs |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
290 False |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
291 >>> attrs.get('title') |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
292 'Foo' |
345 | 293 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
294 Instances may not be manipulated directly. Instead, the operators ``|`` and |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
295 ``-`` can be used to produce new instances that have specific attributes |
345 | 296 added, replaced or removed. |
297 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
298 To remove an attribute, use the ``-`` operator. The right hand side can be |
345 | 299 either a string or a set/sequence of strings, identifying the name(s) of |
300 the attribute(s) to remove: | |
301 | |
302 >>> attrs - 'title' | |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
303 Attrs([('href', '#')]) |
345 | 304 >>> attrs - ('title', 'href') |
305 Attrs() | |
306 | |
307 The original instance is not modified, but the operator can of course be | |
308 used with an assignment: | |
309 | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
310 >>> attrs |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
311 Attrs([('href', '#'), ('title', 'Foo')]) |
345 | 312 >>> attrs -= 'title' |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
313 >>> attrs |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
314 Attrs([('href', '#')]) |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
315 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
316 To add a new attribute, use the ``|`` operator, where the right hand value |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
317 is a sequence of ``(name, value)`` tuples (which includes `Attrs` |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
318 instances): |
170
6b265e02d099
Allow initialization of `Attributes` with keyword arguments.
cmlenz
parents:
161
diff
changeset
|
319 |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
320 >>> attrs | [('title', 'Bar')] |
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
321 Attrs([('href', '#'), ('title', 'Bar')]) |
171
7fcf8e04514e
Follow-up to [214]: allow initializing `Attributes` with attribute names that contain dashes or conflict with a reserved word (such as ?class?.)
cmlenz
parents:
170
diff
changeset
|
322 |
345 | 323 If the attributes already contain an attribute with a given name, the value |
324 of that attribute is replaced: | |
171
7fcf8e04514e
Follow-up to [214]: allow initializing `Attributes` with attribute names that contain dashes or conflict with a reserved word (such as ?class?.)
cmlenz
parents:
170
diff
changeset
|
325 |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
326 >>> attrs | [('href', 'http://example.org/')] |
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
327 Attrs([('href', 'http://example.org/')]) |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
328 """ |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
329 __slots__ = [] |
1 | 330 |
331 def __contains__(self, name): | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
332 """Return whether the list includes an attribute with the specified |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
333 name. |
498 | 334 |
335 :return: `True` if the list includes the attribute | |
336 :rtype: `bool` | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
337 """ |
133
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
338 for attr, _ in self: |
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
339 if attr == name: |
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
340 return True |
1 | 341 |
345 | 342 def __getslice__(self, i, j): |
593 | 343 """Return a slice of the attributes list. |
344 | |
345 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')]) | |
346 >>> attrs[1:] | |
347 Attrs([('title', 'Foo')]) | |
348 """ | |
345 | 349 return Attrs(tuple.__getslice__(self, i, j)) |
350 | |
351 def __or__(self, attrs): | |
352 """Return a new instance that contains the attributes in `attrs` in | |
353 addition to any already existing attributes. | |
498 | 354 |
355 :return: a new instance with the merged attributes | |
356 :rtype: `Attrs` | |
345 | 357 """ |
358 repl = dict([(an, av) for an, av in attrs if an in self]) | |
359 return Attrs([(sn, repl.get(sn, sv)) for sn, sv in self] + | |
360 [(an, av) for an, av in attrs if an not in self]) | |
361 | |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
362 def __repr__(self): |
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
363 if not self: |
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
364 return 'Attrs()' |
345 | 365 return 'Attrs([%s])' % ', '.join([repr(item) for item in self]) |
366 | |
367 def __sub__(self, names): | |
368 """Return a new instance with all attributes with a name in `names` are | |
369 removed. | |
498 | 370 |
371 :param names: the names of the attributes to remove | |
372 :return: a new instance with the attribute removed | |
373 :rtype: `Attrs` | |
345 | 374 """ |
375 if isinstance(names, basestring): | |
376 names = (names,) | |
377 return Attrs([(name, val) for name, val in self if name not in names]) | |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
378 |
1 | 379 def get(self, name, default=None): |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
380 """Return the value of the attribute with the specified name, or the |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
381 value of the `default` parameter if no such attribute is found. |
435 | 382 |
383 :param name: the name of the attribute | |
384 :param default: the value to return when the attribute does not exist | |
385 :return: the attribute value, or the `default` value if that attribute | |
386 does not exist | |
498 | 387 :rtype: `object` |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
388 """ |
1 | 389 for attr, value in self: |
390 if attr == name: | |
391 return value | |
392 return default | |
393 | |
77
f5ec6d4a61e4
* Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents:
73
diff
changeset
|
394 def totuple(self): |
161
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
395 """Return the attributes as a markup event. |
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
396 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
397 The returned event is a `TEXT` event, the data is the value of all |
161
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
398 attributes joined together. |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
399 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
400 >>> Attrs([('href', '#'), ('title', 'Foo')]).totuple() |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
401 ('TEXT', u'#Foo', (None, -1, -1)) |
498 | 402 |
403 :return: a `TEXT` event | |
404 :rtype: `tuple` | |
161
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
405 """ |
77
f5ec6d4a61e4
* Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents:
73
diff
changeset
|
406 return TEXT, u''.join([x[1] for x in self]), (None, -1, -1) |
f5ec6d4a61e4
* Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents:
73
diff
changeset
|
407 |
1 | 408 |
409 class Markup(unicode): | |
410 """Marks a string as being safe for inclusion in HTML/XML output without | |
411 needing to be escaped. | |
412 """ | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
413 __slots__ = [] |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
414 |
27 | 415 def __new__(cls, text='', *args): |
1 | 416 if args: |
136 | 417 text %= tuple(map(escape, args)) |
27 | 418 return unicode.__new__(cls, text) |
1 | 419 |
420 def __add__(self, other): | |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
421 return Markup(unicode(self) + unicode(escape(other))) |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
422 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
423 def __radd__(self, other): |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
424 return Markup(unicode(escape(other)) + unicode(self)) |
1 | 425 |
426 def __mod__(self, args): | |
427 if not isinstance(args, (list, tuple)): | |
428 args = [args] | |
136 | 429 return Markup(unicode.__mod__(self, tuple(map(escape, args)))) |
1 | 430 |
431 def __mul__(self, num): | |
432 return Markup(unicode(self) * num) | |
433 | |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
434 def __rmul__(self, num): |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
435 return Markup(num * unicode(self)) |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
436 |
17
74cc70129d04
Refactoring to address #6: all match templates are now processed by a single filter, which means that match templates added by included templates are properly applied. A side effect of this refactoring is that `Context` objects may not be reused across multiple template processing runs.
cmlenz
parents:
10
diff
changeset
|
437 def __repr__(self): |
382
2682dabbcd04
* Added documentation for the various stream event kinds.
cmlenz
parents:
377
diff
changeset
|
438 return '<%s %r>' % (self.__class__.__name__, unicode(self)) |
17
74cc70129d04
Refactoring to address #6: all match templates are now processed by a single filter, which means that match templates added by included templates are properly applied. A side effect of this refactoring is that `Context` objects may not be reused across multiple template processing runs.
cmlenz
parents:
10
diff
changeset
|
439 |
54 | 440 def join(self, seq, escape_quotes=True): |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
441 """Return a `Markup` object which is the concatenation of the strings |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
442 in the given sequence, where this `Markup` object is the separator |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
443 between the joined elements. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
444 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
445 Any element in the sequence that is not a `Markup` instance is |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
446 automatically escaped. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
447 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
448 :param seq: the sequence of strings to join |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
449 :param escape_quotes: whether double quote characters in the elements |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
450 should be escaped |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
451 :return: the joined `Markup` object |
498 | 452 :rtype: `Markup` |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
453 :see: `escape` |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
454 """ |
54 | 455 return Markup(unicode(self).join([escape(item, quotes=escape_quotes) |
34 | 456 for item in seq])) |
1 | 457 |
458 def escape(cls, text, quotes=True): | |
459 """Create a Markup instance from a string and escape special characters | |
460 it may contain (<, >, & and \"). | |
461 | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
462 >>> escape('"1 < 2"') |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
463 <Markup u'"1 < 2"'> |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
464 |
1 | 465 If the `quotes` parameter is set to `False`, the \" character is left |
466 as is. Escaping quotes is generally only required for strings that are | |
467 to be used in attribute values. | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
468 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
469 >>> escape('"1 < 2"', quotes=False) |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
470 <Markup u'"1 < 2"'> |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
471 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
472 :param text: the text to escape |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
473 :param quotes: if ``True``, double quote characters are escaped in |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
474 addition to the other special characters |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
475 :return: the escaped `Markup` string |
498 | 476 :rtype: `Markup` |
1 | 477 """ |
73 | 478 if not text: |
479 return cls() | |
480 if type(text) is cls: | |
1 | 481 return text |
73 | 482 text = unicode(text).replace('&', '&') \ |
483 .replace('<', '<') \ | |
484 .replace('>', '>') | |
1 | 485 if quotes: |
486 text = text.replace('"', '"') | |
487 return cls(text) | |
488 escape = classmethod(escape) | |
489 | |
490 def unescape(self): | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
491 """Reverse-escapes &, <, >, and \" and returns a `unicode` object. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
492 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
493 >>> Markup('1 < 2').unescape() |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
494 u'1 < 2' |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
495 |
498 | 496 :return: the unescaped string |
497 :rtype: `unicode` | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
498 :see: `genshi.core.unescape` |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
499 """ |
1 | 500 if not self: |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
501 return u'' |
1 | 502 return unicode(self).replace('"', '"') \ |
503 .replace('>', '>') \ | |
504 .replace('<', '<') \ | |
505 .replace('&', '&') | |
506 | |
116 | 507 def stripentities(self, keepxmlentities=False): |
508 """Return a copy of the text with any character or numeric entities | |
509 replaced by the equivalent UTF-8 characters. | |
510 | |
511 If the `keepxmlentities` parameter is provided and evaluates to `True`, | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
512 the core XML entities (``&``, ``'``, ``>``, ``<`` and |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
513 ``"``) are not stripped. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
514 |
498 | 515 :return: a `Markup` instance with entities removed |
516 :rtype: `Markup` | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
517 :see: `genshi.util.stripentities` |
6 | 518 """ |
116 | 519 return Markup(stripentities(self, keepxmlentities=keepxmlentities)) |
520 | |
521 def striptags(self): | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
522 """Return a copy of the text with all XML/HTML tags removed. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
523 |
498 | 524 :return: a `Markup` instance with all tags removed |
525 :rtype: `Markup` | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
526 :see: `genshi.util.striptags` |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
527 """ |
116 | 528 return Markup(striptags(self)) |
1 | 529 |
530 | |
541 | 531 try: |
532 from genshi._speedups import Markup | |
533 except ImportError: | |
534 pass # just use the Python implementation | |
535 | |
1 | 536 escape = Markup.escape |
537 | |
538 def unescape(text): | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
539 """Reverse-escapes &, <, >, and \" and returns a `unicode` object. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
540 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
541 >>> unescape(Markup('1 < 2')) |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
542 u'1 < 2' |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
543 |
498 | 544 If the provided `text` object is not a `Markup` instance, it is returned |
545 unchanged. | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
546 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
547 >>> unescape('1 < 2') |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
548 '1 < 2' |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
549 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
550 :param text: the text to unescape |
498 | 551 :return: the unescsaped string |
552 :rtype: `unicode` | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
553 """ |
1 | 554 if not isinstance(text, Markup): |
555 return text | |
556 return text.unescape() | |
557 | |
558 | |
559 class Namespace(object): | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
560 """Utility class creating and testing elements with a namespace. |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
561 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
562 Internally, namespace URIs are encoded in the `QName` of any element or |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
563 attribute, the namespace URI being enclosed in curly braces. This class |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
564 helps create and test these strings. |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
565 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
566 A `Namespace` object is instantiated with the namespace URI. |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
567 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
568 >>> html = Namespace('http://www.w3.org/1999/xhtml') |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
569 >>> html |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
570 <Namespace "http://www.w3.org/1999/xhtml"> |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
571 >>> html.uri |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
572 u'http://www.w3.org/1999/xhtml' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
573 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
574 The `Namespace` object can than be used to generate `QName` objects with |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
575 that namespace: |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
576 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
577 >>> html.body |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
578 QName(u'http://www.w3.org/1999/xhtml}body') |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
579 >>> html.body.localname |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
580 u'body' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
581 >>> html.body.namespace |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
582 u'http://www.w3.org/1999/xhtml' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
583 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
584 The same works using item access notation, which is useful for element or |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
585 attribute names that are not valid Python identifiers: |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
586 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
587 >>> html['body'] |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
588 QName(u'http://www.w3.org/1999/xhtml}body') |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
589 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
590 A `Namespace` object can also be used to test whether a specific `QName` |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
591 belongs to that namespace using the ``in`` operator: |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
592 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
593 >>> qname = html.body |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
594 >>> qname in html |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
595 True |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
596 >>> qname in Namespace('http://www.w3.org/2002/06/xhtml2') |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
597 False |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
598 """ |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
599 def __new__(cls, uri): |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
600 if type(uri) is cls: |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
601 return uri |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
602 return object.__new__(cls, uri) |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
603 |
279
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
604 def __getnewargs__(self): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
605 return (self.uri,) |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
606 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
607 def __getstate__(self): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
608 return self.uri |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
609 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
610 def __setstate__(self, uri): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
611 self.uri = uri |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
612 |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
613 def __init__(self, uri): |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
614 self.uri = unicode(uri) |
1 | 615 |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
616 def __contains__(self, qname): |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
617 return qname.namespace == self.uri |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
618 |
278
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
619 def __ne__(self, other): |
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
620 return not self == other |
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
621 |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
622 def __eq__(self, other): |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
623 if isinstance(other, Namespace): |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
624 return self.uri == other.uri |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
625 return self.uri == other |
1 | 626 |
627 def __getitem__(self, name): | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
628 return QName(self.uri + u'}' + name) |
1 | 629 __getattr__ = __getitem__ |
630 | |
631 def __repr__(self): | |
632 return '<Namespace "%s">' % self.uri | |
633 | |
634 def __str__(self): | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
635 return self.uri.encode('utf-8') |
1 | 636 |
637 def __unicode__(self): | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
638 return self.uri |
1 | 639 |
640 | |
147
a4a0ca41b6ad
Use `xmlcharrefreplace` when encoding the output in `Stream.render()`, so that encoding the output to legacy encodings such as ASCII or ISO-8859-1 should always work.
cmlenz
parents:
145
diff
changeset
|
641 # The namespace used by attributes such as xml:lang and xml:space |
141
520a5b7dd6d2
* No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents:
140
diff
changeset
|
642 XML_NAMESPACE = Namespace('http://www.w3.org/XML/1998/namespace') |
520a5b7dd6d2
* No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents:
140
diff
changeset
|
643 |
520a5b7dd6d2
* No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents:
140
diff
changeset
|
644 |
1 | 645 class QName(unicode): |
646 """A qualified element or attribute name. | |
647 | |
648 The unicode value of instances of this class contains the qualified name of | |
666
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
649 the element or attribute, in the form ``{namespace-uri}local-name``. The |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
650 namespace URI can be obtained through the additional `namespace` attribute, |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
651 while the local name can be accessed through the `localname` attribute. |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
652 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
653 >>> qname = QName('foo') |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
654 >>> qname |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
655 QName(u'foo') |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
656 >>> qname.localname |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
657 u'foo' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
658 >>> qname.namespace |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
659 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
660 >>> qname = QName('http://www.w3.org/1999/xhtml}body') |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
661 >>> qname |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
662 QName(u'http://www.w3.org/1999/xhtml}body') |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
663 >>> qname.localname |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
664 u'body' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
665 >>> qname.namespace |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
666 u'http://www.w3.org/1999/xhtml' |
1 | 667 """ |
668 __slots__ = ['namespace', 'localname'] | |
669 | |
670 def __new__(cls, qname): | |
666
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
671 """Create the `QName` instance. |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
672 |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
673 :param qname: the qualified name as a string of the form |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
674 ``{namespace-uri}local-name``, where the leading curly |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
675 brace is optional |
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
676 """ |
100 | 677 if type(qname) is cls: |
1 | 678 return qname |
679 | |
666
050657e221d4
`QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents:
634
diff
changeset
|
680 parts = qname.lstrip(u'{').split(u'}', 1) |
100 | 681 if len(parts) > 1: |
136 | 682 self = unicode.__new__(cls, u'{%s' % qname) |
683 self.namespace, self.localname = map(unicode, parts) | |
1 | 684 else: |
685 self = unicode.__new__(cls, qname) | |
136 | 686 self.namespace, self.localname = None, unicode(qname) |
1 | 687 return self |
279
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
688 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
689 def __getnewargs__(self): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
690 return (self.lstrip('{'),) |
326
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
691 |
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
692 def __repr__(self): |
f999da894391
Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents:
279
diff
changeset
|
693 return 'QName(%s)' % unicode.__repr__(self.lstrip('{')) |