1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
# =XMPP4R - XMPP Library for Ruby
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
# Website::http://xmpp4r.github.io
require 'xmpp4r/rexmladdons'
module Jabber
##
# This class represents an XML element and provides functionality
# for automatic casting of XML element classes according to their
# element name and namespace.
#
# Deriving classes must met these criteria:
# * The element name and namespace must be specified by calling
# the name_xmlns class method
# * The class constructor must be callable with no mandatory parameter
class XMPPElement < REXML::Element
@@name_xmlns_classes = {}
@@force_xmlns = false
##
# Specify XML element name and xmlns for a deriving class,
# this pair and the class will be added to a global pool
#
# If the namespace is nil the class is a "wildcard class"
# matching elements with any xmlns if no other class with
# that namespace was defined
def self.name_xmlns(name, xmlns=nil)
@@name_xmlns_classes[[name, xmlns]] = self
end
##
# Set whether this element is always built with an xmlns attribute
def self.force_xmlns(force)
@@force_xmlns = force
end
##
# Whether this element is always built with an xmlns attribute
def self.force_xmlns?
@@force_xmlns
end
##
# Find the name and namespace for a given class.
# This class must have registered these two values
# by calling name_xmlns at definition time.
#
# Raises an exception if none was found
# klass:: [Class]
# result:: [String, String] name and namespace
def self.name_xmlns_for_class(klass)
klass.ancestors.each do |klass1|
@@name_xmlns_classes.each do |name_xmlns,k|
if klass1 == k
return name_xmlns
end
end
end
raise NoNameXmlnsRegistered.new(klass)
end
##
# Find a class for given name and namespace
# name:: [String]
# xmlns:: [String]
# result:: A descendant of XMPPElement or REXML::Element
def self.class_for_name_xmlns(name, xmlns)
if @@name_xmlns_classes.has_key? [name, xmlns]
@@name_xmlns_classes[[name, xmlns]]
elsif @@name_xmlns_classes.has_key? [name, nil]
@@name_xmlns_classes[[name, nil]]
else
REXML::Element
end
end
##
# Import another REXML::Element descendant to:
# * Either an element class that registered with
# name and xmlns before
# * Or if none was found to the class itself
# (you may call this class method on a deriving class)
def self.import(element)
klass = class_for_name_xmlns(element.name, element.namespace)
if klass != self and klass.ancestors.include?(self)
klass.new.import(element)
else
self.new.import(element)
end
end
##
# Initialize this element, which will then be initialized
# with the name registered with name_xmlns.
def initialize(*arg)
if arg.empty?
name, xmlns = self.class::name_xmlns_for_class(self.class)
super(name)
if self.class::force_xmlns?
add_namespace(xmlns)
end
else
super
end
end
##
# Add a child element which will be imported according to the
# child's name and xmlns
# element:: [REXML::Element] Child
# result:: [REXML::Element or descendant of XMPPElement] New child
def typed_add(element)
if element.kind_of? REXML::Element
element_ns = (element.namespace.to_s == '') ? namespace : element.namespace
klass = XMPPElement::class_for_name_xmlns(element.name, element_ns)
if klass != element.class
element = klass.import(element)
end
end
super(element)
end
def parent=(new_parent)
if parent and parent.namespace('') == namespace('') and attributes['xmlns'].nil?
add_namespace parent.namespace('')
end
super
if new_parent and new_parent.namespace('') == namespace('')
delete_namespace
end
end
def clone
cloned = self.class.new
cloned.add_attributes self.attributes.clone
cloned.context = @context
cloned
end
##
# Generic XML attribute 'xml:lang'
# (REXML provides no shortcut)
def xml_lang
attributes['xml:lang']
end
##
# Set XML language attribute
def xml_lang=(l)
attributes['xml:lang'] = l
end
##
# Set XML language attribute (chainable)
def set_xml_lang(l)
self.xml_lang = l
self
end
end
end
|