example: add 24 game task of Rosetta code
[nit.git] / lib / sax / helpers / xml_filter_impl.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
9 # another product.
10
11 # Base class for deriving an XML filter.
12 module sax::helpers::xml_filter_impl
13
14 import sax::xml_reader
15 import sax::xml_filter
16 import sax::input_source
17 import sax::sax_locator
18 import sax::attributes
19 import sax::entity_resolver
20 import sax::dtd_handler
21 import sax::content_handler
22 import sax::error_handler
23 import sax::sax_parse_exception
24
25 # Base class for deriving an XML filter.
26 #
27 # This class is designed to sit between an `XMLReader`
28 # and the client application's event handlers. By default, it
29 # does nothing but pass requests up to the reader and events
30 # on to the handlers unmodified, but subclasses can override
31 # specific methods to modify the event stream or the configuration
32 # requests as they pass through.
33 #
34 # Note: The original source code and documentation of this class comes, in part,
35 # from [SAX 2.0](http://www.saxproject.org).
36 class XMLFilterImpl
37 super XMLFilter
38 super EntityResolver
39 super DTDHandler
40 super ContentHandler
41 super ErrorHandler
42
43 # XMLFilter
44
45 redef var parent: nullable XMLReader = null is writable
46
47 # XMLReader
48
49 redef var entity_resolver: nullable EntityResolver = null is writable
50 redef var dtd_handler: nullable DTDHandler = null is writable
51 redef var content_handler: nullable ContentHandler = null is writable
52 redef var error_handler: nullable ErrorHandler = null is writable
53
54
55 ############################################################################
56 # XMLReader
57
58 # Construct an empty XML filter, with no parent.
59 #
60 # This filter will have no parent: you must assign a parent
61 # before you start a parse or do any configuration with
62 # `feature=` or `property=`, unless you use this as
63 # a pure event consumer rather than as an `XMLReader`.
64 #
65 # SEE: `parent`
66 init do
67 end
68
69 # Construct an XML filter with the specified parent.
70 #
71 # SEE: `parent`
72 init with_parent(parent_reader: XMLReader) do
73 parent = parent_reader
74 end
75
76 redef fun feature_recognized(name: String): Bool do
77 if parent == null then
78 return false
79 else
80 return parent.feature_recognized(name)
81 end
82 end
83
84 redef fun feature_readable(name: String): Bool do
85 if parent == null then
86 return false
87 else
88 return parent.feature_readable(name)
89 end
90 end
91
92 redef fun feature_writable(name: String): Bool do
93 if parent == null then
94 return false
95 else
96 return parent.feature_writable(name)
97 end
98 end
99
100 # Look up the value of a feature.
101 #
102 # This will always fail if the parent is `null`.
103 #
104 # Parameters:
105 #
106 # * `name`: The feature name.
107 #
108 # Returns:
109 #
110 # The current value of the feature.
111 #
112 # SEE: `feature_recognized`
113 #
114 # SEE: `feature_readable`
115 redef fun feature(name: String): Bool do
116 assert sax_recognized: parent != null else
117 sys.stderr.write("Feature: {name}\n")
118 end
119 return parent.feature(name)
120 end
121
122 # Set the value of a feature.
123 #
124 # This will always fail if the parent is `null`.
125 #
126 # Parameters:
127 #
128 # * `name`: feature name.
129 # * `value`: requested feature value.
130 #
131 # Returns:
132 #
133 # `true` if the feature is set; `false` if the feature can not be set given
134 # the current context.
135 #
136 # SEE: `feature_recognized`
137 #
138 # SEE: `feature_writable`
139 redef fun feature=(name: String, value: Bool) do
140 assert sax_recognized: parent != null else
141 sys.stderr.write("Feature: {name}\n")
142 end
143 parent.feature(name) = value
144 end
145
146 redef fun property_recognized(name: String): Bool do
147 if parent == null then
148 return false
149 else
150 return parent.property_recognized(name)
151 end
152 end
153
154 redef fun property_readable(name: String): Bool do
155 if parent == null then
156 return false
157 else
158 return parent.property_readable(name)
159 end
160 end
161
162 redef fun property_writable(name: String): Bool do
163 if parent == null then
164 return false
165 else
166 return parent.property_writable(name)
167 end
168 end
169
170 # Look up the value of a property.
171 #
172 # Parameters:
173 #
174 # * `name`: The property name.
175 #
176 # Returns:
177 #
178 # The current value of the property.
179 #
180 # SEE: `property_recognized`
181 #
182 # SEE: `property_readable`
183 redef fun property(name: String): nullable Object do
184 assert sax_recognized: parent != null else
185 sys.stderr.write("Property: {name}\n")
186 end
187 return parent.property(name)
188 end
189
190 # Set the value of a property.
191 #
192 # This will always fail if the parent is `null`.
193 #
194 # Parameters:
195 #
196 # * `name`: property name.
197 # * `value`: requested feature value.
198 #
199 # Returns:
200 #
201 # `true` if the property is set; `false` if the property can not be set
202 # given the current context.
203 #
204 # SEE: `property_recognized`
205 #
206 # SEE: `property_writable`
207 redef fun property=(name: String, value: nullable Object) do
208 assert sax_recognized: parent != null else
209 sys.stderr.write("Property: {name}\n")
210 end
211 parent.property(name) = value
212 end
213
214 redef fun parse(input: InputSource) do
215 setup_parse
216 parent.parse(input)
217 end
218
219 redef fun parse_file(system_id: String) do
220 var source = new InputSource
221
222 source.system_id = system_id
223 parse(source)
224 end
225
226
227 ############################################################################
228 # EntityResolver
229
230 redef fun resolve_entity(public_id: nullable String,
231 system_id: nullable String):
232 nullable InputSource do
233 if entity_resolver == null then
234 return null
235 else
236 return entity_resolver.resolve_entity(public_id, system_id)
237 end
238 end
239
240
241 ############################################################################
242 # DTDHandler
243
244 redef fun notation_decl(name: String, public_id: String,
245 system_id: String) do
246 if dtd_handler != null then
247 dtd_handler.notation_decl(name, public_id, system_id)
248 end
249 end
250
251 redef fun unparsed_entity_decl(name: String, public_id: String,
252 system_id: String) do
253 if dtd_handler != null then
254 dtd_handler.unparsed_entity_decl(name, public_id, system_id)
255 end
256 end
257
258
259 ############################################################################
260 # ContentHandler
261
262 redef fun document_locator=(locator: SAXLocator) do
263 if content_handler != null then
264 content_handler.document_locator = locator
265 end
266 end
267
268 redef fun start_document do
269 if content_handler != null then
270 content_handler.start_document
271 end
272 end
273
274 redef fun end_document do
275 if content_handler != null then
276 content_handler.end_document
277 end
278 end
279
280 redef fun start_prefix_mapping(prefix: String, uri: String) do
281 if content_handler != null then
282 content_handler.start_prefix_mapping(prefix, uri)
283 end
284 end
285
286 redef fun end_prefix_mapping(prefix: String) do
287 if content_handler != null then
288 content_handler.end_prefix_mapping(prefix)
289 end
290 end
291
292 redef fun start_element(uri: String, local_name: String, qname: String,
293 atts: Attributes) do
294 if content_handler != null then
295 content_handler.start_element(uri, local_name, qname, atts)
296 end
297 end
298
299 redef fun end_element(uri: String, local_name: String, qname: String) do
300 if content_handler != null then
301 content_handler.end_element(uri, local_name, qname)
302 end
303 end
304
305 redef fun characters(str: String) do
306 if content_handler != null then
307 content_handler.characters(str)
308 end
309 end
310
311 redef fun ignorable_whitespace(str: String) do
312 if content_handler != null then
313 content_handler.ignorable_whitespace(str)
314 end
315 end
316
317 redef fun processing_instruction(target: String, data: nullable String) do
318 if content_handler != null then
319 content_handler.processing_instruction(target, data)
320 end
321 end
322
323 redef fun skipped_entity(name: String) do
324 if content_handler != null then
325 content_handler.skipped_entity(name)
326 end
327 end
328
329
330 ############################################################################
331 # ErrorHandler
332
333 redef fun warning(exception: SAXParseException) do
334 if error_handler != null then
335 error_handler.warning(exception)
336 end
337 end
338
339 redef fun error(exception: SAXParseException) do
340 if error_handler != null then
341 error_handler.error(exception)
342 end
343 end
344
345 redef fun fatal_error(exception: SAXParseException) do
346 if error_handler != null then
347 error_handler.fatal_error(exception)
348 else
349 exception.throw
350 end
351 end
352
353 ############################################################################
354 # private
355
356 # Set up before a parse.
357 #
358 # Before every parse, check whether the parent is
359 # non-null, and re-register the filter for all of the
360 # events.
361 private fun setup_parse do
362 assert parent_is_not_null: parent != 0 else
363 sys.stderr.write("No parent for filter.")
364 end
365 parent.entity_resolver = self
366 parent.dtd_handler = self
367 parent.content_handler = self
368 parent.error_handler = self
369 end
370 end