Class: VCDOM::Element

Inherits:
Node
  • Object
show all
Includes:
Parent, Child
Defined in:
lib/vcdom/element.rb

Direct Known Subclasses

ElementNS

Instance Method Summary collapse

Methods included from Child

#_leave_from_tree, #_set_next_sibling, #_set_parent_node, #initialize_child, #next_sibling, #parent_node, #previous_sibling

Constructor Details

#initialize(doc, tag_name) ⇒ Element

:nodoc:



14
15
16
17
18
19
20
21
# File 'lib/vcdom/element.rb', line 14

def initialize( doc, tag_name ) # :nodoc:
  initialize_parent()
  super( doc )
  @local_name = tag_name
  # attributes
  @attr_nodes = Array.new()
  @attr_node_map = AttrNodeMap.new( @attr_nodes )
end

Instance Method Details

#append_child(new_child) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/vcdom/element.rb', line 36

def append_child( new_child )
  # ノードのタイプチェックなど
  if not new_child.is_a? Node then
    raise ArgumentError.new( "the argument [#{new_child}] is not an object of the expected class." )
  end
  # Element, Text, Comment, ProcessingInstruction, CDATASection, EntityReference
  case new_child.node_type
    when ELEMENT_NODE, TEXT_NODE, CDATA_SECTION_NODE, ENTITY_REFERENCE_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE then
      # OK
    else
      # ERROR
      raise "ERROR"
  end
  _append_child( new_child )
end

#attributesObject

attributes



53
54
55
# File 'lib/vcdom/element.rb', line 53

def attributes
  @attr_node_map
end

#child_element_countObject

The current number of child nodes of that element which are of nodeType ELEMENT_NODE. This value is not stored, but calculated when you access this attribute.



407
408
409
410
411
412
413
414
415
# File 'lib/vcdom/element.rb', line 407

def child_element_count
  num = 0
  self.each_child_node do |n|
    if n.node_type == ELEMENT_NODE then
      num += 1
    end
  end
  return num
end

#each_attr_nodeObject



56
57
58
59
60
# File 'lib/vcdom/element.rb', line 56

def each_attr_node
  @attr_nodes.each do |n|
    yield n
  end
end

#first_element_childObject

The first child node of that element which is of nodeType ELEMENT_NODE, as an Element object. If the element on which this attribute is accessed does not have any child nodes, or if none of those child nodes are element nodes, then this attribute return nil. (defiend at W3C Element Traversal Specification)



347
348
349
350
351
352
353
354
355
356
# File 'lib/vcdom/element.rb', line 347

def first_element_child
  n = self.first_child
  while n do
    if n.node_type == ELEMENT_NODE then
      break
    end
    n = n.next_sibling
  end
  return n
end

#get_attribute(name) ⇒ Object

Retrieves an attribute value by name.



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/vcdom/element.rb', line 88

def get_attribute( name )
  @attr_nodes.each do |attr|
    if attr.name == name then
      #//////////////////////////
      # 変更する
      #//////////////////////////
      return attr.value
    end
  end
  return ""
end

#get_attribute_ns(namespace_uri, local_name) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/vcdom/element.rb', line 123

def get_attribute_ns( namespace_uri, local_name )
  @attr_nodes.each do |attr|
    if attr.namespace_uri == namespace_uri and attr.local_name == local_name then
      #//////////////////////////
      # 変更する
      #//////////////////////////
      return attr.value
    end
  end
  return ""
end

#last_element_childObject

The last child node of that element which is of nodeType ELEMENT_NODE, as an Element object. If the element on which this attribute is accessed does not have any child nodes, or if none of those child nodes are element nodes, then this attribute return nil. (defiend at W3C Element Traversal Specification)



362
363
364
365
366
367
368
369
370
371
# File 'lib/vcdom/element.rb', line 362

def last_element_child
  n = self.last_child
  while n do
    if n.node_type == ELEMENT_NODE then
      break
    end
    n = n.previous_sibling
  end
  return n
end

#local_nameObject



32
33
34
# File 'lib/vcdom/element.rb', line 32

def local_name
  nil
end

#next_element_siblingObject

The sibling node of that element which most immediately follows that element in document order, and which is of nodeType ELEMENT_NODE, as an Element object. If the element on which this attribute is accessed does not have any following sibling nodes, or if none of those following sibling nodes are element nodes, then this attribute must return nil. (defiend at W3C Element Traversal Specification)



394
395
396
397
398
399
400
401
402
403
# File 'lib/vcdom/element.rb', line 394

def next_element_sibling
  n = self.next_sibling
  while n do
    if n.node_type == ELEMENT_NODE then
      break
    end
    n = n.next_sibling
  end
  return n
end

#node_typeObject



23
24
25
# File 'lib/vcdom/element.rb', line 23

def node_type
  ELEMENT_NODE
end

#normalize_namespacesObject

void Element.normalizeNamespaces()



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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/vcdom/element.rb', line 160

