Class: XMLCodec::XMLElement

Inherits:
Object
  • Object
show all
Defined in:
lib/element.rb,
lib/element_attrs.rb,
lib/element_subel.rb,
lib/element_value.rb,
lib/element_export.rb,
lib/element_import.rb,
lib/element_creation.rb,
lib/element_subelements.rb,
lib/element_partial_export.rb

Overview

This class should be inherited from to create classes that are able to import and export XML elements and their children. It provides three main functions: xmlattr, xmlsubel and xmlsubel_mult.

To create an importer/exporter for a XML format all that’s needed is to create a class for each of the elements and then declare their atributes and subelements.

Two other functions have an important role. elname declares the name of the XML element the class represents. elwithvalue declares that the element has no subelements and includes only text content.

After the class is defined import_xml can be used to import the content from a Nokogiri Element or Document and create_xml can be used to create the XML DOM of the element as a child to a Nokogiri Element or Document. For big documents these are usually too slow and memory hungry, using xml_text to export to XML and import_xml_text to import XML are probably better ideas. import_xml_text is just a utility function around XMLStreamObjectParser, that allow more flexible stream parsing of XML files while still using the same XMLElement objects.

Constant Summary collapse

INDENT_STR =
'  '
CACHE =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#__parentObject

Returns the value of attribute __parent.



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

def __parent
  @__parent
end

#__xml_textObject

Returns the value of attribute __xml_text.



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

def __xml_text
  @__xml_text
end

#element_idObject

Returns the value of attribute element_id.



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

def element_id
  @element_id
end

#parent_idObject

Returns the value of attribute parent_id.



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

def parent_id
  @parent_id
end

Class Method Details

.allvalue?Boolean

tests if the element is a value element as defined by ‘elallvalue’

Returns:

  • (Boolean)


9
# File 'lib/element_value.rb', line 9

def self.allvalue?; false end

.get_element_class(name) ⇒ Object

Gets the class for a certain element name.



139
140
141
142
143
144
145
# File 'lib/element.rb', line 139

def self.get_element_class(name)
  cl = elclasses[name.to_sym]
 if not cl and class_variable_get(:@@strict_parsing)
  raise ElementClassNotFound, "No class defined for element type: '" + name.to_s + "'"
end
cl
end

.get_element_names(name) ⇒ Object

Gets the possible element names for a certain element.



148
149
150
# File 'lib/element.rb', line 148

def self.get_element_names(name)
  get_element_class(name).get_elnames
end

.has_subelements?Boolean

Method that checks if a given class has subelements. This is usually only used when exporting stuff.

Returns:

  • (Boolean)


6
# File 'lib/element_subelements.rb', line 6

def self.has_subelements?; false end

.hasvalue?Boolean

tests if the element is a value element as defined by ‘elwithvalue’

Returns:

  • (Boolean)


5
# File 'lib/element_value.rb', line 5

def self.hasvalue?; false end

.import_xml(obj) ⇒ Object

Import the XML into an object from a Nokogiri XML Node or Document or from a string.



6
7
8
9
10
11
12
13
14
15
# File 'lib/element_import.rb', line 6

def self.import_xml(obj)
  if obj.instance_of? String
    _import_xml_text(obj)
  elsif obj.instance_of? Nokogiri::XML::Node or 
        obj.instance_of? Nokogiri::XML::Document
    _import_xml_dom(obj)
  else
    nil
  end
end

.new_with_content(attrs, children) ⇒ Object

Create a new element passing it all the atributes, children and texts



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/element_creation.rb', line 5

def self.new_with_content(attrs, children)
  text_children = []
  element_children = []
  
  children.each do |c|
    if c.is_a? String
      text_children << c
    else
      element_children << c
    end
  end

  obj = self.allocate
  obj.add_attr(attrs)
  obj.add_subel(element_children)
  obj.add_texts(text_children)
  if obj.has_subelements?
    obj.add_subelements(children)
  end
  obj
end

Instance Method Details

#add_attr(attrs) ⇒ Object

add the attributes passed as a hash to the element



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/element_creation.rb', line 28

def add_attr(attrs)
  attrs.each do |name, value|
    if not self.class.attr_names.include?(name.to_sym)
      if self.class.class_variable_get(:@@strict_parsing)
        raise ElementAttributeNotFound, "No attribute '#{name}' defined for class '#{self.class}'" 
      end
    else
      self.send("#{name}=", value)
    end
  end
end

#add_subel(children) ⇒ Object

add the subelements into the element



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/element_creation.rb', line 48

def add_subel(children)
  children.each do |c|
    if subel_name = get_subel(c.class)
      if self.class.subel_mult? subel_name
        self.send(subel_name) <<  c
      else
        self.send(subel_name.to_s+'=', c)
      end 
    end
  end
end

#add_subelements(all_children) ⇒ Object

If the class is one with many subelements import all of them into the object.



62
63
64
# File 'lib/element_creation.rb', line 62

def add_subelements(all_children)
  all_children.each {|c| self.subelements << c}
