annotate genshi/core.py @ 737:ca72e3dc443d trunk

Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
author cmlenz
date Thu, 05 Jun 2008 17:00:15 +0000
parents 4bc6741b2811
children 1fd97b75cdc9 25b8ffa7fe65 5d8ca3f527af
rev   line source
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
2 #
719
4bc6741b2811 Fix copyright years.
cmlenz
parents: 713
diff changeset
3 # Copyright (C) 2006-2008 Edgewall Software
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
4 # All rights reserved.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
5 #
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
230
84168828b074 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
8 # are also available at http://genshi.edgewall.org/wiki/License.
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
9 #
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
230
84168828b074 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
12 # history and logs, available at http://genshi.edgewall.org/log/.
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
13
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
14 """Core classes for markup processing."""
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
24
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
33
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
34
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
35 class Stream(object):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
36 """Represents a stream of markup events.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
37
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
38 This class is basically an iterator over the events.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
50 Also provided are ways to serialize the stream to text. The `serialize()`
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
51 method will return an iterator over generated strings, while `render()`
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
52 returns the complete generated text at once. Both accept various parameters
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
53 that impact the way the stream is serialized.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
56
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
57 START = StreamEventKind('START') #: a start tag
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
58 END = StreamEventKind('END') #: an end tag
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
61 DOCTYPE = StreamEventKind('DOCTYPE') #: doctype declaration
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
62 START_NS = StreamEventKind('START_NS') #: start namespace mapping
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
63 END_NS = StreamEventKind('END_NS') #: end namespace mapping
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
64 START_CDATA = StreamEventKind('START_CDATA') #: start CDATA section
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
65 END_CDATA = StreamEventKind('END_CDATA') #: end CDATA section
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
66 PI = StreamEventKind('PI') #: processing instruction
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
67 COMMENT = StreamEventKind('COMMENT') #: comment
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
70 """Initialize the stream with a sequence of markup events.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
77 """
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
80
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
81 def __iter__(self):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
82 return iter(self.events)
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
84168828b074 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
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
84168828b074 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
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
84168828b074 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
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
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
123
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
124 :param function: the callable object that should be applied as a filter
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
125 :return: the filtered stream
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
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
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
144
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
145 :param filters: one or more callable objects that should be applied as
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
146 filters
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
147 :return: the filtered stream
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
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
688
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
152 def render(self, method=None, encoding='utf-8', out=None, **kwargs):
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
153 """Return a string representation of the stream.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
154
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
155 Any additional keyword arguments are passed to the serializer, and thus
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
156 depend on the `method` parameter value.
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
163 `None`, this method returns a `unicode` object
688
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
164 :param out: a file-like object that the output should be written to
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
165 instead of being returned as one big string; note that if
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
166 this is a file or socket (or similar), the `encoding` must
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
167 not be `None` (that is, the output must be encoded)
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
168 :return: a `str` or `unicode` object (depending on the `encoding`
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
169 parameter), or `None` if the `out` parameter is provided
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
170 :rtype: `basestring`
688
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
171
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
172 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
688
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
173 :note: Changed in 0.5: added the `out` parameter
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
174 """
462
d5e2a7b58116 Add lower-level serialization functions.
cmlenz
parents: 460
diff changeset
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)
688
d8571da25bc5 The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
179 return encode(generator, method=method, encoding=encoding, out=out)
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
182 """Return a new stream that contains the events matching the given
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
183 XPath expression.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
184
576
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
185 >>> from genshi import HTML
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
186 >>> stream = HTML('<doc><elem>foo</elem><elem>bar</elem></doc>')
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
187 >>> print stream.select('elem')
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
188 <elem>foo</elem><elem>bar</elem>
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
189 >>> print stream.select('elem/text()')
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
190 foobar
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
191
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
192 Note that the outermost element of the stream becomes the *context
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
193 node* for the XPath test. That means that the expression "doc" would
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
194 not match anything in the example above, because it only tests against
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
195 child elements of the outermost element:
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
196
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
197 >>> print stream.select('doc')
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
198 <BLANKLINE>
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
199
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
200 You can use the "." expression to match the context node itself
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
201 (although that usually makes little sense):
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
202
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
203 >>> print stream.select('.')
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
204 <doc><elem>foo</elem><elem>bar</elem></doc>
b00765a115a5 Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
207 :param namespaces: mapping of namespace prefixes used in the path
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
208 :param variables: mapping of variable names to values
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
209 :return: the selected substream
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
210 :rtype: `Stream`
435
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
211 :raises PathSyntaxError: if the given path expression is invalid or not
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
212 supported
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
213 """
230
84168828b074 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
218 """Generate strings corresponding to a specific serialization of the
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
219 stream.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
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
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
222 the serialized output incrementally, as opposed to returning a single
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
223 string.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
224
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
225 Any additional keyword arguments are passed to the serializer, and thus
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
226 depend on the `method` parameter value.
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
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
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
232 :return: an iterator over the serialization results (`Markup` or
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
233 `unicode` objects, depending on the serialization method)
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
234 :rtype: ``iterator``
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
235 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
236 """
462
d5e2a7b58116 Add lower-level serialization functions.
cmlenz
parents: 460
diff changeset
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
d5e2a7b58116 Add lower-level serialization functions.
cmlenz
parents: 460
diff changeset
240 return get_serializer(method, **kwargs)(_ensure(self))
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
241
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
242 def __str__(self):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
243 return self.render()
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
244
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
245 def __unicode__(self):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
246 return self.render(encoding=None)
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
247
737
ca72e3dc443d Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
248 def __html__(self):
ca72e3dc443d Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
249 return self
ca72e3dc443d Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
250
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
251
69
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
252 START = Stream.START
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
253 END = Stream.END
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
254 TEXT = Stream.TEXT
460
75425671b437 Apply patch by Alec Thomas for processing XML declarations (#111). Thanks!
cmlenz
parents: 438
diff changeset
255 XML_DECL = Stream.XML_DECL
69
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
256 DOCTYPE = Stream.DOCTYPE
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
257 START_NS = Stream.START_NS
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
258 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
259 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
260 END_CDATA = Stream.END_CDATA
69
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
261 PI = Stream.PI
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
262 COMMENT = Stream.COMMENT
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
263
111
2368c3becc52 Some fixes and more unit tests for the XPath engine.
cmlenz
parents: 100
diff changeset
264 def _ensure(stream):
2368c3becc52 Some fixes and more unit tests for the XPath engine.
cmlenz
parents: 100
diff changeset
265 """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
266 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
267 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
268
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 # 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
270 # 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
271 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
272 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
273 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
274 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
275 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
276 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
277 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
278 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
279
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 # 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
281 # 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
282 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
283 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
284 yield event
111
2368c3becc52 Some fixes and more unit tests for the XPath engine.
cmlenz
parents: 100
diff changeset
285
69
c40a5dcd2b55 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
286
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
287 class Attrs(tuple):
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
288 """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
289
434
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
290 Ordering of the attributes is preserved, while access by name is also
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
291 supported.
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
292
182
2f30ce3fb85e Renamed `Attributes` to `Attrs` to reduce the verbosity.
cmlenz
parents: 172
diff changeset
293 >>> 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
294 >>> 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
295 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
296
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
297 >>> 'href' in attrs
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
298 True
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
299 >>> 'tabindex' in attrs
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
300 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
301 >>> 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
302 'Foo'
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
303
425
073640758a42 Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
304 Instances may not be manipulated directly. Instead, the operators ``|`` and
073640758a42 Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
305 ``-`` can be used to produce new instances that have specific attributes
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
306 added, replaced or removed.
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
307
425
073640758a42 Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
308 To remove an attribute, use the ``-`` operator. The right hand side can be
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
309 either a string or a set/sequence of strings, identifying the name(s) of
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
310 the attribute(s) to remove:
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
311
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
312 >>> 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
313 Attrs([('href', '#')])
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
314 >>> attrs - ('title', 'href')
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
315 Attrs()
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
316
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
317 The original instance is not modified, but the operator can of course be
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
318 used with an assignment:
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
319
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', '#'), ('title', 'Foo')])
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
322 >>> attrs -= 'title'
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
323 >>> 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
324 Attrs([('href', '#')])
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
325
425
073640758a42 Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
326 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
327 is a sequence of ``(name, value)`` tuples (which includes `Attrs`
073640758a42 Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
328 instances):
170
6b265e02d099 Allow initialization of `Attributes` with keyword arguments.
cmlenz
parents: 161
diff changeset
329
403
228907abb726 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
330 >>> 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
331 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
332
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
333 If the attributes already contain an attribute with a given name, the value
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
334 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
335
403
228907abb726 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
336 >>> 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
337 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
338 """
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
339 __slots__ = []
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
340
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
341 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
342 """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
343 name.
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
344
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
345 :return: `True` if the list includes the attribute
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
346 :rtype: `bool`
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
347 """
133
79f445396cd7 Minor cleanup and performance improvement for the builder module.
cmlenz
parents: 123
diff changeset
348 for attr, _ in self:
79f445396cd7 Minor cleanup and performance improvement for the builder module.
cmlenz
parents: 123
diff changeset
349 if attr == name:
79f445396cd7 Minor cleanup and performance improvement for the builder module.
cmlenz
parents: 123
diff changeset
350 return True
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
351
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
352 def __getslice__(self, i, j):
593
0af1b7982ba5 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
353 """Return a slice of the attributes list.
0af1b7982ba5 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
354
0af1b7982ba5 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
355 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')])
0af1b7982ba5 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
356 >>> attrs[1:]
0af1b7982ba5 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
357 Attrs([('title', 'Foo')])
0af1b7982ba5 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
358 """
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
359 return Attrs(tuple.__getslice__(self, i, j))
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
360
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
361 def __or__(self, attrs):
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
362 """Return a new instance that contains the attributes in `attrs` in
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
363 addition to any already existing attributes.
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
364
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
365 :return: a new instance with the merged attributes
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
366 :rtype: `Attrs`
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
367 """
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
368 repl = dict([(an, av) for an, av in attrs if an in self])
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
369 return Attrs([(sn, repl.get(sn, sv)) for sn, sv in self] +
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
370 [(an, av) for an, av in attrs if an not in self])
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
371
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
372 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
373 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
374 return 'Attrs()'
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
375 return 'Attrs([%s])' % ', '.join([repr(item) for item in self])
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
376
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
377 def __sub__(self, names):
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
378 """Return a new instance with all attributes with a name in `names` are
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
379 removed.
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
380
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
381 :param names: the names of the attributes to remove
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
382 :return: a new instance with the attribute removed
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
383 :rtype: `Attrs`
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
384 """
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
385 if isinstance(names, basestring):
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
386 names = (names,)
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
387 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
388
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
389 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
390 """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
391 value of the `default` parameter if no such attribute is found.
435
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
392
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
393 :param name: the name of the attribute
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
394 :param default: the value to return when the attribute does not exist
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
395 :return: the attribute value, or the `default` value if that attribute
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
396 does not exist
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
397 :rtype: `object`
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
398 """
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
399 for attr, value in self:
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
400 if attr == name:
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
401 return value
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
402 return default
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
403
77
f5ec6d4a61e4 * Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents: 73
diff changeset
404 def totuple(self):
161
7b1f07496bf7 Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
405 """Return the attributes as a markup event.
7b1f07496bf7 Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
406
425
073640758a42 Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
407 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
408 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
409
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
410 >>> 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
411 ('TEXT', u'#Foo', (None, -1, -1))
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
412
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
413 :return: a `TEXT` event
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
414 :rtype: `tuple`
161
7b1f07496bf7 Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
415 """
77
f5ec6d4a61e4 * Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents: 73
diff changeset
416 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
417
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
418
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
419 class Markup(unicode):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
420 """Marks a string as being safe for inclusion in HTML/XML output without
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
421 needing to be escaped.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
422 """
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
423 __slots__ = []
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
424
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
425 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
426 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
427
51d4101f49ca * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
428 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
429 return Markup(unicode(escape(other)) + unicode(self))
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
430
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
431 def __mod__(self, args):
713
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
432 if isinstance(args, dict):
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
433 args = dict(zip(args.keys(), map(escape, args.values())))
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
434 elif isinstance(args, (list, tuple)):
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
435 args = tuple(map(escape, args))
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
436 else:
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
437 args = escape(args)
5420fe9d99a9 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
438 return Markup(unicode.__mod__(self, args))
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
439
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
440 def __mul__(self, num):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
441 return Markup(unicode(self) * num)
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
442
204
51d4101f49ca * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
443 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
444 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
445
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 def __repr__(self):
382
2682dabbcd04 * Added documentation for the various stream event kinds.
cmlenz
parents: 377
diff changeset
447 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
448
54
1f3cd91325d9 Fix a number of escaping problems:
cmlenz
parents: 34
diff changeset
449 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
450 """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
451 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
452 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
453
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
454 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
455 automatically escaped.
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
456
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
457 :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
458 :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
459 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
460 :return: the joined `Markup` object
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
461 :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
462 :see: `escape`
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
463 """
54
1f3cd91325d9 Fix a number of escaping problems:
cmlenz
parents: 34
diff changeset
464 return Markup(unicode(self).join([escape(item, quotes=escape_quotes)
34
3421dd98f015 quotes should not be escaped inside text nodes
mgood
parents: 27
diff changeset
465 for item in seq]))
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
466
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
467 def escape(cls, text, quotes=True):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
468 """Create a Markup instance from a string and escape special characters
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
469 it may contain (<, >, & and \").
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
470
434
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
471 >>> 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
472 <Markup u'&#34;1 &lt; 2&#34;'>
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
473
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
474 If the `quotes` parameter is set to `False`, the \" character is left
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
475 as is. Escaping quotes is generally only required for strings that are
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
476 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
477
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
478 >>> 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
479 <Markup u'"1 &lt; 2"'>
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
480
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
481 :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
482 :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
483 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
484 :return: the escaped `Markup` string
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
485 :rtype: `Markup`
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
486 """
73
1da51d718391 Some more performance tweaks.
cmlenz
parents: 69
diff changeset
487 if not text:
1da51d718391 Some more performance tweaks.
cmlenz
parents: 69
diff changeset
488 return cls()
1da51d718391 Some more performance tweaks.
cmlenz
parents: 69
diff changeset
489 if type(text) is cls:
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
490 return text
737
ca72e3dc443d Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
491 if hasattr(text, '__html__'):
ca72e3dc443d Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
492 return Markup(text.__html__())
ca72e3dc443d Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
493
73
1da51d718391 Some more performance tweaks.
cmlenz
parents: 69
diff changeset
494 text = unicode(text).replace('&', '&amp;') \
1da51d718391 Some more performance tweaks.
cmlenz
parents: 69
diff changeset
495 .replace('<', '&lt;') \
1da51d718391 Some more performance tweaks.
cmlenz
parents: 69
diff changeset
496 .replace('>', '&gt;')
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
497 if quotes:
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
498 text = text.replace('"', '&#34;')
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
499 return cls(text)
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
500 escape = classmethod(escape)
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
501
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
502 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
503 """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
504
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
505 >>> Markup('1 &lt; 2').unescape()
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
506 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
507
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
508 :return: the unescaped string
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
509 :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
510 :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
511 """
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
512 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
513 return u''
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
514 return unicode(self).replace('&#34;', '"') \
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
515 .replace('&gt;', '>') \
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
516 .replace('&lt;', '<') \
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
517 .replace('&amp;', '&')
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
518
116
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
519 def stripentities(self, keepxmlentities=False):
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
520 """Return a copy of the text with any character or numeric entities
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
521 replaced by the equivalent UTF-8 characters.
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
522
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
523 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
524 the core XML entities (``&amp;``, ``&apos;``, ``&gt;``, ``&lt;`` and
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
525 ``&quot;``) 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
526
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
527 :return: a `Markup` instance with entities removed
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
528 :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
529 :see: `genshi.util.stripentities`
6
71e8e645fe81 Simplified implementation of `py:content` directive.
cmlenz
parents: 5
diff changeset
530 """
116
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
531 return Markup(stripentities(self, keepxmlentities=keepxmlentities))
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
532
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
533 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
534 """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
535
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
536 :return: a `Markup` instance with all tags removed
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
537 :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
538 :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
539 """
116
c77c113846d6 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
540 return Markup(striptags(self))
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
541
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
542
541
773d8c470e82 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
543 try:
773d8c470e82 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
544 from genshi._speedups import Markup
773d8c470e82 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
545 except ImportError:
773d8c470e82 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
546 pass # just use the Python implementation
773d8c470e82 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
547
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
548 escape = Markup.escape
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
549
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
550 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
551 """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
552
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
553 >>> unescape(Markup('1 &lt; 2'))
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
554 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
555
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
556 If the provided `text` object is not a `Markup` instance, it is returned
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
557 unchanged.
434
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
558
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
559 >>> unescape('1 &lt; 2')
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
560 '1 &lt; 2'
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
561
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
562 :param text: the text to unescape
498
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
563 :return: the unescsaped string
700e7b47bf2b A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
564 :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
565 """
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
566 if not isinstance(text, Markup):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
567 return text
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
568 return text.unescape()
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
569
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
570
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
571 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
572 """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
573
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
574 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
575 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
576 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
577
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
578 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
579
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
580 >>> 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
581 >>> html
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
582 <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
583 >>> html.uri
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
584 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
585
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
586 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
587 that namespace:
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
588
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
589 >>> 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
590 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
591 >>> html.body.localname
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
592 u'body'
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
593 >>> html.body.namespace
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
594 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
595
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
596 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
597 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
598
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
599 >>> 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
600 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
601
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
602 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
603 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
604
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
605 >>> qname = html.body
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
606 >>> qname in html
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
607 True
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
608 >>> 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
609 False
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
610 """
224
90d62225f411 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
611 def __new__(cls, uri):
90d62225f411 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
612 if type(uri) is cls:
90d62225f411 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
613 return uri
685
8ce1a80c8843 Fix #180 (py2.6 warning).
cmlenz
parents: 666
diff changeset
614 return object.__new__(cls)
224
90d62225f411 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
615
279
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
616 def __getnewargs__(self):
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
617 return (self.uri,)
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
618
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
619 def __getstate__(self):
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
620 return self.uri
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
621
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
622 def __setstate__(self, uri):
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
623 self.uri = uri
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
624
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
625 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
626 self.uri = unicode(uri)
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
627
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
628 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
629 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
630
278
d6c58473a9d0 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
631 def __ne__(self, other):
d6c58473a9d0 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
632 return not self == other
d6c58473a9d0 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
633
18
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
634 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
635 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
636 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
637 return self.uri == other
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
638
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
639 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
640 return QName(self.uri + u'}' + name)
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
641 __getattr__ = __getitem__
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
642
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
643 def __repr__(self):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
644 return '<Namespace "%s">' % self.uri
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
645
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
646 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
647 return self.uri.encode('utf-8')
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
648
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
649 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
650 return self.uri
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
651
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
652
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
653 # 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
654 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
655
520a5b7dd6d2 * No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents: 140
diff changeset
656
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
657 class QName(unicode):
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
658 """A qualified element or attribute name.
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
659
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
660 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
661 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
662 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
663 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
664
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
665 >>> qname = QName('foo')
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
666 >>> 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
667 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
668 >>> qname.localname
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
669 u'foo'
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
670 >>> qname.namespace
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
671
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
672 >>> 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
673 >>> 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
674 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
675 >>> qname.localname
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
676 u'body'
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
677 >>> qname.namespace
5420cfe42d36 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
678 u'http://www.w3.org/1999/xhtml'
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
679 """
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
680 __slots__ = ['namespace', 'localname']
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
681
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
682 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
683 """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
684
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
685 :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
686 ``{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
687 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
688 """
100
a519f581a1b1 Ported [111] to trunk.
cmlenz
parents: 96
diff changeset
689 if type(qname) is cls:
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
690 return qname
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
691
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
692 parts = qname.lstrip(u'{').split(u'}', 1)
100
a519f581a1b1 Ported [111] to trunk.
cmlenz
parents: 96
diff changeset
693 if len(parts) > 1:
136
b86f496f6035 Minor performance improvements in serialization.
cmlenz
parents: 133
diff changeset
694 self = unicode.__new__(cls, u'{%s' % qname)
b86f496f6035 Minor performance improvements in serialization.
cmlenz
parents: 133
diff changeset
695 self.namespace, self.localname = map(unicode, parts)
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
696 else:
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
697 self = unicode.__new__(cls, qname)
136
b86f496f6035 Minor performance improvements in serialization.
cmlenz
parents: 133
diff changeset
698 self.namespace, self.localname = None, unicode(qname)
1
5479aae32f5a Initial import.
cmlenz
parents:
diff changeset
699 return self
279
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
700
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
701 def __getnewargs__(self):
a99666402b12 Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
702 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
703
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
704 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
705 return 'QName(%s)' % unicode.__repr__(self.lstrip('{'))
Copyright (C) 2012-2017 Edgewall Software