File: rexml/attribute.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: REXML#4
  class: Attribute#9
includes
  Namespace ( REXML )
  Node ( REXML )
inherits from
  Object ( Builtin-Module )
has properties
attribute: element [R] #14
attribute: normalized [W] #17
constant: PATTERN #18
method: initialize / 3 #42
method: prefix #70
method: namespace #83
method: == / 1 #90
method: hash #95
method: to_string #105
method: to_s #114
method: value #130
method: clone #143
method: element= / 1 #151
method: remove #159
method: write / 2 #164
method: node_type #168
method: inspect #172
method: xpath #178

Class Hierarchy

Object ( Builtin-Module )
  Attribute ( REXML ) #9

Code

   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      # 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
  60 
  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
  77 
  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
  87 
  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
  93 
  94      # Creates (and returns) a hash from both the name and value
  95      def hash
  96        name.hash + value.hash
  97      end
  98 
  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
 112 
 113      # Returns the attribute value, with entities replaced
 114      def to_s
 115        return @normalized if @normalized
 116 
 117        doctype = nil
 118        if @element
 119          doc = @element.document
 120          doctype = doc.doctype if doc
 121        end
 122 
 123        @normalized = Text::normalize( @unnormalized, doctype )
 124        @unnormalized = nil
 125        @normalized
 126      end
 127 
 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
 141 
 142      # Returns a copy of this attribute
 143      def clone
 144        Attribute.new self
 145      end
 146 
 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
 155 
 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
 162 
 163      # Writes this attribute (EG, puts 'key="value"' to the output)
 164      def write( output, indent=-1 )
 165        output << to_string
 166      end
 167 
 168      def node_type
 169        :attribute
 170      end
 171 
 172      def inspect
 173        rv = ""
 174        write( rv )
 175        rv
 176      end
 177 
 178      def xpath
 179        path = @element.xpath
 180        path += "/@#{self.expanded_name}"
 181        return path
 182      end
 183    end
 184  end
 185  #vim:ts=2 sw=2 noexpandtab: