Class: REXML::Entity

Inherits:
Child show all
Includes:
XMLTokens
Defined in:
lib/rexml/entity.rb

Overview

God, I hate DTDs. I really do. Why this idiot standard still plagues us is beyond me.

Constant Summary collapse

PUBIDCHAR =
"\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
SYSTEMLITERAL =
%Q{((?:"[^"]*")|(?:'[^']*'))}
PUBIDLITERAL =
%Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
EXTERNALID =
"(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
NDATADECL =
"\\s+NDATA\\s+#{NAME}"
PEREFERENCE =
"%#{NAME};"
ENTITYVALUE =
%Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
PEDEF =
"(?:#{ENTITYVALUE}|#{EXTERNALID})"
ENTITYDEF =
"(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
PEDECL =
"<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
GEDECL =
"<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
ENTITYDECL =
/\s*(?:#{GEDECL})|(?:#{PEDECL})/um
PEREFERENCE_RE =
/#{PEREFERENCE}/um

Constants included from XMLTokens

XMLTokens::NAME, XMLTokens::NAMECHAR, XMLTokens::NAME_STR, XMLTokens::NCNAME_STR, XMLTokens::NMTOKEN, XMLTokens::NMTOKENS, XMLTokens::REFERENCE

Instance Attribute Summary collapse

Attributes inherited from Child

#parent

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Child

#bytes, #document, #next_sibling=, #previous_sibling=, #remove, #replace_with

Methods included from Node

#each_recursive, #find_first_recursive, #indent, #index_in_parent, #next_sibling_node, #parent?, #previous_sibling_node

Constructor Details

#initialize(stream, value = nil, parent = nil, reference = false) ⇒ Entity

Create a new entity. Simple entities can be constructed by passing a name, value to the constructor; this creates a generic, plain entity reference. For anything more complicated, you have to pass a Source to the constructor with the entity definiton, or use the accessor methods. WARNING: There is no validation of entity state except when the entity is read from a stream. If you start poking around with the accessors, you can easily create a non-conformant Entity. The best thing to do is dump the stupid DTDs and use XMLSchema instead.

e = Entity.new( 'amp', '&' )


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
# File 'lib/rexml/entity.rb', line 35

def initialize stream, value=nil, parent=nil, reference=false
	super(parent)
	@ndata = @pubid = @value = @external = nil
	if stream.kind_of? Array
		@name = stream[1]
		if stream[-1] == '%'
			@reference = true 
			stream.pop
		else
			@reference = false
		end
		if stream[2] =~ /SYSTEM|PUBLIC/
			@external = stream[2]
			if @external == 'SYSTEM'
				@ref = stream[3]
				@ndata = stream[4] if stream.size == 5
			else
				@pubid = stream[3]
				@ref = stream[4]
			end
		else
			@value = stream[2]
		end
	else
		@reference = reference
		@external = nil
		@name = stream
		@value = value
	end
end

Instance Attribute Details

#externalObject (readonly)

Returns the value of attribute external.



23
24
25
# File 'lib/rexml/entity.rb', line 23

def external
  @external
end

#nameObject (readonly)

Returns the value of attribute name.



23
24
25
# File 'lib/rexml/entity.rb', line 23

def name
  @name
end

#ndataObject (readonly)

Returns the value of attribute ndata.



23
24
25
# File 'lib/rexml/entity.rb', line 23

def ndata
  @ndata
end

#pubidObject (readonly)

Returns the value of attribute pubid.



23
24
25
# File 'lib/rexml/entity.rb', line 23

def pubid
  @pubid
end

#refObject (readonly)

Returns the value of attribute ref.



23
24
25
# File 'lib/rexml/entity.rb', line 23

def ref
  @ref
end

Class Method Details

.matches?(string) ⇒ Boolean

Evaluates whether the given string matchs an entity definition, returning true if so, and false otherwise.

Returns:

  • (Boolean)


68
69
70
# File 'lib/rexml/entity.rb', line 68

def Entity::matches? string
	(ENTITYDECL =~ string) == 0
end

Instance Method Details

#normalizedObject

Returns the value of this entity unprocessed – raw. This is the normalized value; that is, with all %ent; and &ent; entities intact



86
87
88
# File 'lib/rexml/entity.rb', line 86

def normalized
	@value
end

#to_sObject

Returns this entity as a string. See write().



114
115
116
117
118
# File 'lib/rexml/entity.rb', line 114

def to_s
	rv = ''
	write rv
	rv
end

#unnormalizedObject

Evaluates to the unnormalized value of this entity; that is, replacing all entities – both %ent; and &ent; entities. This differs from value() in that value only replaces %ent; entities.



75
76
77
78
79
80
# File 'lib/rexml/entity.rb', line 75

def unnormalized
	v = value()
	return nil if v.nil?
	@unnormalized = Text::unnormalize(v, parent)
	@unnormalized
end

#valueObject

Returns the value of this entity. At the moment, only internal entities are processed. If the value contains internal references (IE, %blah;), those are replaced with their values. IE, if the doctype contains:

<!ENTITY % foo "bar">
<!ENTITY yada "nanoo %foo; nanoo>

then:

doctype.entity('yada').value   #-> "nanoo bar nanoo"


129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rexml/entity.rb', line 129

def value
	if @value
		matches = @value.scan(PEREFERENCE_RE)
		rv = @value.clone
		if @parent
			matches.each do |entity_reference|
				entity_value = @parent.entity( entity_reference[0] )
				rv.gsub!( /%#{entity_reference};/um, entity_value )
			end
		end
		return rv
	end
	nil
end

#write(out, indent = -1) ⇒ Object

Write out a fully formed, correct entity definition (assuming the Entity object itself is valid.)



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/rexml/entity.rb', line 92

def write out, indent=-1
	out << '<!ENTITY '
	out << '% ' if @reference
	out << @name
	out << ' '
	if @external
		out << @external << ' '
		if @pubid
			q = @pubid.include?('"')?"'":'"'
			out << q << @pubid << q << ' '
		end
		q = @ref.include?('"')?"'":'"'
		out << q << @ref << q
		out << ' NDATA ' << @ndata if @ndata
	else
		q = @value.include?('"')?"'":'"'
		out << q << @value << q
	end
	out << '>'
end