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 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