xml-mapping 0.8.1 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +64 -3
- data/README +871 -173
- data/README_XPATH +40 -13
- data/Rakefile +37 -26
- data/TODO.txt +39 -8
- data/examples/README +5 -0
- data/examples/company_usage.intout +34 -22
- data/examples/documents_folders.rb +31 -0
- data/examples/documents_folders.xml +16 -0
- data/examples/documents_folders_usage.intin.rb +18 -0
- data/examples/documents_folders_usage.intout +46 -0
- data/examples/order_signature_enhanced_usage.intout +21 -11
- data/examples/order_usage.intin.rb +52 -5
- data/examples/order_usage.intout +154 -80
- data/examples/person.intin.rb +44 -0
- data/examples/person.intout +27 -0
- data/examples/person_mm.intin.rb +119 -0
- data/examples/person_mm.intout +114 -0
- data/examples/publication.intin.rb +44 -0
- data/examples/publication.intout +20 -0
- data/examples/reader.intin.rb +33 -0
- data/examples/reader.intout +19 -0
- data/examples/stringarray.rb +5 -0
- data/examples/stringarray.xml +10 -0
- data/examples/stringarray_usage.intin.rb +11 -0
- data/examples/stringarray_usage.intout +31 -0
- data/examples/time_augm.intout +19 -7
- data/examples/time_augm_loading.intin.rb +44 -0
- data/examples/time_augm_loading.intout +12 -0
- data/examples/time_node.intin.rb +79 -0
- data/examples/time_node.rb +3 -2
- data/examples/time_node_w_marshallers.intin.rb +48 -0
- data/examples/time_node_w_marshallers.intout +25 -0
- data/examples/time_node_w_marshallers.xml +9 -0
- data/examples/xpath_create_new.intout +132 -114
- data/examples/xpath_ensure_created.intout +86 -65
- data/examples/xpath_pathological.intout +16 -16
- data/examples/xpath_usage.intout +1 -1
- data/install.rb +1 -0
- data/lib/xml/mapping.rb +3 -1
- data/lib/xml/mapping/base.rb +442 -272
- data/lib/xml/mapping/core_classes_mapping.rb +32 -0
- data/lib/xml/mapping/standard_nodes.rb +176 -86
- data/lib/xml/mapping/version.rb +2 -2
- data/lib/xml/rexml_ext.rb +186 -0
- data/lib/xml/xxpath.rb +28 -265
- data/lib/xml/xxpath/steps.rb +345 -0
- data/lib/xml/xxpath_methods.rb +96 -0
- data/test/all_tests.rb +4 -1
- data/test/benchmark_fixtures.rb +14 -0
- data/test/{multiple_mappings.rb → bookmarks.rb} +0 -0
- data/test/company.rb +47 -0
- data/test/documents_folders.rb +11 -1
- data/test/examples_test.rb +29 -0
- data/test/fixtures/benchmark.xml +77 -0
- data/test/fixtures/company1.xml +9 -0
- data/test/fixtures/documents_folders.xml +0 -8
- data/test/fixtures/documents_folders2.xml +13 -19
- data/test/fixtures/triangle_m1.xml +17 -0
- data/test/fixtures/triangle_m2.xml +19 -0
- data/test/inheritance_test.rb +50 -0
- data/test/multiple_mappings_test.rb +155 -0
- data/test/rexml_xpath_benchmark.rb +29 -0
- data/test/triangle_mm.rb +57 -0
- data/test/xml_mapping_adv_test.rb +36 -1
- data/test/xml_mapping_test.rb +136 -7
- data/test/xpath_test.rb +154 -0
- data/test/xxpath_benchmark.rb +36 -0
- data/test/xxpath_benchmark.result1.txt +17 -0
- data/test/xxpath_methods_test.rb +61 -0
- metadata +139 -90
@@ -0,0 +1,96 @@
|
|
1
|
+
# xxpath -- XPath implementation for Ruby, including write access
|
2
|
+
# Copyright (C) 2004-2010 Olaf Klischat
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/xxpath"
|
5
|
+
|
6
|
+
module XML
|
7
|
+
|
8
|
+
# set of convenience wrappers around XML::XPath's instance methods,
|
9
|
+
# for people who frequently use XML::XPath directly. This module is
|
10
|
+
# included into the REXML node classes and adds methods to them that
|
11
|
+
# enable you to write a call like
|
12
|
+
#
|
13
|
+
# path.first(xml_element)
|
14
|
+
#
|
15
|
+
# as the more pleasant-looking variant
|
16
|
+
#
|
17
|
+
# xml_element.first_xpath(path)
|
18
|
+
#
|
19
|
+
# with the added bonus that _path_ may not only be an XML::XXPath
|
20
|
+
# instance, but also just a String containing the XPath expression.
|
21
|
+
#
|
22
|
+
# Please note that the names of all the added methods are suffixed
|
23
|
+
# with "_xpath" to avoid name clashes with REXML methods. Please
|
24
|
+
# note also that this was changed recently, so older versions of
|
25
|
+
# xml-mapping (version < 0.9) used method names without _xpath
|
26
|
+
# appended and thus would be incompatible with this one here.
|
27
|
+
#
|
28
|
+
# As a special convenience, if you're using an older version of
|
29
|
+
# REXML that doesn't have the new methods yet, methods without
|
30
|
+
# _xpath in their names will also (additionally) be added to the
|
31
|
+
# REXML classes. This will enable code that relied on the old names
|
32
|
+
# to keep on working as long as REXML isn't updated, at which point
|
33
|
+
# that code will fail and must be changed to used the methods
|
34
|
+
# suffixed with _xpath.
|
35
|
+
module XXPathMethods
|
36
|
+
# see XML::XXPath#each
|
37
|
+
def each_xpath(path,options={},&block)
|
38
|
+
to_xxpath(path).each self, options, &block
|
39
|
+
end
|
40
|
+
|
41
|
+
# see XML::XXPath#first
|
42
|
+
def first_xpath(path,options={})
|
43
|
+
to_xxpath(path).first self, options
|
44
|
+
end
|
45
|
+
|
46
|
+
# see XML::XXPath#all
|
47
|
+
def all_xpath(path,options={})
|
48
|
+
to_xxpath(path).all self, options
|
49
|
+
end
|
50
|
+
|
51
|
+
# see XML::XXPath#create_new
|
52
|
+
def create_new_xpath(path)
|
53
|
+
to_xxpath(path).create_new self
|
54
|
+
end
|
55
|
+
|
56
|
+
unless REXML::Element.new.respond_to? :first
|
57
|
+
|
58
|
+
# see XML::XXPath#first
|
59
|
+
def first_xpath(path,options={})
|
60
|
+
to_xxpath(path).first self, options
|
61
|
+
end
|
62
|
+
|
63
|
+
# see XML::XXPath#all
|
64
|
+
def all_xpath(path,options={})
|
65
|
+
to_xxpath(path).all self, options
|
66
|
+
end
|
67
|
+
|
68
|
+
# see XML::XXPath#create_new
|
69
|
+
def create_new_xpath(path)
|
70
|
+
to_xxpath(path).create_new self
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_xxpath(path)
|
76
|
+
if String===path
|
77
|
+
XXPath.new path
|
78
|
+
else
|
79
|
+
path
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
module REXML
|
88
|
+
class Child # mix into nearly every REXML class -- maybe this is a bit too brutal
|
89
|
+
include XML::XXPathMethods
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
class XML::XXPath::Accessors::Attribute
|
95
|
+
include XML::XXPathMethods
|
96
|
+
end
|
data/test/all_tests.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.dirname(__FILE__)+"/tests_init"
|
2
|
+
|
3
|
+
require "rexml/document"
|
4
|
+
include REXML
|
5
|
+
|
6
|
+
@d = Document.new(File.new(File.dirname(__FILE__) + "/fixtures/benchmark.xml"))
|
7
|
+
|
8
|
+
@path_by_name = "foo/bar/foo/bar"
|
9
|
+
@path_by_idx = "foo/bar[5]" # "bar6"
|
10
|
+
@path_by_idx_idx = "foo/bar[3]/bar[4]" # "bar4-6"
|
11
|
+
@path_by_attr_idx = "foo/bar[@barkey='subtree']/bar[4]" # "bar4-6"
|
12
|
+
@path_by_attr = "@key" # "xy"
|
13
|
+
|
14
|
+
@count=500
|
File without changes
|
data/test/company.rb
CHANGED
@@ -4,6 +4,7 @@ require 'xml/mapping'
|
|
4
4
|
class Address; end
|
5
5
|
class Office; end
|
6
6
|
class Customer; end
|
7
|
+
class Thing; end
|
7
8
|
|
8
9
|
|
9
10
|
class Company
|
@@ -21,6 +22,7 @@ class Company
|
|
21
22
|
text_node :ent3, "arrtest/entry[3]"
|
22
23
|
|
23
24
|
array_node :stuff, "stuff", "*"
|
25
|
+
array_node :things, "stuff2", "thing", :class=>Thing
|
24
26
|
|
25
27
|
object_node :test_default_value_identity, "dummy", :default_value => ["default"]
|
26
28
|
end
|
@@ -54,3 +56,48 @@ class Customer
|
|
54
56
|
text_node :uid, "@uid"
|
55
57
|
text_node :name, "name"
|
56
58
|
end
|
59
|
+
|
60
|
+
|
61
|
+
class Thing
|
62
|
+
include XML::Mapping
|
63
|
+
|
64
|
+
choice_node 'name', (text_node :name, 'name'),
|
65
|
+
'@name', (text_node :name, '@name'),
|
66
|
+
:else, (text_node :name, '.')
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
class Names1
|
71
|
+
include XML::Mapping
|
72
|
+
|
73
|
+
choice_node :if, 'name', :then, (text_node :name, 'name'),
|
74
|
+
:elsif, 'names/name', :then, (array_node :names, 'names', 'name', :class=>String)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
class ReaderTest
|
79
|
+
include XML::Mapping
|
80
|
+
|
81
|
+
attr_accessor :read
|
82
|
+
|
83
|
+
text_node :foo, "foo"
|
84
|
+
text_node :foo2, "foo2", :reader=>proc{|obj,xml| (obj.read||=[]) << :foo2 }
|
85
|
+
text_node :foo3, "foo3", :reader=>proc{|obj,xml,default|
|
86
|
+
(obj.read||=[]) << :foo3
|
87
|
+
default.call(obj,xml)
|
88
|
+
}
|
89
|
+
text_node :bar, "bar"
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
class WriterTest
|
94
|
+
include XML::Mapping
|
95
|
+
|
96
|
+
text_node :foo, "foo"
|
97
|
+
text_node :foo2, "foo2", :writer=>proc{|obj,xml| e = xml.elements.add; e.name='quux'; e.text='dingdong2' }
|
98
|
+
text_node :foo3, "foo3", :writer=>proc{|obj,xml,default|
|
99
|
+
default.call(obj,xml)
|
100
|
+
e = xml.elements.add; e.name='quux'; e.text='dingdong3'
|
101
|
+
}
|
102
|
+
text_node :bar, "bar"
|
103
|
+
end
|
data/test/documents_folders.rb
CHANGED
@@ -23,7 +23,17 @@ end
|
|
23
23
|
class Folder <Entry
|
24
24
|
include XML::Mapping
|
25
25
|
|
26
|
-
array_node :entries, "
|
26
|
+
array_node :entries, "document|folder", :default_value=>[]
|
27
|
+
|
28
|
+
def [](name)
|
29
|
+
entries.select{|e|e.name==name}[0]
|
30
|
+
end
|
31
|
+
|
32
|
+
def append(name,entry)
|
33
|
+
entries << entry
|
34
|
+
entry.name = name
|
35
|
+
entry
|
36
|
+
end
|
27
37
|
|
28
38
|
def ==(other)
|
29
39
|
Folder===other and
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__)+"/tests_init"
|
2
|
+
$:.unshift File.dirname(__FILE__)+"/../examples"
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'xml/xxpath_methods'
|
6
|
+
|
7
|
+
require 'xml/mapping'
|
8
|
+
|
9
|
+
# unit tests for some code in ../examples. Most of that code is
|
10
|
+
# included in ../README and tested when regenerating the README, but
|
11
|
+
# some things are better done outside.
|
12
|
+
class ExamplesTest < Test::Unit::TestCase
|
13
|
+
|
14
|
+
def test_time_node
|
15
|
+
require 'time_node'
|
16
|
+
require 'order_signature_enhanced'
|
17
|
+
|
18
|
+
s = Signature.load_from_file File.dirname(__FILE__)+"/../examples/order_signature_enhanced.xml"
|
19
|
+
assert_equal Time.local(2005,2,13), s.signed_on
|
20
|
+
|
21
|
+
s.signed_on = Time.local(2006,6,15)
|
22
|
+
xml2 = s.save_to_xml
|
23
|
+
|
24
|
+
assert_equal "15", xml2.first_xpath("signed-on/day").text
|
25
|
+
assert_equal "6", xml2.first_xpath("signed-on/month").text
|
26
|
+
assert_equal "2006", xml2.first_xpath("signed-on/year").text
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1"?>
|
2
|
+
|
3
|
+
<bla rootkey='rootkeyval'>
|
4
|
+
<foo>x</foo>
|
5
|
+
<bar>bar1</bar>
|
6
|
+
<foo key='xy'>
|
7
|
+
y
|
8
|
+
<u/>
|
9
|
+
<bar barkey='hello'>
|
10
|
+
bar2
|
11
|
+
</bar>
|
12
|
+
<quux barkey='goodbye'>
|
13
|
+
quux1
|
14
|
+
</quux>
|
15
|
+
<bar>
|
16
|
+
bar3
|
17
|
+
</bar>
|
18
|
+
<bar barkey='subtree'>
|
19
|
+
bar4
|
20
|
+
<bar>
|
21
|
+
bar4-1
|
22
|
+
</bar>
|
23
|
+
<foo>
|
24
|
+
z
|
25
|
+
<bar>
|
26
|
+
bar4-2
|
27
|
+
</bar>
|
28
|
+
hello
|
29
|
+
<bar>
|
30
|
+
bar4-3
|
31
|
+
</bar>
|
32
|
+
</foo>
|
33
|
+
<bar>
|
34
|
+
bar4-4
|
35
|
+
</bar>
|
36
|
+
<bar>
|
37
|
+
bar4-5
|
38
|
+
</bar>
|
39
|
+
<quux barkey='hello'>
|
40
|
+
bar4-quux1
|
41
|
+
</quux>
|
42
|
+
<bar>
|
43
|
+
bar4-6
|
44
|
+
</bar>
|
45
|
+
<bar>
|
46
|
+
bar4-7
|
47
|
+
</bar>
|
48
|
+
</bar>
|
49
|
+
<quux barkey='hello'>
|
50
|
+
quux2
|
51
|
+
</quux>
|
52
|
+
This buffer is for notes you don't want to save, and for Lisp
|
53
|
+
evaluation. If you want to create a file, first visit that file
|
54
|
+
with C-x C-f, then enter the text in that file's own buffer.
|
55
|
+
<bar>
|
56
|
+
bar5
|
57
|
+
</bar>
|
58
|
+
<bar>
|
59
|
+
bar6
|
60
|
+
</bar>
|
61
|
+
<quux>
|
62
|
+
quux3
|
63
|
+
</quux>
|
64
|
+
<quux barkey='hello'>
|
65
|
+
quux4
|
66
|
+
</quux>
|
67
|
+
<bar>
|
68
|
+
bar7
|
69
|
+
</bar>
|
70
|
+
<bar>
|
71
|
+
bar8
|
72
|
+
</bar>
|
73
|
+
<bar>
|
74
|
+
bar9
|
75
|
+
</bar>
|
76
|
+
</foo>
|
77
|
+
</bla>
|
data/test/fixtures/company1.xml
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
<folder>
|
5
5
|
<name>home</name>
|
6
6
|
|
7
|
-
<entries>
|
8
7
|
<document>
|
9
8
|
<name>plan</name>
|
10
9
|
<contents>
|
@@ -16,11 +15,9 @@
|
|
16
15
|
<folder>
|
17
16
|
<name>work</name>
|
18
17
|
|
19
|
-
<entries>
|
20
18
|
<folder>
|
21
19
|
<name>xml-mapping</name>
|
22
20
|
|
23
|
-
<entries>
|
24
21
|
<document>
|
25
22
|
<name>README</name>
|
26
23
|
<contents>
|
@@ -34,7 +31,6 @@
|
|
34
31
|
rake away
|
35
32
|
</contents>
|
36
33
|
</document>
|
37
|
-
</entries>
|
38
34
|
</folder>
|
39
35
|
|
40
36
|
<document>
|
@@ -44,14 +40,12 @@
|
|
44
40
|
4:00 PM appointment
|
45
41
|
</contents>
|
46
42
|
</document>
|
47
|
-
</entries>
|
48
43
|
</folder>
|
49
44
|
|
50
45
|
|
51
46
|
<folder>
|
52
47
|
<name>books</name>
|
53
48
|
|
54
|
-
<entries>
|
55
49
|
<document>
|
56
50
|
<name>The Hitchhiker's Guide to the Galaxy</name>
|
57
51
|
<contents>
|
@@ -64,8 +58,6 @@
|
|
64
58
|
The Pragmatic Programmer's Guide
|
65
59
|
</contents>
|
66
60
|
</document>
|
67
|
-
</entries>
|
68
61
|
</folder>
|
69
62
|
|
70
|
-
</entries>
|
71
63
|
</folder>
|
@@ -3,28 +3,22 @@
|
|
3
3
|
<folder>
|
4
4
|
<name>home</name>
|
5
5
|
|
6
|
-
<
|
7
|
-
<
|
8
|
-
|
9
|
-
|
10
|
-
</document>
|
6
|
+
<document>
|
7
|
+
<name>plan</name>
|
8
|
+
<contents> inhale, exhale</contents>
|
9
|
+
</document>
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
<folder>
|
12
|
+
<name>work</name>
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
<name>xml-mapping</name>
|
14
|
+
<folder>
|
15
|
+
<name>xml-mapping</name>
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
</document>
|
24
|
-
</entries>
|
25
|
-
</folder>
|
26
|
-
</entries>
|
17
|
+
<document>
|
18
|
+
<name>README</name>
|
19
|
+
<contents>foo bar baz</contents>
|
20
|
+
</document>
|
27
21
|
</folder>
|
22
|
+
</folder>
|
28
23
|
|
29
|
-
</entries>
|
30
24
|
</folder>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1"?>
|
2
|
+
|
3
|
+
<triangle color="green">
|
4
|
+
<name>tri1</name>
|
5
|
+
<points>
|
6
|
+
<point>
|
7
|
+
<x> 3 </x>
|
8
|
+
<y> 0 </y>
|
9
|
+
</point>
|
10
|
+
<point>
|
11
|
+
<x> 2 </x>
|
12
|
+
<y> 4 </y>
|
13
|
+
</point>
|
14
|
+
<point>
|
15
|
+
<x> 0 </x>
|
16
|
+
<y> 1 </y>
|
17
|
+
</point>
|
18
|
+
</points>
|
19
|
+
</triangle>
|