def normalize_namespaces()
  # non-namespace Attrs of Element
  non_ns_attrs = Array.new()
  # Pick up local namespace declarations
  # for ( all DOM Level 2 valid local namespace declaration attributes of Element ) {
  #   if (the namespace declaration is invalid) {
  #     Note: The prefix xmlns is used only to declare namespace bindings and
  #     is by definition bound to the namespace name http://www.w3.org/2000/xmlns/.
  #     It must not be declared. No other prefix may be bound to this namespace name.         
  #       ==> Report an error.
  #   } else {
  #       ==>  Record the namespace declaration
  #   }
  # }
  #ns = Hash.new()
  @attr_nodes.each do |n|
    if n.name == "xmlns" then
    #  ns[nil] = n[0].data
    elsif n.prefix == "xmlns" then
    #  ns[n.local_name.intern] = n[0].data
    else
      non_ns_attrs << n
    end
  end
  
  # Fixup element's namespace
  if self.namespace_uri then
    # when Element's namespaceURI is not nil
    # prefix / ns ペアが既にスコープ内に存在するかどうかの確認
    # この flag チェックは変更しないとダメかも...
    flag = false
    if self.prefix.nil? then
      #///////////////////////////////////
      # is_default_namespace だとダメー
      #///////////////////////////////////
      #if self.is_default_namespace( self.namespace_uri ) then
      #  flag = true
      #end
      n = self
      loop do
        if n.nil? then
          break
        elsif n.node_type == ELEMENT_NODE then
          if n.get_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns" ) == self.namespace_uri then
            flag = true
            break
          end
        end
        n = n.parent_node
      end
    else
      #///////////////////////////////////
      # lookup_namespace_uri だとダメー
      #///////////////////////////////////
      #if self.lookup_namespace_uri( self.prefix ) == self.namespace_uri then
      #  flag = true
      #end
      if self.prefix == "xml" then
        # ok?
        flag = true
      else
        n = self
        loop do
          if n.nil? then
            break
          elsif n.node_type == ELEMENT_NODE then
            if n.get_attribute_ns( "http://www.w3.org/2000/xmlns/", self.prefix ) == self.namespace_uri then
              flag = true
              break
            end
          end
          n = n.parent_node
        end
      end
    end
    if flag then
      # when Element's prefix/namespace pair (or default namespace, if no prefix) are within the scope of a binding
      #    ==> do nothing, declaration in scope is inherited
      # See section "B.1.1: Scope of a binding" for an example
    else
      # ==> Create a local namespace declaration attr for this namespace,
      #          with Element's current prefix (or a default namespace, if
      #          no prefix). If there's a conflicting local declaration
      #          already present, change its value to use this namespace.
      #          See section "B.1.2: Conflicting namespace declaration" for an example
      #          // NOTE that this may break other nodes within this Element's
      #          // subtree, if they're already using this prefix.
      #          // They will be repaired when we reach them.
      if self.prefix.nil? then
        self.set_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns", self.namespace_uri )
      else
        self.set_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns:#{self.prefix}", self.namespace_uri )
      end
    end
  else
    # when Element has no namespace URI:
    if self.local_name.nil? then
      # when Element's localName is null
      #       // DOM Level 1 node
      #       ==> if in process of validation against a namespace aware schema 
      #           (i.e XML Schema) report a fatal error: the processor can not recover 
      #           in this situation. 
      #           Otherwise, report an error: no namespace fixup will be performed on this node.
    else
      # when Element has no pseudo-prefix
      if self.prefix.nil? and not self.is_default_namespace( nil ) then
        # when there's a conflicting local default namespace declaration already present
        #        ==> change its value to use this empty namespace.
        self.set_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns", "" )
      elsif self.prefix and self.lookup_prefix( nil ) == self.prefix then
        self.set_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns:#{self.prefix}", "" )
      end
      #      // NOTE that this may break other nodes within this Element's
      #      // subtree, if they're already using the default namespaces.
      #      // They will be repaired when we reach them.
    end
  end
  
  # Examine and polish the attributes
  #for ( all non-namespace Attrs of Element )
  non_ns_attrs.each do |attr|
    if attr.namespace_uri then
      if attr.prefix == "xml" then
        # do nothing
      # when attr has a namespace URI
      elsif attr.prefix.nil? or self.lookup_namespace_uri( attr.prefix ) != attr.namespace_uri then
        # when attribute has no prefix (default namespace decl does not apply to attributes) 
        # OR attribute prefix is not declared OR conflict: attribute has a prefix that conflicts with a binding
        #        already active in scope)
        if not (new_prefix = self.lookup_prefix( attr.namespace_uri )).nil? then
          # when (namespaceURI matches an in scope declaration of one or more prefixes)
          # pick the most local binding available; 
          # if there is more than one pick one arbitrarily
          # ==> change attribute's prefix.
          attr.prefix = new_prefix
        else
          if not attr.prefix.nil? and self.lookup_namespace_uri( attr.prefix ).nil? then
            # when the current prefix is not null and it has no in scope declaration
            # ==> declare this prefix
            self.set_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns:#{attr.prefix}", attr.namespace_uri )
          else
            # find a prefix following the pattern "NS" +index (starting at 1)
            # make sure this prefix is not declared in the current scope.
            # create a local namespace declaration attribute
            #==> change attribute's prefix.
            i = 0
            loop do
              i += 1
              if self.lookup_namespace_uri( "NS#{i}" ).nil? then
                self.set_attribute_ns( "http://www.w3.org/2000/xmlns/", "xmlns:NS#{i}", attr.namespace_uri )
                break
              end
            end
            attr.prefix = "NS#{i}"
          end
        end
      end
    else
      # attr has no namespace URI
      if attr.local_name.nil? then
        # when attr has no localName
        #   = DOM Level 1 node
        #==> if in process of validation against a namespace aware schema 
        #     (i.e XML Schema) report a fatal error: the processor can not recover 
        #      in this situation. 
        #      Otherwise, report an error: no namespace fixup will be performed on this node.
      else
        # attr has no namespace URI and no prefix
        # no action is required, since attrs don't use default
        # ==> do nothing 
      end
    end
  end # end for-all-Attrs
  
  # do this recursively
  #for ( all child elements of Element )
  self.each_child_node do |c|
    if c.node_type == ELEMENT_NODE then
      c.normalize_namespaces()
    end
  end # end Element.normalizeNamespaces
