Class: Ox::Element
Overview
An Element represents a element of an XML document. It has a name, attributes, and sub-nodes.
To access the child elements or attributes there are several options. One is to walk the nodes and attributes. Another is to use the locate() method. The easiest for simple regularly formatted XML is to reference the sub elements or attributes simply by name. Repeating elements with the same name can be referenced with an element count as well. A few examples should explain the 'easy' API more clearly.
Example
doc = Ox.parse(%Q{ <?xml?> <People> <Person age="58"> <given>Peter</given> <surname>Ohler</surname> </Person> <Person> <given>Makie</given> <surname>Ohler</surname> </Person> </People> }) doc.People.Person.given.text => "Peter" doc.People.Person(1).given.text => "Makie" doc.People.Person.age => "58"
Direct Known Subclasses
Instance Attribute Summary
Attributes inherited from Node
Instance Method Summary (collapse)
-
- (Object) <<(node)
Appends a Node to the Element's nodes array.
- - (Object) alocate(path, found)
-
- (Boolean) eql?(other)
(also: #==)
Returns true if this Object and other are of the same type and have the equivalent value and the equivalent elements otherwise false is returned.
-
- (Element) initialize(name)
constructor
Creates a new Element with the specified name.
-
- (Object) locate(path)
Returns an array of Nodes or Strings that correspond to the locations specified by the path parameter.
-
- (Element|Node|String|nil) method_missing(id, *args, &block)
Handles the 'easy' API that allows navigating a simple XML by referencing elements and attributes by name.
-
- (Array) nodes
Returns the Element's nodes array.
-
- (Object) text
Returns the first String in the elements nodes array or nil if there is no String node.
Methods included from HasAttrs
Constructor Details
- (Element) initialize(name)
Creates a new Element with the specified name.
41 42 43 44 45 |
# File 'lib/ox/element.rb', line 41 def initialize(name) super @attributes = nil @nodes = nil end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
- (Element|Node|String|nil) method_missing(id, *args, &block)
Handles the 'easy' API that allows navigating a simple XML by referencing elements and attributes by name.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/ox/element.rb', line 135 def method_missing(id, *args, &block) ids = id.to_s i = args[0].to_i # will be 0 if no arg or parsing fails nodes.each do |n| if (n.is_a?(Element) || n.is_a?(Instruct)) && (n.value == id || n.value == ids) return n if 0 == i i -= 1 end end if instance_variable_defined?(:@attributes) return @attributes[id] if @attributes.has_key?(id) return @attributes[ids] if @attributes.has_key?(ids) end raise NoMethodError.new("#{ids} not found", name) end |
Instance Method Details
- (Object) <<(node)
Appends a Node to the Element's nodes array. Returns the element itself so multiple appends can be chained together.
59 60 61 62 63 64 |
# File 'lib/ox/element.rb', line 59 def <<(node) @nodes = [] if !instance_variable_defined?(:@nodes) or @nodes.nil? raise "argument to << must be a String or Ox::Node." unless node.is_a?(String) or node.is_a?(Node) @nodes << node self end |
- (Object) alocate(path, found)
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 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/ox/element.rb', line 153 def alocate(path, found) step = path[0] if step.start_with?('@') # attribute raise InvalidPath.new(path) unless 1 == path.size if instance_variable_defined?(:@attributes) step = step[1..-1] sym_step = step.to_sym @attributes.each do |k,v| found << v if ('?' == step or k == step or k == sym_step) end end else # element name if (i = step.index('[')).nil? # just name name = step qual = nil else name = step[0..i-1] raise InvalidPath.new(path) unless step.end_with?(']') i += 1 qual = step[i..i] # step[i] would be better but some rubies (jruby, ree, rbx) take that as a Fixnum. if '0' <= qual and qual <= '9' qual = '+' else i += 1 end index = step[i..-2].to_i end if '?' == name or '*' == name match = nodes elsif '^' == name[0..0] # 1.8.7 thinks name[0] is a fixnum case name[1..-1] when 'Element' match = nodes.select { |e| e.is_a?(Element) } when 'String', 'Text' match = nodes.select { |e| e.is_a?(String) } when 'Comment' match = nodes.select { |e| e.is_a?(Comment) } when 'CData' match = nodes.select { |e| e.is_a?(CData) } when 'DocType' match = nodes.select { |e| e.is_a?(DocType) } else #puts "*** no match on #{name}" match = [] end else match = nodes.select { |e| e.is_a?(Element) and name == e.name } end unless qual.nil? or match.empty? case qual when '+' match = index < match.size ? [match[index]] : [] when '-' match = index <= match.size ? [match[-index]] : [] when '<' match = 0 < index ? match[0..index - 1] : [] when '>' match = index <= match.size ? match[index + 1..-1] : [] else raise InvalidPath.new(path) end end if (1 == path.size) match.each { |n| found << n } elsif '*' == name match.each { |n| n.alocate(path, found) if n.is_a?(Element) } match.each { |n| n.alocate(path[1..-1], found) if n.is_a?(Element) } else match.each { |n| n.alocate(path[1..-1], found) if n.is_a?(Element) } end end end |
- (Boolean) eql?(other) Also known as: ==
Returns true if this Object and other are of the same type and have the equivalent value and the equivalent elements otherwise false is returned.
70 71 72 73 74 75 76 |
# File 'lib/ox/element.rb', line 70 def eql?(other) return false if (other.nil? or self.class != other.class) return false unless super(other) return false unless self.attributes == other.attributes return false unless self.nodes == other.nodes true end |
- (Object) locate(path)
Returns an array of Nodes or Strings that correspond to the locations specified by the path parameter. The path parameter describes the path to the return values which can be either nodes in the XML or attributes. The path is a relative description. There are similarities between the locate() method and XPath but locate does not follow the same rules as XPath. The syntax is meant to be simpler and more Ruby like.
Like XPath the path delimiters are the slash (/) character. The path is split on the delimiter and each element of the path then describes the child of the current Element to traverse.
Attributes are specified with an @ prefix.
Each element name in the path can be followed by a bracket expression that narrows the paths to traverse. Supported expressions are numbers with a preceeding qualifier. Qualifiers are -, , <, and >. The qualifier is the default. A - qualifier indicates the index begins at the end of the children just like for Ruby Arrays. The < and > qualifiers indicates all elements either less than or greater than should be matched. Note that unlike XPath, the element index starts at 0 similar to Ruby be contrary to XPath.
Element names can also be wildcard characters. A * indicates any decendent should be followed. A ? indicates any single Element can match the wildcard. A ^ character followed by the name of a Class will match any node of the specified class. Valid class names are Element, Comment, String (or Text), CData, DocType.
Examples are:
-
element.locate("Family/Pete/*")returns all children of the Pete Element. -
element.locate("Family/?[1]")returns the first element in the Family Element. -
element.locate("Family/?[<3]")returns the first 3 elements in the Family Element. -
element.locate("Family/?/@age")returns the arg attribute for each child in the Family Element. -
element.locate("Family/*/@type")returns the type attribute value for decendents of the Family. -
element.locate("Family/^Comment")returns any comments that are a child of Family.
122 123 124 125 126 127 128 |
# File 'lib/ox/element.rb', line 122 def locate(path) return [self] if path.nil? found = [] pa = path.split('/') alocate(pa, found) found end |
- (Array) nodes
Returns the Element's nodes array. These are the sub-elements of this Element.
51 52 53 54 |
# File 'lib/ox/element.rb', line 51 def nodes @nodes = [] if !instance_variable_defined?(:@nodes) or @nodes.nil? @nodes end |
- (Object) text
Returns the first String in the elements nodes array or nil if there is no String node.
81 82 83 84 |
# File 'lib/ox/element.rb', line 81 def text() nodes.each { |n| return n if n.is_a?(String) } nil end |