annotate genshi/core.py @ 634:60a1fb39f915

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