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
21 # Common abstractions for SAX listeners reading XML documents generated by Doxygen.
22 abstract class DoxmlListener
25 # The locator setted by calling `document_locator=`.
26 protected var locator
: nullable SAXLocator = null
29 fun graph
: ProjectGraph is abstract
31 redef fun document_locator
=(locator
: SAXLocator) do
32 self.locator
= locator
35 protected fun dox_uri
: String do return ""
37 redef fun start_element
(uri
: String, local_name
: String, qname
: String,
40 if uri
!= dox_uri
then return # None of our business.
41 start_dox_element
(local_name
, atts
)
44 # Process the start of an element in the Doxygen’s namespace.
46 # See `ContentHandler.start_element` for the description of the parameters.
47 protected fun start_dox_element
(local_name
: String, atts
: Attributes) do end
49 redef fun end_element
(uri
: String, local_name
: String, qname
: String) do
51 if uri
!= dox_uri
then return # None of our business.
52 end_dox_element
(local_name
)
55 # Process the end of an element in the Doxygen’s namespace.
57 # See `ContentHandler.start_element` for the description of the parameters.
58 protected fun end_dox_element
(local_name
: String) do end
60 protected fun get_bool
(atts
: Attributes, local_name
: String): Bool do
61 return get_optional
(atts
, local_name
, "no") == "yes"
64 # Get the value of an optional attribute.
68 # * `atts`: attribute list.
69 # * `local_name`: local name of the attribute.
70 # * `default`: value to return when the specified attribute is not found.
71 protected fun get_optional
(atts
: Attributes, local_name
: String,
72 default
: String): String do
73 return atts
.value_ns
(dox_uri
, local_name
) or else default
76 # Get the value of an required attribute.
80 # * `atts`: attribute list.
81 # * `local_name`: local name of the attribute.
82 protected fun get_required
(atts
: Attributes, local_name
: String): String do
83 var value
= atts
.value_ns
(dox_uri
, local_name
)
85 throw_error
("The `{local_name}` attribute is required.")
92 redef fun end_document
do
96 # Throw an error with the specified message by prepending the current location.
97 protected fun throw_error
(message
: String) do
98 var e
: SAXParseException
100 if locator
!= null then
101 e
= new SAXParseException.with_locator
(message
, locator
.as(not null))
103 e
= new SAXParseException(message
)
109 # A `DoxmlListener` that read only a part of a document.
111 # Temporary redirect events to itself until it ends processing its part.
112 abstract class StackableListener
115 # The associated reader.
116 var reader
: XMLReader
118 # The parent listener.
119 var parent
: DoxmlListener
121 # Namespace’s IRI of the element at the root of the part to process.
122 private var root_uri
: String = ""
124 # Local name of the element at the root of the part to process.
125 private var root_local_name
: String = ""
127 # The number of open element of the same type than the root of the part to process.
128 private var depth
= 0
131 private var p_graph
: ProjectGraph is noinit
136 p_graph
= parent
.graph
139 redef fun graph
do return p_graph
141 # Temporary redirect events to itself until the end of the specified element.
142 fun listen_until
(uri
: String, local_name
: String) do
144 root_local_name
= local_name
146 reader
.content_handler
= self
147 locator
= parent
.locator
150 redef fun start_element
(uri
: String, local_name
: String, qname
: String,
153 if uri
== root_uri
and local_name
== root_local_name
then
158 redef fun end_element
(uri
: String, local_name
: String, qname
: String) do
160 if uri
== root_uri
and local_name
== root_local_name
then
164 parent
.end_element
(uri
, local_name
, qname
)
169 # Reset the reader’s listener to the parent.
171 reader
.content_handler
= parent
175 redef fun end_document
do
180 # A SAX listener that skips any event except the end of the part to process.
182 # Used to skip an entire element.
184 super StackableListener
187 # Concatenates any text node found.
189 super StackableListener
191 protected var buffer
: Buffer = new FlatBuffer
192 private var sp
: Bool = false
194 redef fun listen_until
(uri
: String, local_name
: String) do
200 redef fun characters
(str
: String) do
202 if buffer
.length
> 0 then buffer
.append
(" ")
208 redef fun ignorable_whitespace
(str
: String) do
213 protected fun flush_buffer
: String do
221 redef fun to_s
do return buffer
.to_s
224 # Processes a content of type `linkedTextType`.
225 abstract class LinkedTextListener[T
: LinkedText]
229 var linked_text
: T
is noinit
231 private var refid
= ""
233 # Create a new instance of `T`.
234 protected fun create_linked_text
: T
is abstract
236 redef fun listen_until
(uri
: String, local_name
: String) do
237 linked_text
= create_linked_text
242 redef fun start_dox_element
(local_name
: String, atts
: Attributes) do
245 if "ref" == local_name
then refid
= get_required
(atts
, "refid")
248 redef fun end_dox_element
(local_name
: String) do
251 if "ref" == local_name
then refid
= ""
254 private fun push_part
do
257 if not s
.is_empty
then
258 linked_text
.add_part
(s
, refid
)
262 redef fun to_s
do return linked_text
.to_s
265 # Processes the content of a `<type>` element.
267 super LinkedTextListener[RawType]
269 private var raw_type
: RawType is noinit
271 redef fun create_linked_text
do return new RawType(graph
)