Class | SDL4R::Tag |
In: |
lib/sdl4r/tag.rb
|
Parent: | Object |
SDL documents are made of Tags.
See the README for a longer explanation on SDL documents.
Do not assume that methods returning sets (Hash, Array, etc) of children/values/attributes/etc in this class returns copies or implementations. It can be one or the other depending on the method. The implementations are designed to be correct and somewhat efficient, not too protect the Tag internal state from ill-use of the returned values.
Daniel Leuck, Philippe Vosges
Creates an empty tag in the given namespace. If the namespace is nil it will be coerced to an empty String.
tag = Tag.new("name") tag = Tag.new("namespace", "name") tag = Tag.new("fruit") do add_value 2 new_child("orange") do set_attribute("quantity", 2) end end
which builds the following SDL structure
fruit 2 { orange quantity=2 }
ArgumentError if the name is not a legal SDL identifier (see SDL4R#validate_identifier) or the namespace is non-blank and is not a legal SDL identifier.
# File lib/sdl4r/tag.rb, line 95 def initialize(namespace, name = nil, &block) namespace, name = to_nns namespace, name raise ArgumentError, "tag namespace must be a String" unless namespace.is_a? String raise ArgumentError, "tag name must be a String" unless name.is_a? String SDL4R.validate_identifier(namespace) unless namespace.empty? @namespace = namespace name = name.to_s.strip raise ArgumentError, "Tag name cannot be nil or empty" if name.empty? SDL4R.validate_identifier(name) @name = name @children = [] @values = [] # a Hash of Hash : {namespace => {name => value}} # The default namespace is represented by an empty string. @attributesByNamespace = {} instance_eval(&block) if block_given? end
Adds the given object as a child if it is a Tag, as an attribute if it is a Hash {key => value} (supports namespaces), or as a value otherwise. If it is an array, each of its elements is added to this Tag via this operator. If any of its elements is itself an array, then an anonymous tag is created and the array is passed to it via this operator (see the examples below)
tag << Tag.new("child") tag << 123 # new integer value tag << "islamabad" # new string value tag << { "metric:length" => 1027 } # new attribute (with namespace) tag << [nil, 456, "abc"] # several values added tag = Tag.new("tag") tag << [[1, 2, 3], [4, 5, 6]] # tag { # 1 2 3 # 4 5 6 # }
Returns self.
Use other accessors for a stricter and less "magical" behavior.
# File lib/sdl4r/tag.rb, line 169 def <<(o) if o.is_a?(Tag) add_child(o) elsif o.is_a?(Hash) o.each_pair { |key, value| namespace, key = key.split(/:/) if key.match(/:/) namespace ||= "" set_attribute(namespace, key, value) } elsif o.is_a? Array o.each { |item| if item.is_a? Array anonymous = new_child("content") anonymous << item else self << item end } else add_value(o) end return self end
attribute(key) attribute(namespace, key)
Returns the attribute of the specified namespace of specified key or nil if not found.
# File lib/sdl4r/tag.rb, line 518 def attribute(namespace, key = nil) namespace, key = to_nns namespace, key attributes = @attributesByNamespace[namespace] return attributes.nil? ? nil : attributes[key] end
Returns a Hash of the attributes of the specified namespace (default is all) or enumerates them.
tag.attributes # => { "length" => 123, "width" = 25.4, "orig:color" => "gray" } tag.attributes("orig") do |namespace, key, value| p "#{namespace}:#{key} = #{value}" end
namespace:: namespace of the returned attributes. If nil, all attributes are returned with qualified names (e.g. "meat:color"). If "", attributes of the default namespace are returned.
# File lib/sdl4r/tag.rb, line 556 def attributes(namespace = nil, &block) # :yields: namespace, key, value if block_given? each_attribute(namespace, &block) else if namespace.nil? hash = {} each_attribute do | namespace, key, value | qualified_name = namespace.empty? ? key : namespace + ':' + key hash[qualified_name] = value end return hash else return @attributesByNamespace[namespace] end end end
Sets all the attributes of the default namespace for this Tag in one operation.
See set_attributes
# File lib/sdl4r/tag.rb, line 660 def attributes=(attribute_hash) set_attributes(attribute_hash) end
child child(name) child(recursive, name)
Get the first child with the given name, optionally using a recursive search.
name: | the name of the child Tag. If nil, the first child is returned (nil if there are |
no children at all).
Returns the first child tag having the given name or nil if no such child exists
# File lib/sdl4r/tag.rb, line 313 def child(recursive = false, name = nil) if name.nil? name = recursive recursive = false end unless name return @children.first else each_child(recursive, name) { |child| return child } end end
children(recursive) children(recursive, name) children(recursive, namespace, name) children(recursive) { |child| ... } children(recursive, name) { |child| ... } children(recursive, namespace, name) { |child| ... }
Returns an Array of the children Tags of this Tag or enumerates them.
recursive: | if true children and all descendants will be returned. False by default. |
name: | if not nil, only children having this name will be returned. Nil by default. |
namespace: | use nil for all namespaces and "" for the default one. Nil by default. |
tag.children # => array of the children tag.children(true) { |descendant| ... } tag.children(false, "name") # => children of name "name" tag.children(false, "ns", nil) # => children of namespace "ns"
# File lib/sdl4r/tag.rb, line 258 def children(recursive = false, namespace = nil, name = :DEFAULT, &block) # :yields: child if name == :DEFAULT name = namespace namespace = nil end if block_given? each_child(recursive, namespace, name, &block) return nil else unless recursive or name or namespace return @children else result = [] each_child(recursive, namespace, name) { |child| result << child } return result end end end
Returns a string representation of the children tags.
linePrefix: | A prefix to insert before every line. |
s: | a String that receives the string representation |
TODO: break up long lines using the backslash
# File lib/sdl4r/tag.rb, line 833 def children_to_string(line_prefix = "", s = "") @children.each do |child| s << child.to_string(line_prefix) << $/ end return s end
Returns the values of all the children with the given name. If the child has more than one value, all the values will be added as an array. If the child has no value, nil will be added. The search is not recursive.
name: | if nil, all children are considered (nil by default). |
# File lib/sdl4r/tag.rb, line 287 def children_values(name = nil) children_values = [] each_child(false, name) { |child| case child.values.size when 0 children_values << nil when 1 children_values << child.value else children_values << child.values end } return children_values end
Clears the attributes of the specified namespace or all the attributes if namespace is nil.
# File lib/sdl4r/tag.rb, line 596 def clear_attributes(namespace = nil) if namespace.nil? @attributesByNamespace.clear else @attributesByNamespace.delete(namespace) end end
Returns true if this tag (including all of its values, attributes, and children) is equivalent to the given tag.
Returns true if the tags are equivalet
# File lib/sdl4r/tag.rb, line 846 def eql?(o) # this is safe because to_string() dumps the full state return o.is_a?(Tag) && o.to_string == to_string; end
Indicates whether there is at least an attribute in this Tag.
has_attribute?
Indicates whether there is the specified attribute exists in this Tag.
has_attribute?(key) has_attribute?(namespace, key)
# File lib/sdl4r/tag.rb, line 531 def has_attribute?(namespace = nil, key = nil) namespace, key = to_nns namespace, key if namespace or key attributes = @attributesByNamespace[namespace] return attributes.nil? ? false : attributes.has_key?(key) else attributes { return true } return false end end
The namespace to set. nil will be coerced to the empty string.
Raises ArgumentError if the namespace is non-blank and is not
a legal SDL identifier (see {@link SDL4R#validate_identifier(String)})
# File lib/sdl4r/tag.rb, line 680 def namespace=(a_namespace) a_namespace = a_namespace.to_s SDL4R.validate_identifier(a_namespace) unless a_namespace.empty? @namespace = a_namespace end
Creates a new child tag. Can take a block so that you can write something like:
car = Tag.new("car") do new_child("wheels") do self << 4 end end
The context of execution of the given block is the child instance
Returns the created child Tag.
# File lib/sdl4r/tag.rb, line 132 def new_child(*args, &block) return add_child Tag.new(*args, &block) end
Adds all the tags specified in the given IO, String, Pathname or URI to this Tag.
Returns this Tag after adding all the children read from input.
# File lib/sdl4r/tag.rb, line 690 def read(input) if input.is_a? String read_from_io(true) { StringIO.new(input) } elsif input.is_a? Pathname read_from_io(true) { input.open("r:UTF-8") } elsif input.is_a? URI read_from_io(true) { input.open } else read_from_io(false) { input } end return self end
Reads and parses the io returned by the specified block and closes this io if close_io is true.
# File lib/sdl4r/tag.rb, line 709 def read_from_io(close_io) io = yield begin Parser.new(io).parse.each do |tag| add_child(tag) end ensure if close_io io.close rescue IOError end end end
remove_attribute(key) remove_attribute(namespace, key)
Removes the attribute, whose name and namespace are specified.
key: | name of the removed atribute |
namespace: | namespace of the removed attribute (equal to "", default namespace, by default) |
Returns the value of the removed attribute or nil if it didn‘t exist.
# File lib/sdl4r/tag.rb, line 587 def remove_attribute(namespace, key = nil) namespace, key = to_nns namespace, key attributes = @attributesByNamespace[namespace] return attributes.nil? ? nil : attributes.delete(key) end
set_attribute(key, value) set_attribute(namespace, key, value)
Set an attribute in the given namespace for this tag. The allowable attribute value types are the same as those allowed for {@link addValue(Object)}
namespace: | The namespace for this attribute |
key: | The attribute key |
value: | The attribute value |
@throws IllegalArgumentException if the key is not a legal SDL
identifier (see {@link SDL4R#validateIdentifier(String)}), or the namespace is non-blank and is not a legal SDL identifier, or the value is not a legal SDL type
# File lib/sdl4r/tag.rb, line 488 def set_attribute(namespace, key, value = :default) if value == :default value = key key = namespace namespace = "" end raise ArgumentError, "attribute namespace must be a String" unless namespace.is_a? String raise ArgumentError, "attribute key must be a String" unless key.is_a? String raise ArgumentError, "attribute key cannot be empty" if key.empty? SDL4R.validate_identifier(namespace) unless namespace.empty? SDL4R.validate_identifier(key) attributes = @attributesByNamespace[namespace] if attributes.nil? attributes = {} @attributesByNamespace[namespace] = attributes end attributes[key] = SDL4R.coerce_or_fail(value) end
set_attributes(attribute_hash) set_attributes(namespace, attribute_hash)
Sets the attributes specified by a Hash in the given namespace in one operation. The previous attributes of the specified namespace are removed. See set_attribute for allowable attribute value types.
attributes: | a Hash where keys are attribute keys |
namespace: | "" (default namespace) by default |
Raises an ArgumentError if any key in the map is not a legal SDL
identifier (see SDL4R#validate_identifier), or any value is not a legal SDL type.
# File lib/sdl4r/tag.rb, line 637 def set_attributes(namespace, attribute_hash = nil) if attribute_hash.nil? attribute_hash = namespace namespace = "" end raise ArgumentError, "namespace can't be nil" if namespace.nil? raise ArgumentError, "attribute_hash should be a Hash" unless attribute_hash.is_a? Hash namespace_attributes = @attributesByNamespace[namespace] namespace_attributes.clear if namespace_attributes attribute_hash.each_pair do |key, value| # Calling set_attribute() is required to ensure validations set_attribute(namespace, key, value) end end
Returns a new Hash where the children‘s names as keys and their values as the key‘s value. Example:
child1 "toto" child2 2
would give
{ "child1" => "toto", "child2" => 2 }
# File lib/sdl4r/tag.rb, line 375 def to_child_hash hash = {} children { |child| hash[child.name] = child.value } return hash end
Returns a new Hash where the children‘s names as keys and their values as the key‘s value. Values are converted to Strings. nil values become empty Strings. Example:
child1 "toto" child2 2 child3 null
would give
{ "child1" => "toto", "child2" => "2", "child3" => "" }
# File lib/sdl4r/tag.rb, line 393 def to_child_string_hash hash = {} children do |child| # FIXME: it is quite hard to be sure whether we should mimic the Java version # as there might be a lot of values that don't translate nicely to Strings. hash[child.name] = child.value.to_s end return hash end
linePrefix: | A prefix to insert before every line. |
Returns A string representation of this tag using SDL
TODO: break up long lines using the backslash
# File lib/sdl4r/tag.rb, line 776 def to_string(line_prefix = "", indent = "\t") line_prefix = "" if line_prefix.nil? s = "" s << line_prefix if name == "content" && namespace.empty? skip_value_space = true else skip_value_space = false s << "#{namespace}:" unless namespace.empty? s << name end # output values values do |value| if skip_value_space skip_value_space = false else s << " " end s << SDL4R.format(value, true, line_prefix, indent) end # output attributes unless @attributesByNamespace.empty? all_attributes_hash = attributes all_attributes_array = all_attributes_hash.sort { |a, b| namespace1, name1 = a[0].split(':') namespace1, name1 = "", namespace1 if name1.nil? namespace2, name2 = b[0].split(':') namespace2, name2 = "", namespace2 if name2.nil? diff = namespace1 <=> namespace2 diff == 0 ? name1 <=> name2 : diff } all_attributes_array.each do |attribute_name, attribute_value| s << " " << attribute_name << '=' << SDL4R.format(attribute_value, true) end end # output children unless @children.empty? s << " {#{$/}" children_to_string(line_prefix + indent, s) s << line_prefix << ?} end return s end
Returns a string containing an XML representation of this tag. Values will be represented using _val0, _val1, etc.
line_prefix: | A prefix to insert before every line. |
uri_by_namespace: | a Hash giving the URIs for the namespaces. Nil to ignore this. |
# File lib/sdl4r/tag.rb, line 864 def to_xml_string(line_prefix = "", uri_by_namespace = nil) line_prefix ||= "" s = "" s << line_prefix << ?< s << "#{namespace}:" unless namespace.empty? s << name # output namespace declarations if uri_by_namespace uri_by_namespace.each_pair do |namespace, uri| if namespace s << " xmlns:#{namespace}=\"#{uri}\"" else s << " xmlns=\"#{uri}\"" end end end # output values unless @values.empty? i = 0 @values.each do |value| s << " _val" << i.to_s << "=\"" << SDL4R.format(value, false) << "\"" i += 1 end end # output attributes if has_attribute? attributes do |attribute_namespace, attribute_name, attribute_value| s << " " s << "#{attribute_namespace}:" unless attribute_namespace.empty? s << attribute_name << "=\"" << SDL4R.format(attribute_value, false) << ?" end end if @children.empty? s << "/>" else s << ">\n" @children.each do |child| s << child.to_xml_string(line_prefix + " ") << ?\n end s << line_prefix << "</" s << "#{namespace}:" unless namespace.empty? s << name << ?> end return s end
Set the values for this tag. See {@link addValue(Object)} for legal value types.
values: | The new values |
@throws IllegalArgumentException if the collection contains any values
which are not legal SDL types
# File lib/sdl4r/tag.rb, line 463 def values=(someValues) @values.clear() someValues.to_a.each { |v| # this is required to ensure validation of types add_value(v) } nil end
Write this tag out to the given IO or StringIO or String (optionally clipping the root.) Returns output.
output: | an IO or StringIO or a String to write to |
include_root: | if true this tag will be written out as the root element, if false only the |
children will be written. False by default.
# File lib/sdl4r/tag.rb, line 732 def write(output, include_root = false) if output.is_a? String io = StringIO.new(output) close_io = true # indicates we close the IO ourselves elsif output.is_a? IO or output.is_a? StringIO io = output close_io = false # let the caller close the IO else raise ArgumentError, "'output' should be a String or an IO but was #{output.class}" end if include_root io << to_s else first = true children do |child| io << $/ unless first first = false io << child.to_s end end io.close() if close_io output end