2 require "rexml/parseexception"
3 require "rexml/namespace"
5 require 'rexml/attlistdecl'
6 require 'rexml/xmltokens'
9 # Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
10 # ... >. DOCTYPES can be used to declare the DTD of a document, as well as
11 # being used to declare entities used in the document.
12 class DocType < Parent
19 'gt'=>EntityConst::GT,
20 'lt'=>EntityConst::LT,
21 'quot'=>EntityConst::QUOT,
22 "apos"=>EntityConst::APOS
25 # name is the name of the doctype
26 # external_id is the referenced DTD, if given
27 attr_reader :name, :external_id, :entities, :namespaces
31 # dt = DocType.new( 'foo', '-//I/Hate/External/IDs' )
32 # # <!DOCTYPE foo '-//I/Hate/External/IDs'>
33 # dt = DocType.new( doctype_to_clone )
34 # # Incomplete. Shallow clone of doctype
36 # +Note+ that the constructor:
38 # Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
40 # is _deprecated_. Do not use it. It will probably disappear.
41 def initialize( first, parent=nil )
42 @entities = DEFAULT_ENTITIES
43 @long_name = @uri = nil
44 if first.kind_of? String
48 elsif first.kind_of? DocType
51 @external_id = first.external_id
52 elsif first.kind_of? Array
55 @external_id = first[1]
58 elsif first.kind_of? Source
60 parser = Parsers::BaseParser.new( first )
62 if event[0] == :start_doctype
63 @name, @external_id, @long_name, @uri, = event[1..-1]
74 def attributes_of element
77 child.each do |key,val|
78 rv << Attribute.new(key,val)
79 end if child.kind_of? AttlistDecl and child.element_name == element
84 def attribute_of element, attribute
85 att_decl = find do |child|
86 child.kind_of? AttlistDecl and
87 child.element_name == element and
88 child.include? attribute
90 return nil unless att_decl
99 # Where to write the string
101 # An integer. If -1, no indentation will be used; otherwise, the
102 # indentation will be this number of spaces, and children will be
103 # indented an additional amount.
108 def write( output, indent=0, transitive=false, ie_hack=false )
109 f = REXML::Formatters::Default.new
110 indent( output, indent )
114 output << " #@external_id" if @external_id
115 output << " #{@long_name.inspect}" if @long_name
116 output << " #{@uri.inspect}" if @uri
117 unless @children.empty?
118 next_indent = indent + 1
121 @children.each { |child|
123 f.write( child, output )
135 @entities[name].unnormalized if @entities[name]
140 @entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
141 @entities[ child.name ] = child if child.kind_of? Entity
144 # This method retrieves the public identifier identifying the document's
147 # Method contributed by Henrik Martensson
153 strip_quotes(@long_name)
157 # This method retrieves the system identifier identifying the document's DTD
159 # Method contributed by Henrik Martensson
163 strip_quotes(@long_name)
165 @uri.kind_of?(String) ? strip_quotes(@uri) : nil
169 # This method returns a list of notations that have been declared in the
170 # _internal_ DTD subset. Notations in the external DTD subset are not
173 # Method contributed by Henrik Martensson
175 children().select {|node| node.kind_of?(REXML::NotationDecl)}
178 # Retrieves a named notation. Only notations declared in the internal
179 # DTD subset can be retrieved.
181 # Method contributed by Henrik Martensson
183 notations.find { |notation_decl|
184 notation_decl.name == name
190 # Method contributed by Henrik Martensson
191 def strip_quotes(quoted_string)
192 quoted_string =~ /^[\'\"].*[\ยด\"]$/ ?
193 quoted_string[1, quoted_string.length-2] :
198 # We don't really handle any of these since we're not a validating
199 # parser, so we can be pretty dumb about them. All we need to be able
200 # to do is spew them back out on a write()
202 # This is an abstract class. You never use this directly; it serves as a
203 # parent class for the specific declarations.
204 class Declaration < Child
215 # See REXML::Formatters
217 def write( output, indent )
223 class ElementDecl < Declaration
224 def initialize( src )
229 class ExternalEntity < Child
230 def initialize( src )
237 def write( output, indent )
242 class NotationDecl < Child
243 attr_accessor :public, :system
244 def initialize name, middle, pub, sys
253 "<!NOTATION #@name #@middle#{
254 @public ? ' ' + public.inspect : ''
256 @system ? ' ' +@system.inspect : ''
260 def write( output, indent=-1 )
264 # This method retrieves the name of the notation.
266 # Method contributed by Henrik Martensson