Imported File#ftype spec from rubyspecs.
[rbx.git] / lib / rexml / attribute.rb
blob89c1ada36c92304de51d42f01d86c8b7fbcdae5c
1 require "rexml/namespace"
2 require 'rexml/text'
4 module REXML
5         # Defines an Element Attribute; IE, a attribute=value pair, as in:
6         # <element attribute="value"/>.  Attributes can be in their own
7         # namespaces.  General users of REXML will not interact with the
8         # Attribute class much.
9         class Attribute
10                 include Node
11                 include Namespace
13                 # The element to which this attribute belongs
14                 attr_reader :element
15                 # The normalized value of this attribute.  That is, the attribute with
16                 # entities intact.
17                 attr_writer :normalized 
18                 PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
20                 # Constructor.
21     # FIXME: The parser doesn't catch illegal characters in attributes
22     #
23     # first:: 
24     #   Either: an Attribute, which this new attribute will become a
25     #   clone of; or a String, which is the name of this attribute
26     # second::
27     #   If +first+ is an Attribute, then this may be an Element, or nil.
28     #   If nil, then the Element parent of this attribute is the parent
29     #   of the +first+ Attribute.  If the first argument is a String, 
30     #   then this must also be a String, and is the content of the attribute.  
31     #   If this is the content, it must be fully normalized (contain no
32     #   illegal characters).
33     # parent::
34     #   Ignored unless +first+ is a String; otherwise, may be the Element 
35     #   parent of this attribute, or nil.
36     #
37                 #
38                 #  Attribute.new( attribute_to_clone )
39                 #  Attribute.new( attribute_to_clone, parent_element )
40                 #  Attribute.new( "attr", "attr_value" )
41                 #  Attribute.new( "attr", "attr_value", parent_element )
42                 def initialize( first, second=nil, parent=nil )
43                         @normalized = @unnormalized = @element = nil
44                         if first.kind_of? Attribute
45                                 self.name = first.expanded_name
46                                 @unnormalized = first.value
47                                 if second.kind_of? Element
48                                         @element = second
49                                 else
50                                         @element = first.element
51                                 end
52                         elsif first.kind_of? String
53                                 @element = parent
54                                 self.name = first
55                                 @normalized = second.to_s
56                         else
57                                 raise "illegal argument #{first.class.name} to Attribute constructor"
58                         end
59                 end
61                 # Returns the namespace of the attribute.
62                 # 
63                 #  e = Element.new( "elns:myelement" )
64                 #  e.add_attribute( "nsa:a", "aval" )
65                 #  e.add_attribute( "b", "bval" )
66                 #  e.attributes.get_attribute( "a" ).prefix   # -> "nsa"
67                 #  e.attributes.get_attribute( "b" ).prefix   # -> "elns"
68                 #  a = Attribute.new( "x", "y" )
69                 #  a.prefix                                   # -> ""
70                 def prefix
71                         pf = super
72                         if pf == ""
73                                 pf = @element.prefix if @element
74                         end
75                         pf
76                 end
78                 # Returns the namespace URL, if defined, or nil otherwise
79                 # 
80                 #  e = Element.new("el")
81                 #  e.add_attributes({"xmlns:ns", "http://url"})
82                 #  e.namespace( "ns" )              # -> "http://url"
83                 def namespace arg=nil
84                         arg = prefix if arg.nil?
85                         @element.namespace arg
86                 end
88                 # Returns true if other is an Attribute and has the same name and value,
89                 # false otherwise.
90                 def ==( other )
91                         other.kind_of?(Attribute) and other.name==name and other.value==value
92                 end
94                 # Creates (and returns) a hash from both the name and value
95                 def hash
96                         name.hash + value.hash
97                 end
99                 # Returns this attribute out as XML source, expanding the name
100                 #
101                 #  a = Attribute.new( "x", "y" )
102                 #  a.to_string     # -> "x='y'"
103                 #  b = Attribute.new( "ns:x", "y" )
104                 #  b.to_string     # -> "ns:x='y'"
105                 def to_string
106                         if @element and @element.context and @element.context[:attribute_quote] == :quote
107                                 %Q^#@expanded_name="#{to_s().gsub(/"/, '&quote;')}"^
108                         else
109                                 "#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'"
110                         end
111                 end
113                 # Returns the attribute value, with entities replaced
114                 def to_s
115                         return @normalized if @normalized
117                         doctype = nil
118                         if @element
119                                 doc = @element.document
120                                 doctype = doc.doctype if doc
121                         end
123                         @normalized = Text::normalize( @unnormalized, doctype )
124                         @unnormalized = nil
125       @normalized
126                 end
128                 # Returns the UNNORMALIZED value of this attribute.  That is, entities
129                 # have been expanded to their values
130                 def value
131                         return @unnormalized if @unnormalized
132                         doctype = nil
133                         if @element
134                                 doc = @element.document
135                                 doctype = doc.doctype if doc
136                         end
137                         @unnormalized = Text::unnormalize( @normalized, doctype )
138                         @normalized = nil
139       @unnormalized
140                 end
142                 # Returns a copy of this attribute
143                 def clone
144                         Attribute.new self
145                 end
147                 # Sets the element of which this object is an attribute.  Normally, this
148                 # is not directly called.
149                 #
150                 # Returns this attribute
151                 def element=( element )
152                         @element = element
153                         self
154                 end
156                 # Removes this Attribute from the tree, and returns true if successfull
157                 # 
158                 # This method is usually not called directly.
159                 def remove
160                         @element.attributes.delete self.name unless @element.nil?
161                 end
163                 # Writes this attribute (EG, puts 'key="value"' to the output)
164                 def write( output, indent=-1 )
165                         output << to_string
166                 end
168     def node_type
169       :attribute
170     end
172     def inspect
173       rv = ""
174       write( rv )
175       rv
176     end
178     def xpath
179       path = @element.xpath
180       path += "/@#{self.expanded_name}"
181       return path
182     end
183         end
185 #vim:ts=2 sw=2 noexpandtab: