Mercurial > genshi > genshi-test
annotate genshi/core.py @ 634:60a1fb39f915
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.
author | cmlenz |
---|---|
date | Wed, 05 Sep 2007 12:45:04 +0000 |
parents | bc5faca93699 |
children | 9729855cacf4 |
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
60a1fb39f915
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
516a6cae0aa8
* 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
d6e9170c5ccc
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
18 |
d6e9170c5ccc
* 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
79a7db5177e9
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', |
79a7db5177e9
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
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
23 __docformat__ = 'restructuredtext en' |
1 | 24 |
25 | |
17
ad63ad459524
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
d6e9170c5ccc
* 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
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
28 __slots__ = [] |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
29 _instances = {} |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
30 |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
31 def __new__(cls, val): |
4b5b4653d41e
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
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
40 Stream events are tuples of the form:: |
397
d6e9170c5ccc
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
41 |
d6e9170c5ccc
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
42 (kind, data, position) |
d6e9170c5ccc
* Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents:
382
diff
changeset
|
43 |
425
5b248708bbed
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), |
5b248708bbed
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 |
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
46 ``(filename, line, offset)`` tuple that contains the location of the |
5b248708bbed
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, |
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
48 ``position`` is ``(None, -1, -1)``. |
397
d6e9170c5ccc
* 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
bc5faca93699
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
6b5544bb5a99
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
bc5faca93699
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
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
72 :param events: a sequence or iterable providing the events |
605
bc5faca93699
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 |
bc5faca93699
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 |
bc5faca93699
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 |
bc5faca93699
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
bc5faca93699
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
516a6cae0aa8
* 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): |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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. |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
87 |
516a6cae0aa8
* 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: |
516a6cae0aa8
* 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
516a6cae0aa8
* 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>''') |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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> |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
94 |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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: |
516a6cae0aa8
* 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
516a6cae0aa8
* 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() |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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> |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
102 |
516a6cae0aa8
* 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
d6e9170c5ccc
* 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
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
105 |
516a6cae0aa8
* 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): |
516a6cae0aa8
* 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: |
516a6cae0aa8
* 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: |
516a6cae0aa8
* 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() |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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> |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
113 |
516a6cae0aa8
* 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: |
516a6cae0aa8
* 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
516a6cae0aa8
* 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() |
516a6cae0aa8
* 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 |
516a6cae0aa8
* 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! |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
120 |
516a6cae0aa8
* 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"; |
516a6cae0aa8
* 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
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
127 """ |
605
bc5faca93699
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
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
129 |
123
93bbdcf9428b
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): |
93bbdcf9428b
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
e815c2c07572
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
93bbdcf9428b
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 |
93bbdcf9428b
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, |
93bbdcf9428b
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
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
136 |
425
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
137 The call:: |
204
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
138 |
516a6cae0aa8
* 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) |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
140 |
425
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
141 is equivalent to:: |
204
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
142 |
516a6cae0aa8
* 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
e815c2c07572
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
516a6cae0aa8
* 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
e815c2c07572
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
bc5faca93699
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
5b248708bbed
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
50eab0469148
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
bc5faca93699
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 |
bc5faca93699
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
5b248708bbed
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
bc5faca93699
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: |
bc5faca93699
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
93bbdcf9428b
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
8de2620504b9
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
5b248708bbed
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
8de2620504b9
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
93bbdcf9428b
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
4cbebb15a834
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
5b248708bbed
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
50eab0469148
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
bc5faca93699
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 |
bc5faca93699
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
bc5faca93699
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: |
bc5faca93699
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
6b5544bb5a99
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
ef761afcedff
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 |
ef761afcedff
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
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
254 def _ensure(stream): |
8a4d9064f363
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
60a1fb39f915
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) |
60a1fb39f915
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() |
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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: |
60a1fb39f915
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
56d534eb53f9
* 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'): |
56d534eb53f9
* 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() |
56d534eb53f9
* 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: |
56d534eb53f9
* 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
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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 |
60a1fb39f915
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
56d534eb53f9
* 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
8a4d9064f363
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
279 |
434
e065d7906b68
* 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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
282 |
182
41db0260ebb1
Renamed `Attributes` to `Attrs` to reduce the verbosity.
cmlenz
parents:
172
diff
changeset
|
283 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')]) |
18
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
284 >>> attrs |
403
32b283e1d310
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
286 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
287 >>> 'href' in attrs |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
288 True |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
289 >>> 'tabindex' in attrs |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
290 False |
403
32b283e1d310
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
4cbebb15a834
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
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
294 Instances may not be manipulated directly. Instead, the operators ``|`` and |
5b248708bbed
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
5b248708bbed
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
32b283e1d310
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
310 >>> attrs |
403
32b283e1d310
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
313 >>> attrs |
403
32b283e1d310
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
315 |
425
5b248708bbed
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 |
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
317 is a sequence of ``(name, value)`` tuples (which includes `Attrs` |
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
318 instances): |
170
f1ac0510d392
Allow initialization of `Attributes` with keyword arguments.
cmlenz
parents:
161
diff
changeset
|
319 |
403
32b283e1d310
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')] |
32b283e1d310
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
34e0455ada92
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
34e0455ada92
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
32b283e1d310
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/')] |
32b283e1d310
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
328 """ |
4cbebb15a834
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
4cbebb15a834
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 |
4cbebb15a834
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
337 """ |
133
b9a0031d4bbb
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
338 for attr, _ in self: |
b9a0031d4bbb
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
339 if attr == name: |
b9a0031d4bbb
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
08ada6b4b767
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): |
08ada6b4b767
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: |
08ada6b4b767
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
08ada6b4b767
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
4cbebb15a834
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 |
4cbebb15a834
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
4cbebb15a834
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
f1aa49c759b2
* Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents:
73
diff
changeset
|
394 def totuple(self): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
395 """Return the attributes as a markup event. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
396 |
425
5b248708bbed
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
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
398 attributes joined together. |
434
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
399 |
e065d7906b68
* 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() |
e065d7906b68
* 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
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
405 """ |
77
f1aa49c759b2
* 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) |
f1aa49c759b2
* 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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
413 __slots__ = [] |
4cbebb15a834
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
516a6cae0aa8
* 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))) |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
422 |
516a6cae0aa8
* 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): |
516a6cae0aa8
* 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
516a6cae0aa8
* 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): |
516a6cae0aa8
* 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)) |
516a6cae0aa8
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
436 |
17
ad63ad459524
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
d7da3fba7faf
* Added documentation for the various stream event kinds.
cmlenz
parents:
377
diff
changeset
|
438 return '<%s %r>' % (self.__class__.__name__, unicode(self)) |
17
ad63ad459524
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
e065d7906b68
* 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 |
e065d7906b68
* 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 |
e065d7906b68
* 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. |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
444 |
e065d7906b68
* 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 |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
446 automatically escaped. |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
447 |
e065d7906b68
* 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 |
e065d7906b68
* 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 |
e065d7906b68
* 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 |
e065d7906b68
* 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
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
453 :see: `escape` |
e065d7906b68
* 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
e065d7906b68
* 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"') |
e065d7906b68
* 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"'> |
e065d7906b68
* 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
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
468 |
e065d7906b68
* 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) |
e065d7906b68
* 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"'> |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
471 |
e065d7906b68
* 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 |
e065d7906b68
* 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 |
e065d7906b68
* 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 |
e065d7906b68
* 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
e065d7906b68
* 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. |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
492 |
e065d7906b68
* 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() |
e065d7906b68
* 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' |
e065d7906b68
* 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
e065d7906b68
* 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` |
e065d7906b68
* 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
4cbebb15a834
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
e065d7906b68
* 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 |
e065d7906b68
* 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. |
e065d7906b68
* 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
e065d7906b68
* 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
e065d7906b68
* 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. |
e065d7906b68
* 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
e065d7906b68
* 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` |
e065d7906b68
* 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
e065d7906b68
* 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. |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
540 |
e065d7906b68
* 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')) |
e065d7906b68
* 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' |
e065d7906b68
* 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
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
546 |
e065d7906b68
* 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') |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
548 '1 < 2' |
e065d7906b68
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
549 |
e065d7906b68
* 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
e065d7906b68
* 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
4cbebb15a834
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. |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
561 |
4cbebb15a834
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 |
4cbebb15a834
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 |
4cbebb15a834
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. |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
565 |
4cbebb15a834
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. |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
567 |
4cbebb15a834
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') |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
569 >>> html |
4cbebb15a834
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"> |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
571 >>> html.uri |
4cbebb15a834
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' |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
573 |
4cbebb15a834
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 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
575 that namespace: |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
576 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
577 >>> html.body |
326
08ada6b4b767
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
579 >>> html.body.localname |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
580 u'body' |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
581 >>> html.body.namespace |
4cbebb15a834
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' |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
583 |
4cbebb15a834
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 |
4cbebb15a834
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: |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
586 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
587 >>> html['body'] |
326
08ada6b4b767
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
589 |
4cbebb15a834
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
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
591 belongs to that namespace using the ``in`` operator: |
18
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
592 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
593 >>> qname = html.body |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
594 >>> qname in html |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
595 True |
4cbebb15a834
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') |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
597 False |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
598 """ |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
599 def __new__(cls, uri): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
600 if type(uri) is cls: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
601 return uri |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
602 return object.__new__(cls, uri) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
603 |
279
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
604 def __getnewargs__(self): |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
605 return (self.uri,) |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
606 |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
607 def __getstate__(self): |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
608 return self.uri |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
609 |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
610 def __setstate__(self, uri): |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
611 self.uri = uri |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
612 |
18
4cbebb15a834
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): |
4cbebb15a834
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
4cbebb15a834
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): |
4cbebb15a834
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 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
618 |
278
8de2620504b9
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
619 def __ne__(self, other): |
8de2620504b9
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
620 return not self == other |
8de2620504b9
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
621 |
18
4cbebb15a834
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): |
4cbebb15a834
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): |
4cbebb15a834
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 |
4cbebb15a834
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
4cbebb15a834
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
4cbebb15a834
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
4cbebb15a834
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
f7fb556f2678
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
b3ceaa35fb6b
* 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') |
b3ceaa35fb6b
* No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents:
140
diff
changeset
|
643 |
b3ceaa35fb6b
* 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 | |
425
5b248708bbed
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
649 the element or attribute, in the form ``{namespace}localname``. The namespace |
1 | 650 URI can be obtained through the additional `namespace` attribute, while the |
651 local name can be accessed through the `localname` attribute. | |
18
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
652 |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
653 >>> qname = QName('foo') |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
654 >>> qname |
326
08ada6b4b767
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
656 >>> qname.localname |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
657 u'foo' |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
658 >>> qname.namespace |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
659 |
4cbebb15a834
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') |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
661 >>> qname |
326
08ada6b4b767
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
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
663 >>> qname.localname |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
664 u'body' |
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
665 >>> qname.namespace |
4cbebb15a834
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): | |
100 | 671 if type(qname) is cls: |
1 | 672 return qname |
673 | |
18
4cbebb15a834
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
674 parts = qname.split(u'}', 1) |
100 | 675 if len(parts) > 1: |
136 | 676 self = unicode.__new__(cls, u'{%s' % qname) |
677 self.namespace, self.localname = map(unicode, parts) | |
1 | 678 else: |
679 self = unicode.__new__(cls, qname) | |
136 | 680 self.namespace, self.localname = None, unicode(qname) |
1 | 681 return self |
279
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
682 |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
683 def __getnewargs__(self): |
4b5b4653d41e
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
684 return (self.lstrip('{'),) |
326
08ada6b4b767
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
|
685 |
08ada6b4b767
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
|
686 def __repr__(self): |
08ada6b4b767
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
|
687 return 'QName(%s)' % unicode.__repr__(self.lstrip('{')) |