1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Basic SAX listeners.
16 module doxml
::listener
20 import language_specific
22 # Common abstractions for SAX listeners reading XML documents generated by Doxygen.
23 abstract class DoxmlListener
26 # The locator setted by calling `document_locator=`.
27 protected var locator
: nullable SAXLocator = null
30 fun graph
: ProjectGraph is abstract
32 # The language-specific strategies to use.
33 fun source_language
: SourceLanguage is abstract
35 redef fun document_locator
=(locator
: SAXLocator) do
36 self.locator
= locator
39 # The Doxygen’s namespace IRI.
40 protected fun dox_uri
: String do return ""
42 redef fun start_element
(uri
: String, local_name
: String, qname
: String,
45 if uri
!= dox_uri
then return # None of our business.
46 start_dox_element
(local_name
, atts
)
49 # Process the start of an element in the Doxygen’s namespace.
51 # See `ContentHandler.start_element` for the description of the parameters.
52 protected fun start_dox_element
(local_name
: String, atts
: Attributes) do end
54 redef fun end_element
(uri
: String, local_name
: String, qname
: String) do
56 if uri
!= dox_uri
then return # None of our business.
57 end_dox_element
(local_name
)
60 # Process the end of an element in the Doxygen’s namespace.
62 # See `ContentHandler.start_element` for the description of the parameters.
63 protected fun end_dox_element
(local_name
: String) do end
65 # Get the boolean value of the specified attribute.
68 protected fun get_bool
(atts
: Attributes, local_name
: String): Bool do
69 return get_optional
(atts
, local_name
, "no") == "yes"
72 # Get the value of an optional attribute.
76 # * `atts`: attribute list.
77 # * `local_name`: local name of the attribute.
78 # * `default`: value to return when the specified attribute is not found.
79 protected fun get_optional
(atts
: Attributes, local_name
: String,
80 default
: String): String do
81 return atts
.value_ns
(dox_uri
, local_name
) or else default
84 # Get the value of an required attribute.
88 # * `atts`: attribute list.
89 # * `local_name`: local name of the attribute.
90 protected fun get_required
(atts
: Attributes, local_name
: String): String do
91 var value
= atts
.value_ns
(dox_uri
, local_name
)
93 throw_error
("The `{local_name}` attribute is required.")
100 redef fun end_document
do
104 # Throw an error with the specified message by prepending the current location.
105 protected fun throw_error
(message
: String) do
106 var e
: SAXParseException
108 if locator
!= null then
109 e
= new SAXParseException.with_locator
(message
, locator
.as(not null))
111 e
= new SAXParseException(message
)
117 # A `DoxmlListener` that read only a part of a document.
119 # Temporary redirect events to itself until it ends processing its part.
120 abstract class StackableListener
123 # The associated reader.
124 var reader
: XMLReader
126 # The parent listener.
127 var parent
: DoxmlListener
129 # Namespace’s IRI of the element at the root of the part to process.
130 private var root_uri
: String = ""
132 # Local name of the element at the root of the part to process.
133 private var root_local_name
: String = ""
135 # The number of open element of the same type than the root of the part to process.
136 private var depth
= 0
139 private var p_graph
: ProjectGraph is noinit
141 # The language-specific strategies to use.
142 private var p_source
: SourceLanguage is noinit
147 p_graph
= parent
.graph
148 p_source
= parent
.source_language
151 redef fun graph
do return p_graph
152 redef fun source_language
do return p_source
154 # Temporary redirect events to itself until the end of the specified element.
155 fun listen_until
(uri
: String, local_name
: String) do
157 root_local_name
= local_name
159 reader
.content_handler
= self
160 locator
= parent
.locator
163 redef fun start_element
(uri
: String, local_name
: String, qname
: String,
166 if uri
== root_uri
and local_name
== root_local_name
then
171 redef fun end_element
(uri
: String, local_name
: String, qname
: String) do
173 if uri
== root_uri
and local_name
== root_local_name
then
177 parent
.end_element
(uri
, local_name
, qname
)
182 # Reset the reader’s listener to the parent.
184 reader
.content_handler
= parent
188 redef fun end_document
do
193 # A SAX listener that skips any event except the end of the part to process.
195 # Used to skip an entire element.
197 super StackableListener
200 # Concatenates any text node found.
202 super StackableListener
205 protected var buffer
: Buffer = new FlatBuffer
207 # Is the last read chunk was ignorable white space?
208 private var sp
: Bool = false
210 redef fun listen_until
(uri
: String, local_name
: String) do
216 redef fun characters
(str
: String) do
218 if buffer
.length
> 0 then buffer
.append
(" ")
224 redef fun ignorable_whitespace
(str
: String) do
229 protected fun flush_buffer
: String do
237 redef fun to_s
do return buffer
.to_s
240 # Processes a content of type `linkedTextType`.
241 abstract class LinkedTextListener[T
: LinkedText]
245 var linked_text
: T
is noinit
247 private var refid
= ""
249 # Create a new instance of `T`.
250 protected fun create_linked_text
: T
is abstract
252 redef fun listen_until
(uri
: String, local_name
: String) do
253 linked_text
= create_linked_text
258 redef fun start_dox_element
(local_name
: String, atts
: Attributes) do
261 if "ref" == local_name
then refid
= get_required
(atts
, "refid")
264 redef fun end_dox_element
(local_name
: String) do
267 if "ref" == local_name
then refid
= ""
270 private fun push_part
do
273 if not s
.is_empty
then
274 linked_text
.add_part
(s
, refid
)
278 redef fun to_s
do return linked_text
.to_s
281 # Processes the content of a `<type>` element.
283 super LinkedTextListener[RawType]
285 private var raw_type
: RawType is noinit
287 redef fun create_linked_text
do return new RawType(graph
)