1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
require "rexml/parent"
require "rexml/parseexception"
require "rexml/namespace"
require 'rexml/entity'
require 'rexml/attlistdecl'
require 'rexml/xmltokens'
module REXML
# Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
# ... >. DOCTYPES can be used to declare the DTD of a document, as well as
# being used to declare entities used in the document.
class DocType < Parent
include XMLTokens
START = "<!DOCTYPE"
STOP = ">"
SYSTEM = "SYSTEM"
PUBLIC = "PUBLIC"
DEFAULT_ENTITIES = {
'gt'=>EntityConst::GT,
'lt'=>EntityConst::LT,
'quot'=>EntityConst::QUOT,
"apos"=>EntityConst::APOS
}
# name is the name of the doctype
# external_id is the referenced DTD, if given
attr_reader :name, :external_id, :entities, :namespaces
# Constructor
#
# dt = DocType.new( 'foo', '-//I/Hate/External/IDs' )
# # <!DOCTYPE foo '-//I/Hate/External/IDs'>
# dt = DocType.new( doctype_to_clone )
# # Incomplete. Shallow clone of doctype
#
# +Note+ that the constructor:
#
# Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
#
# is _deprecated_. Do not use it. It will probably disappear.
def initialize( first, parent=nil )
@entities = DEFAULT_ENTITIES
@long_name = @uri = nil
if first.kind_of? String
super()
@name = first
@external_id = parent
elsif first.kind_of? DocType
super( parent )
@name = first.name
@external_id = first.external_id
elsif first.kind_of? Array
super( parent )
@name = first[0]
@external_id = first[1]
@long_name = first[2]
@uri = first[3]
elsif first.kind_of? Source
super( parent )
parser = Parsers::BaseParser.new( first )
event = parser.pull
if event[0] == :start_doctype
@name, @external_id, @long_name, @uri, = event[1..-1]
end
else
super()
end
end
def node_type
:doctype
end
def attributes_of element
rv = []
each do |child|
child.each do |key,val|
rv << Attribute.new(key,val)
end if child.kind_of? AttlistDecl and child.element_name == element
end
rv
end
def attribute_of element, attribute
att_decl = find do |child|
child.kind_of? AttlistDecl and
child.element_name == element and
child.include? attribute
end
return nil unless att_decl
att_decl[attribute]
end
def clone
DocType.new self
end
# output::
# Where to write the string
# indent::
# An integer. If -1, no indenting will be used; otherwise, the
# indentation will be this number of spaces, and children will be
# indented an additional amount.
# transitive::
# If transitive is true and indent is >= 0, then the output will be
# pretty-printed in such a way that the added whitespace does not affect
# the absolute *value* of the document -- that is, it leaves the value
# and number of Text nodes in the document unchanged.
# ie_hack::
# Internet Explorer is the worst piece of crap to have ever been
# written, with the possible exception of Windows itself. Since IE is
# unable to parse proper XML, we have to provide a hack to generate XML
# that IE's limited abilities can handle. This hack inserts a space
# before the /> on empty tags.
#
def write( output, indent=0, transitive=false, ie_hack=false )
indent( output, indent )
output << START
output << ' '
output << @name
output << " #@external_id" if @external_id
output << " #@long_name" if @long_name
output << " #@uri" if @uri
unless @children.empty?
next_indent = indent + 1
output << ' ['
child = nil # speed
@children.each { |child|
output << "\n"
child.write( output, next_indent )
}
output << "\n"
#output << ' '*next_indent
output << "]"
end
output << STOP
end
def context
@parent.context
end
def entity( name )
@entities[name].unnormalized if @entities[name]
end
def add child
super(child)
@entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
@entities[ child.name ] = child if child.kind_of? Entity
end
end
# We don't really handle any of these since we're not a validating
# parser, so we can be pretty dumb about them. All we need to be able
# to do is spew them back out on a write()
# This is an abstract class. You never use this directly; it serves as a
# parent class for the specific declarations.
class Declaration < Child
def initialize src
super()
@string = src
end
def to_s
@string+'>'
end
def write( output, indent )
output << (' '*indent) if indent > 0
output << to_s
end
end
public
class ElementDecl < Declaration
def initialize( src )
super
end
end
class ExternalEntity < Child
def initialize( src )
super()
@entity = src
end
def to_s
@entity
end
def write( output, indent )
output << @entity
output << "\n"
end
end
class NotationDecl < Child
def initialize name, middle, rest
@name = name
@middle = middle
@rest = rest
end
def to_s
"<!NOTATION #@name '#@middle #@rest'>"
end
def write( output, indent=-1 )
output << (' '*indent) if indent > 0
output << to_s
end
end
end
|