1 | require "rexml/namespace"
|
---|
2 | require 'rexml/text'
|
---|
3 |
|
---|
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
|
---|
12 |
|
---|
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
|
---|
19 |
|
---|
20 | # Constructor.
|
---|
21 | #
|
---|
22 | # Attribute.new( attribute_to_clone )
|
---|
23 | # Attribute.new( source )
|
---|
24 | # Attribute.new( "attr", "attr_value" )
|
---|
25 | # Attribute.new( "attr", "attr_value", parent_element )
|
---|
26 | def initialize( first, second=nil, parent=nil )
|
---|
27 | @normalized = @unnormalized = @element = nil
|
---|
28 | if first.kind_of? Attribute
|
---|
29 | self.name = first.expanded_name
|
---|
30 | @value = first.value
|
---|
31 | if second.kind_of? Element
|
---|
32 | @element = second
|
---|
33 | else
|
---|
34 | @element = first.element
|
---|
35 | end
|
---|
36 | elsif first.kind_of? String
|
---|
37 | @element = parent if parent.kind_of? Element
|
---|
38 | self.name = first
|
---|
39 | @value = second.to_s
|
---|
40 | else
|
---|
41 | raise "illegal argument #{first.class.name} to Attribute constructor"
|
---|
42 | end
|
---|
43 | end
|
---|
44 |
|
---|
45 | # Returns the namespace of the attribute.
|
---|
46 | #
|
---|
47 | # e = Element.new( "elns:myelement" )
|
---|
48 | # e.add_attribute( "nsa:a", "aval" )
|
---|
49 | # e.add_attribute( "b", "bval" )
|
---|
50 | # e.attributes.get_attribute( "a" ).prefix # -> "nsa"
|
---|
51 | # e.attributes.get_attribute( "b" ).prefix # -> "elns"
|
---|
52 | # a = Attribute.new( "x", "y" )
|
---|
53 | # a.prefix # -> ""
|
---|
54 | def prefix
|
---|
55 | pf = super
|
---|
56 | if pf == ""
|
---|
57 | pf = @element.prefix if @element
|
---|
58 | end
|
---|
59 | pf
|
---|
60 | end
|
---|
61 |
|
---|
62 | # Returns the namespace URL, if defined, or nil otherwise
|
---|
63 | #
|
---|
64 | # e = Element.new("el")
|
---|
65 | # e.add_attributes({"xmlns:ns", "http://url"})
|
---|
66 | # e.namespace( "ns" ) # -> "http://url"
|
---|
67 | def namespace arg=nil
|
---|
68 | arg = prefix if arg.nil?
|
---|
69 | @element.namespace arg
|
---|
70 | end
|
---|
71 |
|
---|
72 | # Returns true if other is an Attribute and has the same name and value,
|
---|
73 | # false otherwise.
|
---|
74 | def ==( other )
|
---|
75 | other.kind_of?(Attribute) and other.name==name and other.value==@value
|
---|
76 | end
|
---|
77 |
|
---|
78 | # Creates (and returns) a hash from both the name and value
|
---|
79 | def hash
|
---|
80 | name.hash + value.hash
|
---|
81 | end
|
---|
82 |
|
---|
83 | # Returns this attribute out as XML source, expanding the name
|
---|
84 | #
|
---|
85 | # a = Attribute.new( "x", "y" )
|
---|
86 | # a.to_string # -> "x='y'"
|
---|
87 | # b = Attribute.new( "ns:x", "y" )
|
---|
88 | # b.to_string # -> "ns:x='y'"
|
---|
89 | def to_string
|
---|
90 | "#@expanded_name='#{to_s().gsub(/'/, ''')}'"
|
---|
91 | end
|
---|
92 |
|
---|
93 | # Returns the attribute value, with entities replaced
|
---|
94 | def to_s
|
---|
95 | return @normalized if @normalized
|
---|
96 |
|
---|
97 | doctype = nil
|
---|
98 | if @element
|
---|
99 | doc = @element.document
|
---|
100 | doctype = doc.doctype if doc
|
---|
101 | end
|
---|
102 |
|
---|
103 | @unnormalized = nil
|
---|
104 | @normalized = Text::normalize( @value, doctype )
|
---|
105 | end
|
---|
106 |
|
---|
107 | # Returns the UNNORMALIZED value of this attribute. That is, entities
|
---|
108 | # have been expanded to their values
|
---|
109 | def value
|
---|
110 | return @unnormalized if @unnormalized
|
---|
111 | doctype = nil
|
---|
112 | if @element
|
---|
113 | doc = @element.document
|
---|
114 | doctype = doc.doctype if doc
|
---|
115 | end
|
---|
116 | @normalized = nil
|
---|
117 | @unnormalized = Text::unnormalize( @value, doctype )
|
---|
118 | end
|
---|
119 |
|
---|
120 | # Returns a copy of this attribute
|
---|
121 | def clone
|
---|
122 | Attribute.new self
|
---|
123 | end
|
---|
124 |
|
---|
125 | # Sets the element of which this object is an attribute. Normally, this
|
---|
126 | # is not directly called.
|
---|
127 | #
|
---|
128 | # Returns this attribute
|
---|
129 | def element=( element )
|
---|
130 | @element = element
|
---|
131 | self
|
---|
132 | end
|
---|
133 |
|
---|
134 | # Removes this Attribute from the tree, and returns true if successfull
|
---|
135 | #
|
---|
136 | # This method is usually not called directly.
|
---|
137 | def remove
|
---|
138 | @element.attributes.delete self.name unless @element.nil?
|
---|
139 | end
|
---|
140 |
|
---|
141 | # Writes this attribute (EG, puts 'key="value"' to the output)
|
---|
142 | def write( output, indent=-1 )
|
---|
143 | output << to_string
|
---|
144 | end
|
---|
145 |
|
---|
146 | def node_type
|
---|
147 | :attribute
|
---|
148 | end
|
---|
149 |
|
---|
150 | def inspect
|
---|
151 | rv = ""
|
---|
152 | write( rv )
|
---|
153 | rv
|
---|
154 | end
|
---|
155 |
|
---|
156 | def xpath
|
---|
157 | path = @element.xpath
|
---|
158 | path += "/@#{self.expanded_name}"
|
---|
159 | return path
|
---|
160 | end
|
---|
161 | end
|
---|
162 | end
|
---|
163 | #vim:ts=2 sw=2 noexpandtab:
|
---|