Mercurial > genshi > mirror
annotate genshi/core.py @ 703:af57b12e3dd2 experimental-match-fastpaths
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
author | aflett |
---|---|
date | Mon, 31 Mar 2008 22:47:50 +0000 |
parents | 8ce1a80c8843 |
children | 5420fe9d99a9 |
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 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
152 def render(self, method=None, encoding='utf-8', out=None, **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 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
164 :param out: a file-like object that the output should be written to |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
165 instead of being returned as one big string; note that if |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
166 this is a file or socket (or similar), the `encoding` must |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
167 not be `None` (that is, the output must be encoded) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
168 :return: a `str` or `unicode` object (depending on the `encoding` |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
169 parameter), or `None` if the `out` parameter is provided |
498 | 170 :rtype: `basestring` |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
171 |
498 | 172 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
173 :note: Changed in 0.5: added the `out` parameter |
1 | 174 """ |
462 | 175 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
|
176 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
|
177 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
|
178 generator = self.serialize(method=method, **kwargs) |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
685
diff
changeset
|
179 return encode(generator, method=method, encoding=encoding, out=out) |
1 | 180 |
278
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
181 def select(self, path, namespaces=None, variables=None): |
1 | 182 """Return a new stream that contains the events matching the given |
183 XPath expression. | |
184 | |
576 | 185 >>> from genshi import HTML |
186 >>> stream = HTML('<doc><elem>foo</elem><elem>bar</elem></doc>') | |
187 >>> print stream.select('elem') | |
188 <elem>foo</elem><elem>bar</elem> | |
189 >>> print stream.select('elem/text()') | |
190 foobar | |
191 | |
192 Note that the outermost element of the stream becomes the *context | |
193 node* for the XPath test. That means that the expression "doc" would | |
194 not match anything in the example above, because it only tests against | |
195 child elements of the outermost element: | |
196 | |
197 >>> print stream.select('doc') | |
198 <BLANKLINE> | |
199 | |
200 You can use the "." expression to match the context node itself | |
201 (although that usually makes little sense): | |
202 | |
203 >>> print stream.select('.') | |
204 <doc><elem>foo</elem><elem>bar</elem></doc> | |
205 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
206 :param path: a string containing the XPath expression |
435 | 207 :param namespaces: mapping of namespace prefixes used in the path |
208 :param variables: mapping of variable names to values | |
209 :return: the selected substream | |
498 | 210 :rtype: `Stream` |
435 | 211 :raises PathSyntaxError: if the given path expression is invalid or not |
212 supported | |
1 | 213 """ |
230 | 214 from genshi.path import Path |
278
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
215 return Path(path).select(self, namespaces, variables) |
1 | 216 |
123
10279d2eeec9
Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents:
116
diff
changeset
|
217 def serialize(self, method='xml', **kwargs): |
1 | 218 """Generate strings corresponding to a specific serialization of the |
219 stream. | |
220 | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
221 Unlike the `render()` method, this method is a generator that returns |
1 | 222 the serialized output incrementally, as opposed to returning a single |
223 string. | |
224 | |
498 | 225 Any additional keyword arguments are passed to the serializer, and thus |
226 depend on the `method` parameter value. | |
227 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
228 :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
|
229 "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
|
230 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
|
231 the stream is used |
498 | 232 :return: an iterator over the serialization results (`Markup` or |
233 `unicode` objects, depending on the serialization method) | |
234 :rtype: ``iterator`` | |
235 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer | |
1 | 236 """ |
462 | 237 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
|
238 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
|
239 method = self.serializer or 'xml' |
462 | 240 return get_serializer(method, **kwargs)(_ensure(self)) |
1 | 241 |
242 def __str__(self): | |
243 return self.render() | |
244 | |
245 def __unicode__(self): | |
246 return self.render(encoding=None) | |
247 | |
248 | |
69 | 249 START = Stream.START |
250 END = Stream.END | |
251 TEXT = Stream.TEXT | |
460
75425671b437
Apply patch by Alec Thomas for processing XML declarations (#111). Thanks!
cmlenz
parents:
438
diff
changeset
|
252 XML_DECL = Stream.XML_DECL |
69 | 253 DOCTYPE = Stream.DOCTYPE |
254 START_NS = Stream.START_NS | |
255 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
|
256 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
|
257 END_CDATA = Stream.END_CDATA |
69 | 258 PI = Stream.PI |
259 COMMENT = Stream.COMMENT | |
260 | |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
261 def _ensure(stream): |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
262 """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
|
263 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
|
264 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
|
265 |
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
|
266 # 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
|
267 # 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
|
268 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
|
269 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
|
270 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
|
271 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
|
272 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
|
273 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
|
274 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
|
275 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
|
276 |
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
|
277 # 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
|
278 # 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
|
279 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
|
280 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
|
281 yield event |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
100
diff
changeset
|
282 |
69 | 283 |
345 | 284 class Attrs(tuple): |
285 """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
|
286 |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
287 Ordering of the attributes is preserved, while access by name is also |
345 | 288 supported. |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
289 |
182
2f30ce3fb85e
Renamed `Attributes` to `Attrs` to reduce the verbosity.
cmlenz
parents:
172
diff
changeset
|
290 >>> 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
|
291 >>> 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
|
292 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
|
293 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
294 >>> 'href' in attrs |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
295 True |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
296 >>> 'tabindex' in attrs |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
297 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
|
298 >>> 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
|
299 'Foo' |
345 | 300 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
301 Instances may not be manipulated directly. Instead, the operators ``|`` and |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
302 ``-`` can be used to produce new instances that have specific attributes |
345 | 303 added, replaced or removed. |
304 | |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
305 To remove an attribute, use the ``-`` operator. The right hand side can be |
345 | 306 either a string or a set/sequence of strings, identifying the name(s) of |
307 the attribute(s) to remove: | |
308 | |
309 >>> 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
|
310 Attrs([('href', '#')]) |
345 | 311 >>> attrs - ('title', 'href') |
312 Attrs() | |
313 | |
314 The original instance is not modified, but the operator can of course be | |
315 used with an assignment: | |
316 | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
317 >>> 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
|
318 Attrs([('href', '#'), ('title', 'Foo')]) |
345 | 319 >>> attrs -= 'title' |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
320 >>> 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
|
321 Attrs([('href', '#')]) |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
322 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
323 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
|
324 is a sequence of ``(name, value)`` tuples (which includes `Attrs` |
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
325 instances): |
170
6b265e02d099
Allow initialization of `Attributes` with keyword arguments.
cmlenz
parents:
161
diff
changeset
|
326 |
403
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 | [('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
|
328 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
|
329 |
345 | 330 If the attributes already contain an attribute with a given name, the value |
331 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
|
332 |
403
228907abb726
Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents:
397
diff
changeset
|
333 >>> 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
|
334 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
|
335 """ |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
336 __slots__ = [] |
1 | 337 |
338 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
|
339 """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
|
340 name. |
498 | 341 |
342 :return: `True` if the list includes the attribute | |
343 :rtype: `bool` | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
344 """ |
133
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
345 for attr, _ in self: |
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
346 if attr == name: |
79f445396cd7
Minor cleanup and performance improvement for the builder module.
cmlenz
parents:
123
diff
changeset
|
347 return True |
1 | 348 |
345 | 349 def __getslice__(self, i, j): |
593 | 350 """Return a slice of the attributes list. |
351 | |
352 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')]) | |
353 >>> attrs[1:] | |
354 Attrs([('title', 'Foo')]) | |
355 """ | |
345 | 356 return Attrs(tuple.__getslice__(self, i, j)) |
357 | |
358 def __or__(self, attrs): | |
359 """Return a new instance that contains the attributes in `attrs` in | |
360 addition to any already existing attributes. | |
498 | 361 |
362 :return: a new instance with the merged attributes | |
363 :rtype: `Attrs` | |
345 | 364 """ |
365 repl = dict([(an, av) for an, av in attrs if an in self]) | |
366 return Attrs([(sn, repl.get(sn, sv)) for sn, sv in self] + | |
367 [(an, av) for an, av in attrs if an not in self]) | |
368 | |
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
|
369 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
|
370 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
|
371 return 'Attrs()' |
345 | 372 return 'Attrs([%s])' % ', '.join([repr(item) for item in self]) |
373 | |
374 def __sub__(self, names): | |
375 """Return a new instance with all attributes with a name in `names` are | |
376 removed. | |
498 | 377 |
378 :param names: the names of the attributes to remove | |
379 :return: a new instance with the attribute removed | |
380 :rtype: `Attrs` | |
345 | 381 """ |
382 if isinstance(names, basestring): | |
383 names = (names,) | |
384 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
|
385 |
1 | 386 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
|
387 """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
|
388 value of the `default` parameter if no such attribute is found. |
435 | 389 |
390 :param name: the name of the attribute | |
391 :param default: the value to return when the attribute does not exist | |
392 :return: the attribute value, or the `default` value if that attribute | |
393 does not exist | |
498 | 394 :rtype: `object` |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
395 """ |
1 | 396 for attr, value in self: |
397 if attr == name: | |
398 return value | |
399 return default | |
400 | |
77
f5ec6d4a61e4
* Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents:
73
diff
changeset
|
401 def totuple(self): |
161
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
402 """Return the attributes as a markup event. |
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
403 |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
408
diff
changeset
|
404 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
|
405 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
|
406 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
407 >>> 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
|
408 ('TEXT', u'#Foo', (None, -1, -1)) |
498 | 409 |
410 :return: a `TEXT` event | |
411 :rtype: `tuple` | |
161
7b1f07496bf7
Various docstring additions and other cosmetic changes.
cmlenz
parents:
147
diff
changeset
|
412 """ |
77
f5ec6d4a61e4
* Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents:
73
diff
changeset
|
413 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
|
414 |
1 | 415 |
416 class Markup(unicode): | |
417 """Marks a string as being safe for inclusion in HTML/XML output without | |
418 needing to be escaped. | |
419 """ | |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
420 __slots__ = [] |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
421 |
27 | 422 def __new__(cls, text='', *args): |
1 | 423 if args: |
136 | 424 text %= tuple(map(escape, args)) |
27 | 425 return unicode.__new__(cls, text) |
1 | 426 |
427 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
|
428 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
|
429 |
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
430 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
|
431 return Markup(unicode(escape(other)) + unicode(self)) |
1 | 432 |
433 def __mod__(self, args): | |
434 if not isinstance(args, (list, tuple)): | |
435 args = [args] | |
136 | 436 return Markup(unicode.__mod__(self, tuple(map(escape, args)))) |
1 | 437 |
438 def __mul__(self, num): | |
439 return Markup(unicode(self) * num) | |
440 | |
204
51d4101f49ca
* Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents:
200
diff
changeset
|
441 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
|
442 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
|
443 |
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
|
444 def __repr__(self): |
382
2682dabbcd04
* Added documentation for the various stream event kinds.
cmlenz
parents:
377
diff
changeset
|
445 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
|
446 |
54 | 447 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
|
448 """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
|
449 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
|
450 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
|
451 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
452 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
|
453 automatically escaped. |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
454 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
455 :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
|
456 :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
|
457 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
|
458 :return: the joined `Markup` object |
498 | 459 :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
|
460 :see: `escape` |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
461 """ |
54 | 462 return Markup(unicode(self).join([escape(item, quotes=escape_quotes) |
34 | 463 for item in seq])) |
1 | 464 |
465 def escape(cls, text, quotes=True): | |
466 """Create a Markup instance from a string and escape special characters | |
467 it may contain (<, >, & and \"). | |
468 | |
434
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"') |
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 |
1 | 472 If the `quotes` parameter is set to `False`, the \" character is left |
473 as is. Escaping quotes is generally only required for strings that are | |
474 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
|
475 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
476 >>> 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
|
477 <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
|
478 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
479 :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
|
480 :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
|
481 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
|
482 :return: the escaped `Markup` string |
498 | 483 :rtype: `Markup` |
1 | 484 """ |
73 | 485 if not text: |
486 return cls() | |
487 if type(text) is cls: | |
1 | 488 return text |
73 | 489 text = unicode(text).replace('&', '&') \ |
490 .replace('<', '<') \ | |
491 .replace('>', '>') | |
1 | 492 if quotes: |
493 text = text.replace('"', '"') | |
494 return cls(text) | |
495 escape = classmethod(escape) | |
496 | |
497 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
|
498 """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
|
499 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
500 >>> 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
|
501 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
|
502 |
498 | 503 :return: the unescaped string |
504 :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
|
505 :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
|
506 """ |
1 | 507 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
|
508 return u'' |
1 | 509 return unicode(self).replace('"', '"') \ |
510 .replace('>', '>') \ | |
511 .replace('<', '<') \ | |
512 .replace('&', '&') | |
513 | |
116 | 514 def stripentities(self, keepxmlentities=False): |
515 """Return a copy of the text with any character or numeric entities | |
516 replaced by the equivalent UTF-8 characters. | |
517 | |
518 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
|
519 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
|
520 ``"``) 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
|
521 |
498 | 522 :return: a `Markup` instance with entities removed |
523 :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
|
524 :see: `genshi.util.stripentities` |
6 | 525 """ |
116 | 526 return Markup(stripentities(self, keepxmlentities=keepxmlentities)) |
527 | |
528 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
|
529 """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
|
530 |
498 | 531 :return: a `Markup` instance with all tags removed |
532 :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
|
533 :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
|
534 """ |
116 | 535 return Markup(striptags(self)) |
1 | 536 |
537 | |
541 | 538 try: |
539 from genshi._speedups import Markup | |
540 except ImportError: | |
541 pass # just use the Python implementation | |
542 | |
1 | 543 escape = Markup.escape |
544 | |
545 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
|
546 """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
|
547 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
548 >>> 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
|
549 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
|
550 |
498 | 551 If the provided `text` object is not a `Markup` instance, it is returned |
552 unchanged. | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
553 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
554 >>> 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
|
555 '1 < 2' |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
556 |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
557 :param text: the text to unescape |
498 | 558 :return: the unescsaped string |
559 :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
|
560 """ |
1 | 561 if not isinstance(text, Markup): |
562 return text | |
563 return text.unescape() | |
564 | |
565 | |
566 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
|
567 """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
|
568 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
569 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
|
570 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
|
571 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
|
572 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
573 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
|
574 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
575 >>> 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
|
576 >>> html |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
577 <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
|
578 >>> html.uri |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
579 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
|
580 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
581 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
|
582 that namespace: |
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 >>> 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
|
585 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
|
586 >>> html.body.localname |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
587 u'body' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
588 >>> html.body.namespace |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
589 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
|
590 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
591 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
|
592 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
|
593 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
594 >>> 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
|
595 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
|
596 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
597 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
|
598 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
|
599 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
600 >>> qname = html.body |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
601 >>> qname in html |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
602 True |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
603 >>> 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
|
604 False |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
605 """ |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
606 def __new__(cls, uri): |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
607 if type(uri) is cls: |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
608 return uri |
685 | 609 return object.__new__(cls) |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
204
diff
changeset
|
610 |
279
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
611 def __getnewargs__(self): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
612 return (self.uri,) |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
613 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
614 def __getstate__(self): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
615 return self.uri |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
616 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
617 def __setstate__(self, uri): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
618 self.uri = uri |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
619 |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
620 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
|
621 self.uri = unicode(uri) |
1 | 622 |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
623 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
|
624 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
|
625 |
278
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
626 def __ne__(self, other): |
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
627 return not self == other |
d6c58473a9d0
Fix the handling of namespace context for match templates.
cmlenz
parents:
230
diff
changeset
|
628 |
18
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
629 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
|
630 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
|
631 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
|
632 return self.uri == other |
1 | 633 |
634 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
|
635 return QName(self.uri + u'}' + name) |
1 | 636 __getattr__ = __getitem__ |
637 | |
638 def __repr__(self): | |
639 return '<Namespace "%s">' % self.uri | |
640 | |
641 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
|
642 return self.uri.encode('utf-8') |
1 | 643 |
644 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
|
645 return self.uri |
1 | 646 |
647 | |
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
|
648 # 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
|
649 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
|
650 |
520a5b7dd6d2
* No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents:
140
diff
changeset
|
651 |
1 | 652 class QName(unicode): |
653 """A qualified element or attribute name. | |
654 | |
655 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
|
656 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
|
657 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
|
658 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
|
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('foo') |
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'foo') |
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'foo' |
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 |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
667 >>> 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
|
668 >>> 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
|
669 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
|
670 >>> qname.localname |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
671 u'body' |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
672 >>> qname.namespace |
5420cfe42d36
Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents:
17
diff
changeset
|
673 u'http://www.w3.org/1999/xhtml' |
1 | 674 """ |
675 __slots__ = ['namespace', 'localname'] | |
676 | |
677 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
|
678 """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
|
679 |
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 :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
|
681 ``{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
|
682 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
|
683 """ |
100 | 684 if type(qname) is cls: |
1 | 685 return qname |
686 | |
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
|
687 parts = qname.lstrip(u'{').split(u'}', 1) |
100 | 688 if len(parts) > 1: |
136 | 689 self = unicode.__new__(cls, u'{%s' % qname) |
690 self.namespace, self.localname = map(unicode, parts) | |
1 | 691 else: |
692 self = unicode.__new__(cls, qname) | |
136 | 693 self.namespace, self.localname = None, unicode(qname) |
1 | 694 return self |
279
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
695 |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
696 def __getnewargs__(self): |
a99666402b12
Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents:
278
diff
changeset
|
697 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
|
698 |
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
|
699 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
|
700 return 'QName(%s)' % unicode.__repr__(self.lstrip('{')) |