axml 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +13 -0
- data/README +79 -0
- data/Rakefile +203 -0
- data/lib/axml.rb +227 -0
- data/specs/axml_spec.rb +222 -0
- data/specs/spec_helper.rb +57 -0
- metadata +55 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2006, The University of Texas at Austin("U.T. Austin"). All rights reserved.
|
2
|
+
|
3
|
+
Software by John T. Prince under the direction of Edward M. Marcotte.
|
4
|
+
|
5
|
+
By using this software the USER indicates that he or she has read, understood and will comply with the following:
|
6
|
+
|
7
|
+
U. T. Austin hereby grants USER permission to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this software and its documentation for any purpose and without fee, provided that a full copy of this notice is included with the software and its documentation.
|
8
|
+
|
9
|
+
Title to copyright this software and its associated documentation shall at all times remain with U. T. Austin. No right is granted to use in advertising, publicity or otherwise any trademark, service mark, or the name of U. T. Austin.
|
10
|
+
|
11
|
+
This software and any associated documentation are provided "as is," and U. T. AUSTIN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT USE OF THE SOFTWARE, MODIFICATIONS, OR ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY. U. T. Austin, The University of Texas System, its Regents, officers, and employees shall not be liable under any circumstances for any direct, indirect, special, incidental, or consequential damages with respect to any claim by USER or any third party on account of or arising from the use, or inability to use, this software or its associated documentation, even if U. T. Austin has been advised of the possibility of those damages.
|
12
|
+
|
13
|
+
Submit software operation questions to: John T. Prince, Institute for Cellular and Molecular Biology, U. T. Austin, Austin, Texas 78712.
|
data/README
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
AXML
|
2
|
+
====
|
3
|
+
|
4
|
+
AXML - Provides a simple DOM for working with XML (using XMLParser under the
|
5
|
+
hood) that can serve as a drop in replacement for much of the basic libxml
|
6
|
+
functionality (e.g., each, children, child, find_first, find, next). AXML
|
7
|
+
comes from the idea that XML should be AXED (or at least simple to use!)
|
8
|
+
to use).
|
9
|
+
|
10
|
+
Description
|
11
|
+
-----------
|
12
|
+
|
13
|
+
Parses elements, attributes, and text(content), and nothing more. Should be
|
14
|
+
very easy to extend and modify for special cases. It is roughly as fast as
|
15
|
+
libxml, although it currently reads in the entire document first (however,
|
16
|
+
this is memory efficient - nodes are implemented using Struct).
|
17
|
+
|
18
|
+
Examples
|
19
|
+
--------
|
20
|
+
string_or_io = "
|
21
|
+
<n1>
|
22
|
+
<n2 size='big'>
|
23
|
+
<n3>words here</n3>
|
24
|
+
<n3></n3>
|
25
|
+
</n2>
|
26
|
+
<n2 size='small'>
|
27
|
+
<n3 id='3'></n3)
|
28
|
+
</n2>
|
29
|
+
</n1>
|
30
|
+
"
|
31
|
+
|
32
|
+
## Read a string or io
|
33
|
+
n1_node = AXML.parse(string_or_io)
|
34
|
+
|
35
|
+
## Read a file
|
36
|
+
n1_node = AXML.parse_file(filename)
|
37
|
+
|
38
|
+
## Access children
|
39
|
+
n1_node.children # -> [array]
|
40
|
+
n1_node.each {|child| # do something with child }
|
41
|
+
|
42
|
+
## Get attributes and text
|
43
|
+
n2_node['size'] == 'big'
|
44
|
+
n3_node = n2_node.child
|
45
|
+
n3_node.text # -> 'words here'
|
46
|
+
n3_node.content # -> [same]
|
47
|
+
|
48
|
+
## Traverse nodes with next and child
|
49
|
+
n2_node = n1_node.child
|
50
|
+
the_other_n2_node = n2_node.next
|
51
|
+
the_other_n2_node.next = nil
|
52
|
+
|
53
|
+
## Does a little xpath
|
54
|
+
n3_node = n1_node.find_first('descendant::n3')
|
55
|
+
n1_node.find_first('child::n3') # -> nil
|
56
|
+
n1_node.find('descendant::n3') # -> [array of all 3 <n3> nodes]
|
57
|
+
n1_node.find('child::n2') # -> [array of 2 <n2> nodes]
|
58
|
+
|
59
|
+
All Examples (see specs/axml_spec.rb)
|
60
|
+
|
61
|
+
- reads xml strings with "AXML.parse"
|
62
|
+
- reads file handles with "AXML.parse"
|
63
|
+
- reads files with "AXML.parse_file"
|
64
|
+
- can access subnodes with "children" or "kids"
|
65
|
+
- accesses attributes with "[]"
|
66
|
+
- can "find_first_descendant"
|
67
|
+
- can "find_first_child"
|
68
|
+
- can "find" with a little xpath
|
69
|
+
- can do some find_first xpath
|
70
|
+
- can drop nodes with "drop"
|
71
|
+
- can return "child" node
|
72
|
+
- can return "next" node
|
73
|
+
- "to_s" gives xml
|
74
|
+
|
75
|
+
Installation
|
76
|
+
------------
|
77
|
+
|
78
|
+
gem install axml
|
79
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
|
9
|
+
###############################################
|
10
|
+
# GLOBAL
|
11
|
+
###############################################
|
12
|
+
|
13
|
+
FL = FileList
|
14
|
+
NAME = "axml"
|
15
|
+
|
16
|
+
readme = "README"
|
17
|
+
|
18
|
+
rdoc_extra_includes = [readme, "LICENSE"]
|
19
|
+
rdoc_options = ['--main', readme, '--title', NAME]
|
20
|
+
|
21
|
+
lib_files = FL["lib/**/*"]
|
22
|
+
dist_files = lib_files + FL[readme, "LICENSE", "Rakefile", "{specs}/**/*"]
|
23
|
+
changelog = 'CHANGELOG'
|
24
|
+
|
25
|
+
###############################################
|
26
|
+
# ENVIRONMENT
|
27
|
+
###############################################
|
28
|
+
ENV["OS"] == "Windows_NT" ? WIN32 = true : WIN32 = false
|
29
|
+
$gemcmd = "gem"
|
30
|
+
if WIN32
|
31
|
+
unless ENV["TERM"] == "cygwin"
|
32
|
+
$gemcmd << ".cmd"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
###############################################
|
37
|
+
# DOC
|
38
|
+
###############################################
|
39
|
+
Rake::RDocTask.new do |rd|
|
40
|
+
rd.main = readme
|
41
|
+
rd.rdoc_files.include rdoc_extra_includes
|
42
|
+
rd.options.push( *rdoc_options )
|
43
|
+
end
|
44
|
+
|
45
|
+
###############################################
|
46
|
+
# TESTS
|
47
|
+
###############################################
|
48
|
+
|
49
|
+
|
50
|
+
task :ensure_gem_is_uninstalled do
|
51
|
+
reply = `#{$gemcmd} list -l #{NAME}`
|
52
|
+
if reply.include? NAME + " ("
|
53
|
+
puts "GOING to uninstall gem '#{NAME}' for testing"
|
54
|
+
if WIN32
|
55
|
+
%x( #{$gemcmd} uninstall -x #{NAME} )
|
56
|
+
else
|
57
|
+
%x( sudo #{$gemcmd} uninstall -x #{NAME} )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
namespace :spec do
|
63
|
+
task :autotest do
|
64
|
+
require './specs/rspec_autotest'
|
65
|
+
RspecAutotest.run
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "Run specs"
|
70
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
71
|
+
Rake::Task[:ensure_gem_is_uninstalled].invoke
|
72
|
+
t.libs = ['lib']
|
73
|
+
t.spec_files = FileList['specs/**/*_spec.rb']
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "Run specs and output specdoc"
|
77
|
+
Spec::Rake::SpecTask.new('specl') do |t|
|
78
|
+
Rake::Task[:ensure_gem_is_uninstalled].invoke
|
79
|
+
t.spec_files = FileList['specs/**/*_spec.rb']
|
80
|
+
t.libs = ['lib']
|
81
|
+
t.spec_opts = ['--format', 'specdoc' ]
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "Run all specs with RCov"
|
85
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
86
|
+
Rake::Task[:ensure_gem_is_uninstalled].invoke
|
87
|
+
t.spec_files = FileList['specs/**/*_spec.rb']
|
88
|
+
t.rcov = true
|
89
|
+
t.libs = ['lib']
|
90
|
+
t.rcov_opts = ['--exclude', 'specs']
|
91
|
+
end
|
92
|
+
|
93
|
+
#task :spec do
|
94
|
+
# uninstall_gem
|
95
|
+
# # files that match a key word
|
96
|
+
# files_to_run = ENV['SPEC'] || FileList['specs/**/*_spec.rb']
|
97
|
+
# if ENV['SPECM']
|
98
|
+
# files_to_run = files_to_run.select do |file|
|
99
|
+
# file.include?(ENV['SPECM'])
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
# files_to_run.each do |spc|
|
103
|
+
# system "ruby -I lib -S spec #{spc} --format specdoc"
|
104
|
+
# end
|
105
|
+
#end
|
106
|
+
|
107
|
+
###############################################
|
108
|
+
# PACKAGE / INSTALL / UNINSTALL
|
109
|
+
###############################################
|
110
|
+
|
111
|
+
def get_summary(readme)
|
112
|
+
string = ''
|
113
|
+
collect = false
|
114
|
+
IO.foreach(readme) do |line|
|
115
|
+
if collect
|
116
|
+
if line =~ /[^\s]/
|
117
|
+
string << line
|
118
|
+
else
|
119
|
+
break
|
120
|
+
end
|
121
|
+
elsif line =~ /^AXML - .*/
|
122
|
+
string << line
|
123
|
+
collect = true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
string.gsub!("\n", " ")
|
127
|
+
end
|
128
|
+
|
129
|
+
# looks for a header, collects the paragraph after the space
|
130
|
+
def get_section(header, file)
|
131
|
+
get_space = false
|
132
|
+
found_space = false
|
133
|
+
string = ''
|
134
|
+
IO.foreach(file) do |line|
|
135
|
+
if found_space
|
136
|
+
if line =~ /[^\s]/
|
137
|
+
string << line
|
138
|
+
else
|
139
|
+
break
|
140
|
+
end
|
141
|
+
elsif get_space
|
142
|
+
if line !~ /[^\s]/
|
143
|
+
found_space = true
|
144
|
+
get_space = false
|
145
|
+
end
|
146
|
+
elsif line =~ /^#{header}/
|
147
|
+
get_space = true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
string.gsub!("\n", ' ')
|
151
|
+
end
|
152
|
+
|
153
|
+
def get_description(readme)
|
154
|
+
get_section('Description', readme)
|
155
|
+
end
|
156
|
+
|
157
|
+
tm = Time.now
|
158
|
+
gemspec = Gem::Specification.new do |t|
|
159
|
+
description = get_description(readme)
|
160
|
+
summary = get_summary(readme)
|
161
|
+
t.platform = Gem::Platform::RUBY
|
162
|
+
t.name = NAME
|
163
|
+
t.version = IO.readlines(changelog).grep(/##.*version/).pop.split(/\s+/).last.chomp
|
164
|
+
t.summary = summary
|
165
|
+
t.date = "#{tm.year}-#{tm.month}-#{tm.day}"
|
166
|
+
t.email = "jprince@icmb.utexas.edu"
|
167
|
+
t.description = description
|
168
|
+
t.has_rdoc = true
|
169
|
+
t.authors = ["John Prince"]
|
170
|
+
t.files = dist_files
|
171
|
+
t.rdoc_options = rdoc_options
|
172
|
+
t.extra_rdoc_files = rdoc_extra_includes
|
173
|
+
t.executables = FL["bin/*"].map {|file| File.basename(file) }
|
174
|
+
t.requirements << 'xmlparser is needed right now'
|
175
|
+
t.test_files = FL["specs/*_spec.rb"]
|
176
|
+
end
|
177
|
+
|
178
|
+
desc "Create packages."
|
179
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
180
|
+
#pkg.need_zip = true
|
181
|
+
pkg.need_tar = true
|
182
|
+
end
|
183
|
+
|
184
|
+
task :remove_pkg do
|
185
|
+
FileUtils.rm_rf "pkg"
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
task :install => [:reinstall]
|
190
|
+
|
191
|
+
desc "uninstalls the package, packages a fresh one, and installs"
|
192
|
+
task :reinstall => [:remove_pkg, :clean, :package] do
|
193
|
+
reply = `#{$gemcmd} list -l #{NAME}`
|
194
|
+
if reply.include?(NAME + " (")
|
195
|
+
%x( #{$gemcmd} uninstall -a -x #{NAME} )
|
196
|
+
end
|
197
|
+
FileUtils.cd("pkg") do
|
198
|
+
cmd = "#{$gemcmd} install #{NAME}*.gem"
|
199
|
+
puts "EXECUTING: #{cmd}"
|
200
|
+
system cmd
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
data/lib/axml.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'xmlparser'
|
2
|
+
|
3
|
+
class AXML
|
4
|
+
|
5
|
+
def self.parse_file(file)
|
6
|
+
root = nil
|
7
|
+
File.open(file) do |fh|
|
8
|
+
root = parse(fh)
|
9
|
+
end
|
10
|
+
root
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the root node (as Element) or nodes (as Array)
|
14
|
+
def self.parse(stream)
|
15
|
+
parser = AXML::XMLParser.new
|
16
|
+
parser.parse(stream)
|
17
|
+
parser.root
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
AXML::El = Struct.new(:parent, :name, :attrs, :text, :children, :array_index)
|
23
|
+
|
24
|
+
class AXML::El
|
25
|
+
@@tabs = ["", " ", " ", " ", " ", " ", " "]
|
26
|
+
include Enumerable
|
27
|
+
|
28
|
+
@@depth = 0
|
29
|
+
#attr_accessor :name, :attrs, :text, :children, :parent
|
30
|
+
# keeps track of location in array
|
31
|
+
#attr_accessor :array_index
|
32
|
+
|
33
|
+
alias_method :content, :text
|
34
|
+
alias_method :content=, :text=
|
35
|
+
alias_method :kids, :children
|
36
|
+
alias_method :kids=, :children=
|
37
|
+
|
38
|
+
def [](attribute_string)
|
39
|
+
attrs[attribute_string]
|
40
|
+
end
|
41
|
+
|
42
|
+
# accepts same xpath strings as find_first
|
43
|
+
# returns an array of nodes
|
44
|
+
def find(string)
|
45
|
+
(tp, name) = string.split('::')
|
46
|
+
case tp
|
47
|
+
when 'child'
|
48
|
+
find_children(name)
|
49
|
+
when 'descendant'
|
50
|
+
find_descendants(name)
|
51
|
+
when 'following-sibling'
|
52
|
+
find_following_siblings(name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_descendants(name, collect_descendants=[])
|
57
|
+
children.each do |child|
|
58
|
+
collect_descendants.push(child) if child.name == name
|
59
|
+
child.find_descendants(name, collect_descendants)
|
60
|
+
end
|
61
|
+
collect_descendants
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_children(name)
|
65
|
+
children.select {|v| v.name == name }
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# currently must be called with descendent:: or child:: string prefix! e.g.
|
70
|
+
# "descendant::<name>" and "child::<name>" where <name> is the name of the
|
71
|
+
# node you seek)
|
72
|
+
def find_first(string)
|
73
|
+
(tp, name) = string.split('::')
|
74
|
+
case tp
|
75
|
+
when 'child'
|
76
|
+
find_first_child(name)
|
77
|
+
when 'descendant'
|
78
|
+
find_first_descendant(name)
|
79
|
+
when 'following-sibling'
|
80
|
+
find_first_following_sibling(name)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def find_first_descendant(name)
|
85
|
+
self.each do |child_node|
|
86
|
+
if child_node.name == name
|
87
|
+
return child_node
|
88
|
+
else
|
89
|
+
return child_node.find_first_descendant(name)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def find_first_child(name)
|
96
|
+
self.each do |child_node|
|
97
|
+
if child_node.name == name
|
98
|
+
return child_node
|
99
|
+
end
|
100
|
+
end
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def find_following_siblings(name)
|
105
|
+
parent.children[(array_index+1)..-1].select {|v| v.name == name }
|
106
|
+
end
|
107
|
+
|
108
|
+
def find_first_following_sibling(name)
|
109
|
+
node = nil
|
110
|
+
parent.children[(array_index+1)..-1].each do |sibling|
|
111
|
+
if sibling.name == name
|
112
|
+
node = sibling
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
node
|
117
|
+
end
|
118
|
+
|
119
|
+
def children?
|
120
|
+
children.size > 0
|
121
|
+
end
|
122
|
+
alias_method :child?, :children?
|
123
|
+
|
124
|
+
|
125
|
+
def each(&block)
|
126
|
+
children.each do |child|
|
127
|
+
block.call(child)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# drops the current element from the list of its parents children
|
132
|
+
def drop
|
133
|
+
parent.children.delete(self)
|
134
|
+
end
|
135
|
+
|
136
|
+
def drop_child(node)
|
137
|
+
found_it = false
|
138
|
+
found_index = nil
|
139
|
+
children.each_with_index do |v,i|
|
140
|
+
if found_it
|
141
|
+
v.array_index = i - 1
|
142
|
+
end
|
143
|
+
if v.object_id == node.object_id
|
144
|
+
found_index = i
|
145
|
+
found_it = true
|
146
|
+
end
|
147
|
+
end
|
148
|
+
children.delete_at(found_index) if found_index
|
149
|
+
end
|
150
|
+
|
151
|
+
def tabs
|
152
|
+
@@tabs[@@depth]
|
153
|
+
end
|
154
|
+
|
155
|
+
def to_s
|
156
|
+
attstring = ""
|
157
|
+
if attrs.size > 0
|
158
|
+
attstring = " " + attrs.collect { |k,v| "#{k}=\"#{v}\"" }.join(" ")
|
159
|
+
end
|
160
|
+
string = "#{tabs}<#{name}#{attstring}"
|
161
|
+
if children.size > 0
|
162
|
+
string << ">\n"
|
163
|
+
@@depth += 1
|
164
|
+
string << children.collect {|child| child.to_s }.join("")
|
165
|
+
@@depth -= 1
|
166
|
+
string << "#{tabs}</#{name}>\n"
|
167
|
+
else
|
168
|
+
string << "/>\n"
|
169
|
+
end
|
170
|
+
string
|
171
|
+
end
|
172
|
+
|
173
|
+
def inspect
|
174
|
+
"<name='#{name}' attrs='#{attrs.inspect}' children.size=#{children.size}>"
|
175
|
+
end
|
176
|
+
|
177
|
+
# the next node
|
178
|
+
def next
|
179
|
+
parent.children[array_index+1]
|
180
|
+
end
|
181
|
+
|
182
|
+
# the first child (equivalent to children.first)
|
183
|
+
def child
|
184
|
+
children.first
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_node(node)
|
188
|
+
node.array_index = children.size
|
189
|
+
children.push( node )
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
class AXML::XMLParser < XMLParser
|
195
|
+
|
196
|
+
attr_writer :root
|
197
|
+
|
198
|
+
# returns the first node found in the document
|
199
|
+
def root
|
200
|
+
@root.child
|
201
|
+
end
|
202
|
+
|
203
|
+
def initialize
|
204
|
+
@root = AXML::El.new(nil, "root", {}, '', [])
|
205
|
+
@cur = @root
|
206
|
+
end
|
207
|
+
|
208
|
+
def startElement(name, attributes)
|
209
|
+
new_el = AXML::El.new(@cur, name, attributes, '', [])
|
210
|
+
# add the new node to the previous parent node
|
211
|
+
@cur.add_node(new_el)
|
212
|
+
# notice the change in @cur node
|
213
|
+
@cur = new_el
|
214
|
+
#@cur.text = "" ## in initialization now..
|
215
|
+
end
|
216
|
+
|
217
|
+
def endElement(name)
|
218
|
+
@cur = @cur.parent
|
219
|
+
end
|
220
|
+
|
221
|
+
def character(data)
|
222
|
+
@cur.text << data
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
|
data/specs/axml_spec.rb
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
require File.expand_path( File.dirname(__FILE__) + '/spec_helper' )
|
2
|
+
|
3
|
+
require 'axml'
|
4
|
+
|
5
|
+
describe AXML do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@xml_string = <<END
|
9
|
+
<xml>
|
10
|
+
<doc1>
|
11
|
+
<dog name="spot" height="23" weight="13">
|
12
|
+
<flea name="ouchy" height="20" weight="10"/>
|
13
|
+
<flea name="crawly" height="22" weight="9"/>
|
14
|
+
</dog>
|
15
|
+
</doc1>
|
16
|
+
<doc2>
|
17
|
+
<dog name="billy" height="5" weight="3">
|
18
|
+
</dog>
|
19
|
+
</doc2>
|
20
|
+
</xml>
|
21
|
+
END
|
22
|
+
@small_xml_string = <<END
|
23
|
+
<first>
|
24
|
+
<inner1 name="hello">
|
25
|
+
</inner1>
|
26
|
+
<inner2>
|
27
|
+
</inner2>
|
28
|
+
</first>
|
29
|
+
END
|
30
|
+
@xml_large_string = <<END
|
31
|
+
<n1>
|
32
|
+
<n2 id='1'>
|
33
|
+
<n3 id='1'> </n3>
|
34
|
+
<n3 id='2'> </n3>
|
35
|
+
<n3b id='5'></n3b>
|
36
|
+
<n3b id='6'></n3b>
|
37
|
+
</n2>
|
38
|
+
<n2 id='2'>
|
39
|
+
<n3 id='3'> </n3>
|
40
|
+
<n3 id='4'> </n3>
|
41
|
+
</n2>
|
42
|
+
</n1>
|
43
|
+
END
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'reads xml strings with "AXML.parse"' do
|
47
|
+
node = AXML.parse(@small_xml_string)
|
48
|
+
|
49
|
+
node.class.should == AXML::El
|
50
|
+
node.name.should == 'first'
|
51
|
+
node.children.first.name.should == 'inner1'
|
52
|
+
node.kids.first.name.should == 'inner1'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'reads file handles with "AXML.parse"' do
|
56
|
+
file = File.dirname(__FILE__) + '/axml.tmp'
|
57
|
+
File.open(file, 'w') {|fh| fh.puts @xml_string}
|
58
|
+
fh = File.open(file)
|
59
|
+
root = AXML.parse(fh)
|
60
|
+
fh.close
|
61
|
+
root.name.should == 'xml'
|
62
|
+
root.kids[0].kids.first.attrs["name"].should == 'spot'
|
63
|
+
File.unlink(file) if File.exist? file
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'reads files with "AXML.parse_file"' do
|
67
|
+
file = File.dirname(__FILE__) + '/axml.tmp'
|
68
|
+
File.open(file, 'w') {|fh| fh.puts @xml_string}
|
69
|
+
root = AXML.parse_file(file)
|
70
|
+
root.name.should == 'xml'
|
71
|
+
root.kids[0].kids.first.attrs["name"].should == 'spot'
|
72
|
+
File.unlink(file) if File.exist? file
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'can access subnodes with "children" or "kids"' do
|
76
|
+
node = AXML.parse(@small_xml_string)
|
77
|
+
node.name.should == 'first'
|
78
|
+
node.kids.zip(%w(inner1 inner2)) do |kd,nm|
|
79
|
+
kd.name.should == nm
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'accesses attributes with "[]"' do
|
84
|
+
root = AXML.parse(@xml_string)
|
85
|
+
dog_node = root.kids[0].kids[0]
|
86
|
+
dog_node.name.should == 'dog'
|
87
|
+
dog_node['name'].should == 'spot'
|
88
|
+
dog_node['height'].should == '23'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'can "find_first_descendant"' do
|
92
|
+
root = AXML.parse(@xml_string)
|
93
|
+
doc1_node = root.find_first_descendant('doc1')
|
94
|
+
doc1_node.name.should == 'doc1'
|
95
|
+
doc1_node.children.size.should == 1
|
96
|
+
doc1_node.find_first_descendant('xml').should == nil
|
97
|
+
doc1_node.find_first_descendant('doc1').should == nil
|
98
|
+
child_node = root.find_first_descendant('flea')
|
99
|
+
child_node.name.should == 'flea'
|
100
|
+
child_node['name'].should == 'ouchy'
|
101
|
+
child_node.find_first_descendant('flea').should == nil
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'can "find_first_child"' do
|
105
|
+
root = AXML.parse(@xml_string)
|
106
|
+
doc1_node = root.find_first_child('doc1')
|
107
|
+
doc1_node.name.should == 'doc1'
|
108
|
+
doc1_node.children.size.should == 1
|
109
|
+
doc1_node.find_first_child('xml').should == nil
|
110
|
+
doc1_node.find_first_child('doc1').should == nil
|
111
|
+
dog_node = doc1_node.find_first_child('dog')
|
112
|
+
dog_node.name.should == 'dog'
|
113
|
+
dog_node['name'].should == 'spot'
|
114
|
+
doc2_node = root.find_first_child('doc2')
|
115
|
+
doc2_node.name.should == 'doc2'
|
116
|
+
doc2_node.children.size.should == 1
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'can "find" with a little xpath' do
|
120
|
+
root = AXML.parse(@xml_large_string)
|
121
|
+
nodes = root.find('child::n2')
|
122
|
+
nodes.size.should == 2
|
123
|
+
nodes.each {|v| v.name.should == 'n2' }
|
124
|
+
nodes.each_with_index {|v,i| v['id'].should == (i+1).to_s }
|
125
|
+
|
126
|
+
nodes = root.find('descendant::n3')
|
127
|
+
nodes.size.should == 4
|
128
|
+
nodes.each {|v| v.name.should == 'n3' }
|
129
|
+
nodes.each_with_index {|v,i| v['id'].should == (i+1).to_s }
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'can do some find_first xpath' do
|
133
|
+
root = AXML.parse(@xml_string)
|
134
|
+
flea_node = root.find_first('descendant::flea')
|
135
|
+
flea_node.name.should == 'flea'
|
136
|
+
flea_node['name'].should == 'ouchy'
|
137
|
+
root.find_first('child::flea').should be_nil
|
138
|
+
root.find_first('child::doc2').name.should == 'doc2'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'can drop nodes with "drop"' do
|
142
|
+
root = AXML.parse(@xml_string)
|
143
|
+
root.children[0].children[0].drop
|
144
|
+
to_string = <<END
|
145
|
+
<xml>
|
146
|
+
<doc1/>
|
147
|
+
<doc2>
|
148
|
+
<dog name="billy" weight="3" height="5"/>
|
149
|
+
</doc2>
|
150
|
+
</xml>
|
151
|
+
END
|
152
|
+
root.to_s.should == to_string
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'can return "child" node' do
|
156
|
+
root = AXML.parse(@xml_string)
|
157
|
+
doc1 = root.child
|
158
|
+
doc1.name.should == 'doc1'
|
159
|
+
dog = doc1.child
|
160
|
+
dog.name.should == 'dog'
|
161
|
+
dog['name'].should == 'spot'
|
162
|
+
flea = dog.child
|
163
|
+
flea.name.should == 'flea'
|
164
|
+
flea['name'].should == 'ouchy'
|
165
|
+
flea.child.should == nil
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'can return "next" node' do
|
169
|
+
root = AXML.parse(@xml_string)
|
170
|
+
root.next.should == nil
|
171
|
+
doc1 = root.child
|
172
|
+
doc2 = doc1.next
|
173
|
+
doc2.name.should == 'doc2'
|
174
|
+
doc2.next.should == nil
|
175
|
+
dog = doc1.child
|
176
|
+
dog.name.should == 'dog'
|
177
|
+
dog.next.should == nil
|
178
|
+
flea2 = dog.child.next
|
179
|
+
flea2.name.should == 'flea'
|
180
|
+
flea2['name'].should == 'crawly'
|
181
|
+
flea2.next.should == nil
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'can find "following-sibling"' do
|
185
|
+
n1 = AXML.parse(@xml_large_string)
|
186
|
+
n3 = n1.child.child
|
187
|
+
n3.name.should == 'n3'
|
188
|
+
n3id2 = n3.find_first("following-sibling::n3")
|
189
|
+
n3id2['id'].should == '2'
|
190
|
+
n3b = n3.find_first("following-sibling::n3b")
|
191
|
+
n3b['id'].should == '5'
|
192
|
+
n3b.find_first("following-sibling::n3").should == nil
|
193
|
+
end
|
194
|
+
|
195
|
+
it '"to_s" gives xml' do
|
196
|
+
root = AXML.parse(@xml_string)
|
197
|
+
to_string = <<END
|
198
|
+
<xml>
|
199
|
+
<doc1>
|
200
|
+
<dog name="spot" weight="13" height="23">
|
201
|
+
<flea name="ouchy" weight="10" height="20"/>
|
202
|
+
<flea name="crawly" weight="9" height="22"/>
|
203
|
+
</dog>
|
204
|
+
</doc1>
|
205
|
+
<doc2>
|
206
|
+
<dog name="billy" weight="3" height="5"/>
|
207
|
+
</doc2>
|
208
|
+
</xml>
|
209
|
+
END
|
210
|
+
root.to_s.should == to_string
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'can get many attributes at once with values_at (not supported by libxml)' do
|
214
|
+
root = AXML.parse(@xml_string)
|
215
|
+
dog = root.child.child.child
|
216
|
+
exp = %w(ouchy 20 10)
|
217
|
+
reply = dog.attrs.values_at('name', 'height', 'weight')
|
218
|
+
reply.should == exp
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
gem 'rspec'
|
3
|
+
|
4
|
+
|
5
|
+
def xdescribe(*args)
|
6
|
+
puts "#{args.join(' ')}"
|
7
|
+
puts "**SKIPPING**"
|
8
|
+
end
|
9
|
+
|
10
|
+
def Xdescribe(*args)
|
11
|
+
xdescribe(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def xit(*args)
|
15
|
+
puts "- SKIPPING: #{args.join(' ')}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def silent(&block)
|
19
|
+
tmp = $VERBOSE ; $VERBOSE = nil
|
20
|
+
block.call
|
21
|
+
$VERBOSE = tmp
|
22
|
+
end
|
23
|
+
|
24
|
+
silent {
|
25
|
+
ROOT_DIR = File.dirname(__FILE__) + '/..'
|
26
|
+
SPEC_DIR = File.dirname(__FILE__)
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
class String
|
31
|
+
#alias_method :exist?, exist_as_a_file?
|
32
|
+
#alias_method exist_as_a_file?, exist?
|
33
|
+
def exist?
|
34
|
+
File.exist? self
|
35
|
+
end
|
36
|
+
def exist_as_a_file?
|
37
|
+
File.exist? self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "a cmdline program", :shared => true do
|
42
|
+
before(:all) do
|
43
|
+
testdir = File.dirname(__FILE__)
|
44
|
+
libdir = testdir + '/../lib'
|
45
|
+
bindir = testdir + '/../bin'
|
46
|
+
progname = "fasta_shaker.rb"
|
47
|
+
@cmd = "ruby -I #{libdir} #{bindir}/#{@progname} "
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'gives usage when called with no args' do
|
51
|
+
reply = `#{@cmd}`
|
52
|
+
reply.should =~ /usage/i
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: axml
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.2
|
7
|
+
date: 2007-10-19 00:00:00 -05:00
|
8
|
+
summary: AXML - Provides a simple DOM for working with XML (using XMLParser under the hood) that can serve as a drop in replacement for much of the basic libxml functionality (e.g., each, children, child, find_first, find, next). AXML comes from the idea that XML should be AXED (or at least simple to use!) to use).
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: jprince@icmb.utexas.edu
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: Parses elements, attributes, and text(content), and nothing more. Should be very easy to extend and modify for special cases. It is roughly as fast as libxml, although it currently reads in the entire document first (however, this is memory efficient - nodes are implemented using Struct).
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- John Prince
|
31
|
+
files:
|
32
|
+
- lib/axml.rb
|
33
|
+
- README
|
34
|
+
- LICENSE
|
35
|
+
- Rakefile
|
36
|
+
- specs/spec_helper.rb
|
37
|
+
- specs/axml_spec.rb
|
38
|
+
test_files:
|
39
|
+
- specs/axml_spec.rb
|
40
|
+
rdoc_options:
|
41
|
+
- --main
|
42
|
+
- README
|
43
|
+
- --title
|
44
|
+
- axml
|
45
|
+
extra_rdoc_files:
|
46
|
+
- README
|
47
|
+
- LICENSE
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
requirements:
|
53
|
+
- xmlparser is needed right now
|
54
|
+
dependencies: []
|
55
|
+
|