end

#add_texts(texts) ⇒ Object

add the text elements into the element



41
42
43
44
45
# File 'lib/element_creation.rb', line 41

def add_texts(texts)
  if self.hasvalue?
    @value = texts.join
  end
end

#allvalue?Boolean

Returns:

  • (Boolean)


10
# File 'lib/element_value.rb', line 10

def allvalue?; self.class.allvalue?; end

#create_close_tagObject

returns a string with the closing tag for the element



74
75
76
# File 'lib/element_export.rb', line 74

def create_close_tag
  XMLCodec::XMLUtils::create_close_tag(elname.to_s)
end

#create_open_tagObject

returns a string with the opening tag for the element



62
63
64
65
66
67
68
69
70
71
# File 'lib/element_export.rb', line 62

def create_open_tag
  attrs = {}
  self.class.each_attr do |a|
    value = self.send(a)
    if value
      attrs[a.to_s] = value
    end
  end
  XMLCodec::XMLUtils::create_open_tag(elname.to_s, attrs)
end

#create_xml(parent) ⇒ Object

Creates the xml for the element inside the parent element. The parent passed should be a Nokogiri XML Node or Document. This call is recursive creating the XML for any subelements.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/element_export.rb', line 7

def create_xml(parent)
  xmlel = parent.add_child Nokogiri::XML::Element.new(self.elname.to_s, parent)
  if self.hasvalue?
    xmlel.add_child self.value
  end
  create_xml_attr(xmlel)
  create_xml_subel(xmlel)
  
  if self.has_subelements?
    create_xml_subelements(xmlel)
  end
  
  xmlel
end

#create_xml_attr(parent) ⇒ Object

Creates the XML for the atributes



37
38
39
40
41
42
43
44
# File 'lib/element_export.rb', line 37

def create_xml_attr(parent)
  self.class.each_attr do |a|
    value = self.send(a)
    if value
      parent.set_attribute(a.to_s, value)
    end
  end
end

#create_xml_subel(parent) ⇒ Object

Creates the XML subelements



23
24
25
26
27
28
29
# File 'lib/element_export.rb', line 23

def create_xml_subel(parent)
  self.class.each_subel do |a|
    if value = self.send(a)
      value.create_xml(parent)
    end
  end
end

#create_xml_subelements(parent) ⇒ Object

Create the XML of the SubElements



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

def create_xml_subelements(parent)
  self.subelements.create_xml(parent)
end

#delete_element(element) ⇒ Object

Remove the given subelement from the element



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/element.rb', line 112

def delete_element(element)
  self.class.each_subel do |a|  
    value = self.send(a)
    if self.class.subel_mult? a
      value.delete_element(element)
    else
      self.send(a.to_s+'=', nil) if value == element
    end
  end
  
  if has_subelements?
    @subelements.delete_element(element)
  end 
end

#end_partial_export(file) ⇒ Object

Ends the partial exporting of the element.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/element_partial_export.rb', line 47

def end_partial_export(file)
  if not already_partial_export_ended?
    @already_partial_export_ended = true
    
    if not already_partial_exported?
      raise "<#{self} Trying to end the export of an element that hasn't"+
            " been started yet"
    end
    
    each_subelement do |e|
      e.end_partial_export(file)
    end
    
    file << create_close_tag

    if self.__parent
      self.__parent.delete_element(self)
    end
  end
end

#has_subelements?Boolean

Returns:

  • (Boolean)


7
# File 'lib/element_subelements.rb', line 7

def has_subelements?; self.class.has_subelements? end

#hasvalue?Boolean

Returns:

  • (Boolean)


6
# File 'lib/element_value.rb', line 6

def hasvalue?; self.class.hasvalue? end

#partial_export(file) ⇒ Object

Export this element into a file. Will also start to export the parents of the element. It’s equivalent to calling start_partial_export followed by end_partial_export.



18
19
20
21
22
23
# File 'lib/element_partial_export.rb', line 18

def partial_export(file)
  if not already_partial_exported?
    start_partial_export(file)
    end_partial_export(file)
  end
end

#start_partial_export(file) ⇒ Object

Starts to export the element to a file. all the existing elements will be exported. After calling this you should only add stuff that you will export explicitly by calling partial_export or start_partial_export.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/element_partial_export.rb', line 28

def start_partial_export(file)
  if not already_partial_exported?
    @already_partial_exported = true
    if self.__parent
      self.__parent.start_partial_export(file)
    end
    
    file << create_open_tag
    if self.hasvalue?
      file << XMLCodec::XMLUtils::escape_xml(self.value)
    end
    
    each_subelement do |e|
      e.partial_export(file)
    end
  end
end

#xml_textObject

create the XML text of the element



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/element_export.rb', line 47

def xml_text
  str = create_open_tag
  if self.hasvalue?
    str << XMLCodec::XMLUtils::escape_xml(self.value)
  end
  
  each_subelement do |e|
    str << e.xml_text
  end
  
  str << create_close_tag
  str
end