1 require "booh/rexml/parent"
2 require "booh/rexml/parseexception"
3 require "booh/rexml/namespace"
4 require 'booh/rexml/entity'
5 require 'booh/rexml/attlistdecl'
6 require 'booh/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 indenting will be used; otherwise, the
102 # indentation will be this number of spaces, and children will be
103 # indented an additional amount.
105 # If transitive is true and indent is >= 0, then the output will be
106 # pretty-printed in such a way that the added whitespace does not affect
107 # the absolute *value* of the document -- that is, it leaves the value
108 # and number of Text nodes in the document unchanged.
110 # Internet Explorer is the worst piece of crap to have ever been
111 # written, with the possible exception of Windows itself. Since IE is
112 # unable to parse proper XML, we have to provide a hack to generate XML
113 # that IE's limited abilities can handle. This hack inserts a space
114 # before the /> on empty tags.
116 def write( output, indent=0, transitive=false, ie_hack=false )
117 indent( output, indent )
121 output << " #@external_id" if @external_id
122 output << " #@long_name" if @long_name
123 output << " #@uri" if @uri
124 unless @children.empty?
125 next_indent = indent + 1
128 @children.each { |child|
130 child.write( output, next_indent )
132 #output << ' '*next_indent
143 @entities[name].unnormalized if @entities[name]
148 @entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
149 @entities[ child.name ] = child if child.kind_of? Entity
152 # This method retrieves the public identifier identifying the document's
155 # Method contributed by Henrik Martensson
161 strip_quotes(@long_name)
165 # This method retrieves the system identifier identifying the document's DTD
167 # Method contributed by Henrik Martensson
171 strip_quotes(@long_name)
173 @uri.kind_of?(String) ? strip_quotes(@uri) : nil
177 # This method returns a list of notations that have been declared in the
178 # _internal_ DTD subset. Notations in the external DTD subset are not
181 # Method contributed by Henrik Martensson
183 children().select {|node| node.kind_of?(REXML::NotationDecl)}
186 # Retrieves a named notation. Only notations declared in the internal
187 # DTD subset can be retrieved.
189 # Method contributed by Henrik Martensson
191 notations.find { |notation_decl|
192 notation_decl.name == name
198 # Method contributed by Henrik Martensson
199 def strip_quotes(quoted_string)
200 quoted_string =~ /^[\'\"].*[\ยด\"]$/ ?
201 quoted_string[1, quoted_string.length-2] :
206 # We don't really handle any of these since we're not a validating
207 # parser, so we can be pretty dumb about them. All we need to be able
208 # to do is spew them back out on a write()
210 # This is an abstract class. You never use this directly; it serves as a
211 # parent class for the specific declarations.
212 class Declaration < Child
222 def write( output, indent )
223 output << (' '*indent) if indent > 0
229 class ElementDecl < Declaration
230 def initialize( src )
235 class ExternalEntity < Child
236 def initialize( src )
243 def write( output, indent )
248 class NotationDecl < Child
249 attr_accessor :public, :system
250 def initialize name, middle, pub, sys
259 "<!NOTATION #@name #@middle#{
260 @public ? ' ' + public.inspect : ''
262 @system ? ' ' +@system.inspect : ''
266 def write( output, indent=-1 )
267 output << (' '*indent) if indent > 0
271 # This method retrieves the name of the notation.
273 # Method contributed by Henrik Martensson