end

#previous_element_siblingObject

The sibling node of that element which most immediately precedes that element in document order, and which is of nodeType ELEMENT_NODE, as an Element object. If the element on which this attribute is accessed does not have any preceding sibling nodes, or if none of those preceding sibling nodes are element nodes, then this attribute must return nil. (defiend at W3C Element Traversal Specification)



378
379
380
381
382
383
384
385
386
387
# File 'lib/vcdom/element.rb', line 378

def previous_element_sibling
  n = self.previous_sibling
  while n do
    if n.node_type == ELEMENT_NODE then
      break
    end
    n = n.previous_sibling
  end
  return n
end

#set_attribute(name, value) ⇒ Object



81
82
83
84
85
86
# File 'lib/vcdom/element.rb', line 81

def set_attribute( name, value )
  attr = self.owner_document.create_attribute( name )
  attr.append_child( self.owner_document.create_text_node( value ) )
  self.set_attribute_node( attr )
  nil
end

#set_attribute_node(new_attr) ⇒ Object

setAttributeNode Adds a new attribute node. If an attribute with that name (nodeName) is already present in the element, it is replaced by the new one. Replacing an attribute node by itself has no effect. To add a new attribute node with a qualified name and namespace URI, use the setAttributeNodeNS method.

Parameters:

  • new_attr

    The Attr node to add to the attribute list.

Returns:

  • If the newAttr attribute replaces an existing attribute, the replaced Attr node is returned, otherwise null is returned.



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/vcdom/element.rb', line 69

def set_attribute_node( new_attr )
  if new_attr.owner_document != self.owner_document then
    raise "WRONG_DOCUMENT_ERR"
  end
  if not new_attr.owner_element.nil? then
    raise "INUSE_ATTRIBUTE_ERR"
  end
  old_attr = nil
  @attr_nodes << new_attr
  new_attr._set_owner_element( self )
  old_attr
end

#set_attribute_node_ns(new_attr) ⇒ Object

setAttributeNodeNS introduced in DOM Level 2 Adds a new attribute. If an attribute with that local name and that namespace URI is already present in the element, it is replaced by the new one. Replacing an attribute node by itself has no effect. Per [XML Namespaces], applications must use the value null as the namespaceURI parameter for methods if they wish to have no namespace.

Parameters:

  • new_attr

    The Attr node to add to the attribute list.

Returns:

  • If the newAttr attribute replaces an existing attribute with the same local name and namespace URI, the replaced Attr node is returned, otherwise null is returned.



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/vcdom/element.rb', line 105

def set_attribute_node_ns( new_attr )
  if new_attr.owner_document != self.owner_document then
    raise "WRONG_DOCUMENT_ERR"
  end
  if not new_attr.owner_element.nil? then
    raise "INUSE_ATTRIBUTE_ERR"
  end
  old_attr = nil
  @attr_nodes << new_attr
  new_attr._set_owner_element( self )
  old_attr
end

#set_attribute_ns(namespace_uri, qualified_name, value) ⇒ Object



117
118
119
120
121
122
# File 'lib/vcdom/element.rb', line 117

def set_attribute_ns( namespace_uri, qualified_name, value )
  attr = self.owner_document.create_attribute_ns( namespace_uri, qualified_name )
  attr.append_child( self.owner_document.create_text_node( value ) )
  self.set_attribute_node_ns( attr )
  nil
end

#tag_nameObject Also known as: node_name



27
28
29
# File 'lib/vcdom/element.rb', line 27

def tag_name
  @local_name.to_s()
end