xmlcodec 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +460 -0
- data/README +81 -0
- data/Rakefile +84 -0
- data/lib/XMLElement.rb +489 -0
- data/lib/XMLStreamObjectParser.rb +136 -0
- data/lib/XMLStreamParser.rb +116 -0
- data/lib/XMLSubElements.rb +103 -0
- data/lib/XMLUtils.rb +58 -0
- data/lib/xmlcodec.rb +4 -0
- data/test/TestPartialExport.rb +145 -0
- data/test/TestXMLElement.rb +177 -0
- data/test/TestXMLStreamObjectParser.rb +160 -0
- data/test/TestXMLStreamParser.rb +47 -0
- data/test/TestXMLUtils.rb +17 -0
- data/test/simple_objects.rb +47 -0
- metadata +59 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
require "XMLUtils"
|
3
|
+
|
4
|
+
module XMLUtils
|
5
|
+
class XMLSParserContents
|
6
|
+
def initialize
|
7
|
+
@contents = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(content)
|
11
|
+
@contents << content
|
12
|
+
end
|
13
|
+
|
14
|
+
def <<(content)
|
15
|
+
add(content)
|
16
|
+
end
|
17
|
+
|
18
|
+
def array_from(start)
|
19
|
+
@contents[start..-1]
|
20
|
+
end
|
21
|
+
|
22
|
+
def text_from(start)
|
23
|
+
@contents[start..-1].join
|
24
|
+
end
|
25
|
+
|
26
|
+
def size
|
27
|
+
@contents.size
|
28
|
+
end
|
29
|
+
|
30
|
+
def erase_from(start)
|
31
|
+
@contents = @contents[0..(start-1)]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class XMLSParserElement
|
36
|
+
attr_reader :name
|
37
|
+
attr_reader :element_id
|
38
|
+
attr_reader :parent_id
|
39
|
+
attr_reader :elstart
|
40
|
+
|
41
|
+
def initialize(name, elstart, parser, parent_id)
|
42
|
+
@name = name
|
43
|
+
@parser = parser
|
44
|
+
@elstart = elstart
|
45
|
+
@element_id = parser.new_element_id
|
46
|
+
@parent_id = parent_id
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.root(parser)
|
50
|
+
self.new("__XML_ROOT__", 0, parser, nil)
|
51
|
+
end
|
52
|
+
|
53
|
+
def content
|
54
|
+
@parser.contents.text_from(@elstart)
|
55
|
+
end
|
56
|
+
|
57
|
+
def consume
|
58
|
+
@parser.consume
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class XMLStreamParser
|
63
|
+
attr_reader :contents
|
64
|
+
|
65
|
+
def initialize(listener=nil)
|
66
|
+
@listener = listener
|
67
|
+
@contents = XMLSParserContents.new
|
68
|
+
@elid = 0
|
69
|
+
@elements = [XMLSParserElement.root(self)]
|
70
|
+
end
|
71
|
+
|
72
|
+
def new_element_id
|
73
|
+
previous = @elid
|
74
|
+
@elid += 1
|
75
|
+
previous
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse(text)
|
79
|
+
REXML::Document.parse_stream(text, self)
|
80
|
+
end
|
81
|
+
|
82
|
+
def tag_start(name, attrs)
|
83
|
+
@elements << XMLSParserElement.new(name, @contents.size,
|
84
|
+
self, @elements[-1].element_id)
|
85
|
+
@contents << XMLUtils.create_open_tag(name, attrs)
|
86
|
+
end
|
87
|
+
|
88
|
+
def text(text)
|
89
|
+
@contents << text
|
90
|
+
end
|
91
|
+
|
92
|
+
def tag_end(name)
|
93
|
+
@contents << "</"+name+">"
|
94
|
+
element(name)
|
95
|
+
@elements.pop()
|
96
|
+
end
|
97
|
+
|
98
|
+
def content
|
99
|
+
@contents.text_from(@elements[-1].elstart)
|
100
|
+
end
|
101
|
+
|
102
|
+
def element(name)
|
103
|
+
if @listener
|
104
|
+
@listener.element(@elements[-1])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def consume
|
109
|
+
@contents.erase_from(@elements[-1].elstart)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Ignore everything except tags and text for now
|
113
|
+
def method_missing(methId, *args)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'XMLUtils'
|
2
|
+
|
3
|
+
module XMLCodec
|
4
|
+
# A simple element that has only text inside. This is used inside
|
5
|
+
# XMLSubElements to be able to directly add strings to it and have them be
|
6
|
+
# treated as XML text elements.
|
7
|
+
class XMLTextElement
|
8
|
+
attr_accessor :__parent
|
9
|
+
|
10
|
+
# Create a new element for the given string.
|
11
|
+
def initialize(string)
|
12
|
+
@value = XMLUtils::escape_xml(string)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Simple to_s method that just returns the included string
|
16
|
+
def to_s
|
17
|
+
@value
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates the XML for the element by using add_text on the value.
|
21
|
+
def create_xml(parent)
|
22
|
+
parent.add_text(@value)
|
23
|
+
end
|
24
|
+
|
25
|
+
# The XML text of the element is simply it's string value.
|
26
|
+
def xml_text
|
27
|
+
@value
|
28
|
+
end
|
29
|
+
|
30
|
+
def end_partial_export(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
def partial_export(file, except=nil)
|
34
|
+
file << __parent.indentation(1)+self.xml_text+"\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# This is the container class used to hold the elements for the xmlsubelements
|
39
|
+
# and xmlsubel_mult in a XMLElement.
|
40
|
+
class XMLSubElements
|
41
|
+
include Enumerable
|
42
|
+
|
43
|
+
# Create a new instance of the container
|
44
|
+
def initialize(parent)
|
45
|
+
@elements = []
|
46
|
+
@parent = parent
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
# Get the class for a given element name
|
51
|
+
def elclass(name)
|
52
|
+
XMLElement.get_element_class(name)
|
53
|
+
end
|
54
|
+
|
55
|
+
public
|
56
|
+
# Adds a value to the collection. The value may be either a String or a
|
57
|
+
# descendant of XMLElement. If it's a string it's converted into a
|
58
|
+
# XMLTextElement
|
59
|
+
def <<(value)
|
60
|
+
if value.instance_of? String
|
61
|
+
value = XMLTextElement.new(value)
|
62
|
+
end
|
63
|
+
value.__parent = @parent
|
64
|
+
@elements << value
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get the element with the given number
|
68
|
+
def [](num)
|
69
|
+
@elements[num]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get the number of elements in the container
|
73
|
+
def size
|
74
|
+
@elements.size
|
75
|
+
end
|
76
|
+
|
77
|
+
# Create the XML of all the elements by creating the XML for each of them.
|
78
|
+
def create_xml(parent)
|
79
|
+
@elements.each{|e| e.create_xml(parent)}
|
80
|
+
end
|
81
|
+
|
82
|
+
# Import the XML of all the elements
|
83
|
+
def import_xml(xmlelements)
|
84
|
+
xmlelements.each do |xmlel|
|
85
|
+
if xmlel.kind_of? REXML::Text
|
86
|
+
self << xmlel.to_s
|
87
|
+
else
|
88
|
+
self << elclass(xmlel.name.to_sym).import_xml(xmlel)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Iterate all the values in the collection
|
94
|
+
def each
|
95
|
+
@elements.each {|e| yield e}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Delete a certain element from the collection
|
99
|
+
def delete_element(element)
|
100
|
+
@elements.delete(element)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/XMLUtils.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
|
3
|
+
# This module holds generic XML utilities. The module's methods are simple
|
4
|
+
# XML utilities. The module also contains XMLStreamParser, a Generic XML Stream
|
5
|
+
# parser whose events are the text of whole elements instead of start and end
|
6
|
+
# tags.
|
7
|
+
|
8
|
+
module XMLUtils
|
9
|
+
# Gets the REXML DOM for a given filename that must be a XML file.
|
10
|
+
def self.getdoc(filename)
|
11
|
+
file = File.new(filename, 'r')
|
12
|
+
REXML::Document.new file
|
13
|
+
end
|
14
|
+
|
15
|
+
# Count the number of elements that correspond to a given xpath in a file.
|
16
|
+
def self.count_elements(path, filename)
|
17
|
+
doc = getdoc(filename)
|
18
|
+
i = 0
|
19
|
+
XPath.each(doc, path) {|element| i+=1}
|
20
|
+
return i
|
21
|
+
end
|
22
|
+
|
23
|
+
# Test if a given xpath exists in the file.
|
24
|
+
def self.element_exists(path, filename)
|
25
|
+
count_elements(path,filename)>0
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get a xpath from a REXML document.
|
29
|
+
def self.select_path_doc(path, doc)
|
30
|
+
element = REXML::XPath.first(doc, path)
|
31
|
+
return "" if not element
|
32
|
+
if element.respond_to?("value")
|
33
|
+
return element.value || ""
|
34
|
+
end
|
35
|
+
return element.text || ""
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get a xpath from a file.
|
39
|
+
def self.select_path(path, filename)
|
40
|
+
XMLUtils::select_path_doc(path, getdoc(filename))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create an open tag.
|
44
|
+
def self.create_open_tag(name, attrs)
|
45
|
+
str = "<"+name
|
46
|
+
attrs.each {|name, value| str << " #{name}='#{value}'"}
|
47
|
+
str << ">"
|
48
|
+
str
|
49
|
+
end
|
50
|
+
|
51
|
+
# Escape a string so that it can be included in a XML document
|
52
|
+
def self.escape_xml(string)
|
53
|
+
t = REXML::Text.new('')
|
54
|
+
str = ''
|
55
|
+
t.write_with_substitution(str, string)
|
56
|
+
str
|
57
|
+
end
|
58
|
+
end
|
data/lib/xmlcodec.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'XMLUtils'
|
3
|
+
require 'simple_objects'
|
4
|
+
|
5
|
+
class TestPartialExport < Test::Unit::TestCase
|
6
|
+
def validate_well_formed(filename)
|
7
|
+
assert(system("rxp", "-xs", filename))
|
8
|
+
end
|
9
|
+
|
10
|
+
def compare_xpath(value, filename, path)
|
11
|
+
assert_equal(value.strip, XMLUtils::select_path(path, filename).strip)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_simple
|
15
|
+
value = "somevalue"
|
16
|
+
filename = 'test_partial_export_simple.xml'
|
17
|
+
|
18
|
+
file = File.open(filename, "w")
|
19
|
+
sel = SimpleElement.new(value)
|
20
|
+
sel.partial_export(file)
|
21
|
+
file.close
|
22
|
+
|
23
|
+
validate_well_formed(filename)
|
24
|
+
compare_xpath(value, filename, "/abc")
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_double
|
28
|
+
value = 'somevalue'
|
29
|
+
filename = 'test_partial_export_double.xml'
|
30
|
+
|
31
|
+
file = File.open(filename, "w")
|
32
|
+
sel = SimpleElement.new(value)
|
33
|
+
el = TestElement.new
|
34
|
+
el.abc = sel
|
35
|
+
|
36
|
+
sel.partial_export(file)
|
37
|
+
el.end_partial_export(file)
|
38
|
+
file.close
|
39
|
+
|
40
|
+
validate_well_formed(filename)
|
41
|
+
compare_xpath(value, filename, "/subel/abc")
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_triple
|
45
|
+
value = 'somevalue'
|
46
|
+
filename = 'test_partial_export_double.xml'
|
47
|
+
|
48
|
+
file = File.open(filename, "w")
|
49
|
+
sel = SimpleElement.new(value)
|
50
|
+
el1 = TestElement.new
|
51
|
+
el2 = TestElement.new
|
52
|
+
el1.subel = el2
|
53
|
+
el2.abc = sel
|
54
|
+
|
55
|
+
sel.partial_export(file)
|
56
|
+
el1.end_partial_export(file)
|
57
|
+
file.close
|
58
|
+
|
59
|
+
validate_well_formed(filename)
|
60
|
+
compare_xpath(value, filename, "/subel/subel/abc")
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_attr
|
64
|
+
value = 'somevalue'
|
65
|
+
filename = 'test_partial_export_double.xml'
|
66
|
+
|
67
|
+
file = File.open(filename, "w")
|
68
|
+
el = TestElement.new
|
69
|
+
el.someattr = value
|
70
|
+
|
71
|
+
el.partial_export(file)
|
72
|
+
file.close
|
73
|
+
|
74
|
+
compare_xpath(value, filename, "/subel/@someattr")
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_mult
|
78
|
+
value1 = 'somevalue1'
|
79
|
+
value2 = 'somevalue2'
|
80
|
+
filename = 'test_partial_export_mult.xml'
|
81
|
+
|
82
|
+
file = File.open(filename, "w")
|
83
|
+
sel1 = SimpleElement.new(value1)
|
84
|
+
sel2 = SimpleElement.new(value2)
|
85
|
+
|
86
|
+
el = SubelMultElement.new
|
87
|
+
el.abc << sel1
|
88
|
+
sel1.partial_export(file)
|
89
|
+
|
90
|
+
el.abc << sel2
|
91
|
+
sel2.partial_export(file)
|
92
|
+
el.end_partial_export(file)
|
93
|
+
|
94
|
+
file.close
|
95
|
+
|
96
|
+
validate_well_formed(filename)
|
97
|
+
compare_xpath(value1, filename, "/mult/abc[1]")
|
98
|
+
compare_xpath(value2, filename, "/mult/abc[2]")
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_subelements
|
102
|
+
value1 = 'somevalue1'
|
103
|
+
value2 = 'somevalue2'
|
104
|
+
filename = 'test_partial_export_subelements.xml'
|
105
|
+
|
106
|
+
file = File.open(filename, "w")
|
107
|
+
sel1 = SimpleElement.new(value1)
|
108
|
+
sel2 = SimpleElement.new(value2)
|
109
|
+
|
110
|
+
el = SubelElement.new
|
111
|
+
el.subelements << sel1
|
112
|
+
sel1.partial_export(file)
|
113
|
+
|
114
|
+
el.subelements << sel2
|
115
|
+
sel2.partial_export(file)
|
116
|
+
el.end_partial_export(file)
|
117
|
+
|
118
|
+
file.close
|
119
|
+
|
120
|
+
validate_well_formed(filename)
|
121
|
+
compare_xpath(value1, filename, "/subels/abc[1]")
|
122
|
+
compare_xpath(value2, filename, "/subels/abc[2]")
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_subelements_multiple
|
126
|
+
value1 = 'somevalue1'
|
127
|
+
value2 = 'somevalue2'
|
128
|
+
filename = 'test_partial_export_subelements2.xml'
|
129
|
+
|
130
|
+
file = File.open(filename, "w")
|
131
|
+
sel1 = SimpleElement.new(value1)
|
132
|
+
sel2 = SimpleElement.new(value2)
|
133
|
+
|
134
|
+
el = SubelElement.new
|
135
|
+
el.subelements << sel1
|
136
|
+
el.subelements << sel2
|
137
|
+
el.partial_export(file)
|
138
|
+
|
139
|
+
file.close
|
140
|
+
|
141
|
+
validate_well_formed(filename)
|
142
|
+
compare_xpath(value1, filename, "/subels/abc[1]")
|
143
|
+
compare_xpath(value2, filename, "/subels/abc[2]")
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'xmlcodec'
|
3
|
+
require 'rexml/document'
|
4
|
+
require 'simple_objects'
|
5
|
+
|
6
|
+
class TestXMLElement < Test::Unit::TestCase
|
7
|
+
def test_xmlsubel
|
8
|
+
value = 'test'
|
9
|
+
|
10
|
+
el = TestElement.new
|
11
|
+
sel = SimpleElement.new(value)
|
12
|
+
|
13
|
+
el.abc = sel
|
14
|
+
assert_equal(sel, el.abc)
|
15
|
+
assert_equal(value, sel.value)
|
16
|
+
assert_equal(el, sel.__parent)
|
17
|
+
|
18
|
+
assert_equal('<abc>'+value+'</abc>', sel.xml_text)
|
19
|
+
assert_equal('<subel><abc>'+value+'</abc></subel>', el.xml_text)
|
20
|
+
|
21
|
+
dom = REXML::Document.new
|
22
|
+
el.create_xml(dom)
|
23
|
+
|
24
|
+
assert_equal 1, dom.elements.size
|
25
|
+
eldom = dom.elements['subel']
|
26
|
+
assert_not_nil eldom
|
27
|
+
assert_equal 1, eldom.elements.size
|
28
|
+
|
29
|
+
seldom = eldom.elements['abc']
|
30
|
+
assert_not_nil seldom
|
31
|
+
assert_equal value, seldom.text
|
32
|
+
|
33
|
+
el = TestElement.import_xml(dom)
|
34
|
+
assert_equal value, el.abc.value
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_xmlattr
|
38
|
+
value = 'test'
|
39
|
+
el = TestElement.new
|
40
|
+
|
41
|
+
el.someattr = value
|
42
|
+
assert_equal(value, el.someattr)
|
43
|
+
|
44
|
+
assert_equal("<subel someattr='"+value+"'></subel>", el.xml_text)
|
45
|
+
|
46
|
+
dom = REXML::Document.new
|
47
|
+
el.create_xml(dom)
|
48
|
+
|
49
|
+
assert_equal 1, dom.elements.size
|
50
|
+
eldom = dom.elements['subel']
|
51
|
+
assert_not_nil eldom
|
52
|
+
assert_equal value, eldom.attributes['someattr']
|
53
|
+
|
54
|
+
el = TestElement.import_xml(dom)
|
55
|
+
assert_equal value, el.someattr
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_xmlsubelements
|
59
|
+
value = 'test'
|
60
|
+
el = SubelElement.new
|
61
|
+
sel = SimpleElement.new(value)
|
62
|
+
|
63
|
+
el.subelements << sel
|
64
|
+
assert_equal(sel, el.subelements[0])
|
65
|
+
assert_equal(el, sel.__parent)
|
66
|
+
|
67
|
+
assert_equal('<subels><abc>'+value+'</abc></subels>', el.xml_text)
|
68
|
+
|
69
|
+
dom = REXML::Document.new
|
70
|
+
el.create_xml(dom)
|
71
|
+
|
72
|
+
assert_equal 1, dom.elements.size
|
73
|
+
eldom = dom.elements['subels']
|
74
|
+
assert_not_nil eldom
|
75
|
+
assert_equal 1, eldom.elements.size
|
76
|
+
|
77
|
+
seldom = eldom.elements['abc']
|
78
|
+
assert_not_nil seldom
|
79
|
+
assert_equal value, seldom.text
|
80
|
+
|
81
|
+
el = SubelElement.import_xml(dom)
|
82
|
+
assert_equal 1, el.subelements.size
|
83
|
+
assert_equal value, el.subelements[0].value
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_xmlsubel_mult
|
87
|
+
value1 = 'test'
|
88
|
+
value2 = 'test2'
|
89
|
+
el = SubelMultElement.new
|
90
|
+
sel1 = SimpleElement.new(value1)
|
91
|
+
sel2 = SimpleElement.new(value2)
|
92
|
+
|
93
|
+
el.abc << sel1
|
94
|
+
el.abc << sel2
|
95
|
+
|
96
|
+
assert_equal(sel1, el.abc[0])
|
97
|
+
assert_equal(el, sel1.__parent)
|
98
|
+
assert_equal(el, sel2.__parent)
|
99
|
+
|
100
|
+
assert_equal('<mult><abc>'+value1+'</abc><abc>'+value2+'</abc></mult>', el.xml_text)
|
101
|
+
|
102
|
+
dom = REXML::Document.new
|
103
|
+
el.create_xml(dom)
|
104
|
+
|
105
|
+
assert_equal 1, dom.elements.size
|
106
|
+
eldom = dom.elements['mult']
|
107
|
+
assert_not_nil eldom
|
108
|
+
assert_equal 2, eldom.elements.size
|
109
|
+
|
110
|
+
[value1, value2].each_with_index do |value, index|
|
111
|
+
seldom = eldom.elements[index+1]
|
112
|
+
assert_not_nil seldom
|
113
|
+
assert_equal value, seldom.text
|
114
|
+
assert_equal 'abc', seldom.name
|
115
|
+
end
|
116
|
+
|
117
|
+
el = SubelMultElement.import_xml(dom)
|
118
|
+
assert_equal 2, el.abc.size
|
119
|
+
assert_equal value1, el.abc[0].value
|
120
|
+
assert_equal value2, el.abc[1].value
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_delete_element_simple
|
124
|
+
el = TestElement.new
|
125
|
+
sel = SimpleElement.new('')
|
126
|
+
el.abc = sel
|
127
|
+
assert_equal sel, el.abc
|
128
|
+
|
129
|
+
el.delete_element(sel)
|
130
|
+
assert_nil el.abc
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_delete_element_double
|
134
|
+
el = TestElement.new
|
135
|
+
sel1 = SimpleElement.new('')
|
136
|
+
sel2 = SimpleElement2.new('')
|
137
|
+
el.abc = sel1
|
138
|
+
el.abc2 = sel2
|
139
|
+
|
140
|
+
assert_equal sel1, el.abc
|
141
|
+
assert_equal sel2, el.abc2
|
142
|
+
|
143
|
+
el.delete_element(sel1)
|
144
|
+
assert_nil el.abc
|
145
|
+
assert_equal sel2, el.abc2
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_delete_element_multiple
|
149
|
+
el = SubelMultElement.new
|
150
|
+
sel = SimpleElement.new('')
|
151
|
+
el.abc << sel
|
152
|
+
assert_equal sel, el.abc[0]
|
153
|
+
|
154
|
+
el.delete_element(sel)
|
155
|
+
assert_nil el.abc[0]
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_delete_element_subelements
|
159
|
+
el = SubelElement.new
|
160
|
+
sel1 = SimpleElement.new('')
|
161
|
+
sel2 = SimpleElement.new('')
|
162
|
+
el.subelements << sel1
|
163
|
+
el.subelements << sel2
|
164
|
+
|
165
|
+
assert_equal 2, el.subelements.size
|
166
|
+
assert_equal sel1, el.subelements[0]
|
167
|
+
assert_equal sel2, el.subelements[1]
|
168
|
+
|
169
|
+
el.delete_element(sel1)
|
170
|
+
assert_equal 1, el.subelements.size
|
171
|
+
assert_equal sel2, el.subelements[0]
|
172
|
+
|
173
|
+
el.delete_element(sel2)
|
174
|
+
assert_equal 0, el.subelements.size
|
175
|
+
assert_nil el.subelements[0]
|
176
|
+
end
|
177
|
+
end
|