├── HISTORY
├── VERSION
├── doc
├── index.html
└── ECMA-357.pdf
├── work
├── deprecated
│ └── meta
│ │ ├── name
│ │ ├── title
│ │ ├── version
│ │ ├── authors
│ │ ├── collection
│ │ ├── contact
│ │ ├── repository
│ │ └── description
├── re4x.rb
├── r4x.rb
├── e4x-old.rb
└── r4x2.rb
├── .gitignore
├── lib
└── r4x
│ ├── emcascript.rb
│ ├── qname.rb
│ ├── xmllist_delegate.rb
│ ├── xml_delegate.rb
│ └── e4x.rb
├── task
├── notes.syckle
├── ridoc.syckle
├── stats.syckle
├── testrb.syckle
├── rdoc.syckle
├── box.syckle
└── email.syckle
├── MANIFEST
├── README
├── PROFILE
├── .ruby
├── .gemspec
└── LICENSE
/HISTORY:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.5.0
2 |
--------------------------------------------------------------------------------
/doc/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/work/deprecated/meta/name:
--------------------------------------------------------------------------------
1 | r4x
2 |
--------------------------------------------------------------------------------
/work/deprecated/meta/title:
--------------------------------------------------------------------------------
1 | R4X
2 |
--------------------------------------------------------------------------------
/work/deprecated/meta/version:
--------------------------------------------------------------------------------
1 | 0.5.0
2 |
--------------------------------------------------------------------------------
/work/deprecated/meta/authors:
--------------------------------------------------------------------------------
1 | Thomas Sawyer
2 |
--------------------------------------------------------------------------------
/work/deprecated/meta/collection:
--------------------------------------------------------------------------------
1 | rubyworks
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | log
2 | doc/rdoc
3 | doc/ri
4 | pkg
5 | tmp
6 |
--------------------------------------------------------------------------------
/lib/r4x/emcascript.rb:
--------------------------------------------------------------------------------
1 |
2 | module EMCAScript
3 |
4 | end
--------------------------------------------------------------------------------
/task/notes.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | notes:
3 | service: Notes
4 |
5 |
--------------------------------------------------------------------------------
/task/ridoc.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | ridoc:
3 | service: RIDoc
4 |
5 |
--------------------------------------------------------------------------------
/task/stats.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | stats:
3 | service: Stats
4 |
5 |
--------------------------------------------------------------------------------
/task/testrb.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | testrb:
3 | service: Testrb
4 |
5 |
--------------------------------------------------------------------------------
/work/deprecated/meta/contact:
--------------------------------------------------------------------------------
1 | rubyworks-mailinglist@rubyforge.org
2 |
--------------------------------------------------------------------------------
/work/deprecated/meta/repository:
--------------------------------------------------------------------------------
1 | git://github.com/rubyworks/r4x.git
2 |
--------------------------------------------------------------------------------
/work/deprecated/meta/description:
--------------------------------------------------------------------------------
1 | R4X is an implementation of E4X for Ruby.
2 |
--------------------------------------------------------------------------------
/doc/ECMA-357.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubyworks/r4x/master/doc/ECMA-357.pdf
--------------------------------------------------------------------------------
/task/rdoc.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | rdoc:
3 | service : RDoc
4 | template : redfish
5 | active : true
6 |
--------------------------------------------------------------------------------
/task/box.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | box:
3 | service: Box
4 | types : [gz, gem]
5 | spec : true
6 | include: ~
7 | exclude: ~
8 | active : true
9 |
--------------------------------------------------------------------------------
/MANIFEST:
--------------------------------------------------------------------------------
1 | #!mast -x Syckfile -x Profile .ruby bin lib man spec test [A-Z]*
2 | .ruby
3 | lib/r4x/e4x.rb
4 | lib/r4x/emcascript.rb
5 | lib/r4x/qname.rb
6 | lib/r4x/xml_delegate.rb
7 | lib/r4x/xmllist_delegate.rb
8 | PROFILE
9 | LICENSE
10 | README
11 | HISTORY
12 | VERSION
13 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | = R4X
2 |
3 | R4X is a pure-Ruby implementation of E4X.
4 |
5 | == STATUS
6 |
7 | This implementation follows the E4X specification to the letter.
8 | At thei point it is only about half complete.
9 |
10 | One difficulty with the implementation is that Ruby can not
11 | support the exact syntax E4X designates, so an alternative
12 | needs to be used --which has not yet been fully settled upon.
13 |
14 |
--------------------------------------------------------------------------------
/PROFILE:
--------------------------------------------------------------------------------
1 | ---
2 | title : R4X
3 | summary: E4X for Ruby
4 | contact: Trans
5 | license: Apache 2.0
6 | authors: Thomas Sawyer
7 | company: CubyWorks
8 | created: 2008-01-27
9 |
10 | description:
11 | R4X is an implementation of E4X for Ruby.
12 |
13 | resources:
14 | home: http://rubyworks.github.com/r4x
15 | code: http://github.com/rubyworks/r4x
16 |
17 | copyright:
18 | Copyright (c) 2008 Thomas Sawyer
19 |
--------------------------------------------------------------------------------
/task/email.syckle:
--------------------------------------------------------------------------------
1 | ---
2 | email:
3 | service : Email
4 | file : ~
5 | subject : ~
6 | mailto : ruby-talk@ruby-lang.org
7 | from : ENV[EMAIL_ACCOUNT]
8 | server : ENV[EMAIL_SERVER]
9 | port : ENV[EMAIL_PORT]
10 | account : ENV[EMAIL_ACCOUNT]
11 | domain : ENV[EMAIL_DOMAIN]
12 | login : ENV[EMAIL_LOGIN]
13 | secure : ENV[EMAIL_SECURE]
14 | active : true
15 |
16 | #service : Email
17 | #mailto : ruby-talk@ruby-lang.org
18 | #from : admin@tigerops.org
19 | #server : mail.tigerops.org
20 | #port : 25
21 | #domain : tigerops.org
22 | #account : admin@tigerops.org
23 | #secure : false
24 | #login : login
25 |
26 |
--------------------------------------------------------------------------------
/.ruby:
--------------------------------------------------------------------------------
1 | ---
2 | name: r4x
3 | company: CubyWorks
4 | title: R4X
5 | contact: Trans
6 | resources:
7 | code: http://github.com/rubyworks/r4x
8 | home: http://rubyworks.github.com/r4x
9 | pom_verison: 1.0.0
10 | manifest:
11 | - .ruby
12 | - lib/r4x/e4x.rb
13 | - lib/r4x/emcascript.rb
14 | - lib/r4x/qname.rb
15 | - lib/r4x/xml_delegate.rb
16 | - lib/r4x/xmllist_delegate.rb
17 | - PROFILE
18 | - LICENSE
19 | - README
20 | - HISTORY
21 | - VERSION
22 | version: 0.5.0
23 | copyright: Copyright (c) 2008 Thomas Sawyer
24 | licenses:
25 | - Apache 2.0
26 | description: R4X is an implementation of E4X for Ruby.
27 | summary: E4X for Ruby
28 | authors:
29 | - Thomas Sawyer
30 | created: 2008-01-27
31 |
--------------------------------------------------------------------------------
/.gemspec:
--------------------------------------------------------------------------------
1 | --- !ruby/object:Gem::Specification
2 | name: r4x
3 | version: !ruby/object:Gem::Version
4 | version: 0.5.0
5 | platform: ruby
6 | authors:
7 | - rubyworks-mailinglist@rubyforge.org
8 | - Thomas Sawyer
9 | autorequire:
10 | bindir: bin
11 | cert_chain: []
12 |
13 | date: 2009-09-27 00:00:00 -04:00
14 | default_executable:
15 | dependencies: []
16 |
17 | description: R4X is an implementation of E4X for Ruby.
18 | email: rubyworks-mailinglist@rubyforge.org
19 | executables: []
20 |
21 | extensions: []
22 |
23 | extra_rdoc_files:
24 | - README
25 | - MANIFEST
26 | - LICENSE
27 | - HISTORY
28 | files:
29 | - lib
30 | - lib/r4x
31 | - lib/r4x/e4x.rb
32 | - lib/r4x/emcascript.rb
33 | - lib/r4x/qname.rb
34 | - lib/r4x/xml_delegate.rb
35 | - lib/r4x/xmllist_delegate.rb
36 | - meta
37 | - meta/abstract
38 | - meta/authors
39 | - meta/contact
40 | - meta/package
41 | - meta/project
42 | - meta/repository
43 | - meta/version
44 | - LICENSE
45 | - README
46 | - HISTORY
47 | has_rdoc: true
48 | homepage:
49 | licenses: []
50 |
51 | post_install_message:
52 | rdoc_options:
53 | - --inline-source
54 | - --title
55 | - r4x api
56 | - --main
57 | - README
58 | require_paths:
59 | - lib
60 | required_ruby_version: !ruby/object:Gem::Requirement
61 | requirements:
62 | - - ">="
63 | - !ruby/object:Gem::Version
64 | version: "0"
65 | version:
66 | required_rubygems_version: !ruby/object:Gem::Requirement
67 | requirements:
68 | - - ">="
69 | - !ruby/object:Gem::Version
70 | version: "0"
71 | version:
72 | requirements: []
73 |
74 | rubyforge_project: r4x
75 | rubygems_version: 1.3.5
76 | signing_key:
77 | specification_version: 3
78 | summary: R4X is an implementation of E4X for Ruby.
79 | test_files: []
80 |
81 |
--------------------------------------------------------------------------------
/lib/r4x/qname.rb:
--------------------------------------------------------------------------------
1 |
2 | # Defines QName and AttributeName classes.
3 |
4 | class QName
5 |
6 | class << self
7 |
8 | alias :__new :new
9 |
10 | def new( name_or_namespace, name=nil )
11 | case name_or_namespace
12 | when QName
13 | return name_or_namespace
14 | when nil
15 | if QName === name or name.class == "QName"
16 | return name.dup
17 | else
18 | __new(name_or_namespace, name)
19 | end
20 | else
21 | __new(name_or_namespace, name )
22 | end
23 | end
24 |
25 | end
26 |
27 | attr :name
28 | attr :local_name
29 | attr :uri
30 | attr :prefix
31 |
32 | def initialize( namespace, name )
33 | @name = name.local_name.to_s # to_String
34 | case namespace
35 | when nil, ''
36 | namespace = (name == '*' ? nil : get_default_namespace )
37 | end
38 | @local_name = name
39 | unless namespace
40 | @uri = nil
41 | @prefix = nil
42 | else
43 | namespace = Namespace.new( namespace )
44 | @uri = namespace.uri
45 | @prefix = namespace.prefix
46 | end
47 | end
48 |
49 | #
50 | def to_s
51 | s = ''
52 | if uri != ''
53 | unless uri
54 | s = '*::'
55 | else
56 | s = "#{uri}::"
57 | end
58 | end
59 | "#{s}#{local_name}"
60 | end
61 |
62 | #
63 | def get_namespace( in_scope_namespaces=nil )
64 | raise 'no uri [should not have occured]' unless uri
65 | in_scope_namespaces ||= []
66 | ns = in_scope_namespaces.find { |n| uri == n.uri } # prefix == n.prefix ?
67 | ns = Namespace.new( uri ) unless ns # or ns = Namespace.new( prefix, uri ) ?
68 | ns
69 | end
70 |
71 | end
72 |
73 |
74 | class AttributeName
75 |
76 | attr :name
77 |
78 | def initialize( s )
79 | @name = QName.new(s)
80 | end
81 |
82 | def to_s
83 | "@#{@name}"
84 | end
85 |
86 | end
87 |
88 |
--------------------------------------------------------------------------------
/lib/r4x/xmllist_delegate.rb:
--------------------------------------------------------------------------------
1 |
2 | class XmlList
3 |
4 | class XmlListDelegate
5 |
6 | def initialize( x )
7 | @x = x
8 | end
9 |
10 | def list ; @x.__list ; end
11 | def class ; @x.__class ; end
12 |
13 | def target_object ; @x.__target_object ; end
14 | def target_property ; @x.__target_property ; end
15 | def target_object=(to) ; @x.__target_object = to ; end
16 | def target_property=(tp) ; @x.__target_property = tp ; end
17 |
18 | def get( prop )
19 | if prop.kind_of?(Integer)
20 | return @x.__list.at( prop )
21 | end
22 | l = XmlList.new( [], @x, prop )
23 | 0...length { |i|
24 | gq = @x[i].self.get( prop )
25 | l.self.append( gq ) if gq.self.length > 0
26 | }
27 | return l
28 | end
29 |
30 | def put( prop, v )
31 | if prop.kind_of?(Integer)
32 | i = prop
33 | if @x.__target_object
34 | r = @x.__target_object.self.resolve_value
35 | return unless r
36 | else
37 | r = nil
38 | end
39 | if i >= @x.__list.length
40 | if r.is_a?(XmlList)
41 | return if r.self.length != 1
42 | else
43 | r = r[0]
44 | end
45 | y = Xml.new( @x.__target_property.to_sym, r )
46 | if @x.__target_property =~ /^[@_]/
47 | attribute_exists = r.self.get( y.self.name )
48 | return if attributes_exists.self.length > 0
49 | y.self.class = :attribute
50 | elsif (!@x.__target_property) or @x.__target_property.local_name== '*'
51 | y.self.name = nil
52 | y.self.class = :text
53 | else
54 | t.self.class = :element
55 | end
56 | i = length
57 | if y.self.class != :attribute
58 | if y.self.parent
59 | if i > 0
60 | j = 0
61 | while ((j < (y.self.parent.self.length - 1)) and (y.self.parent[j] != @x[i-1])) do
62 | j += 1
63 | end
64 | else
65 | j = y.self.parent.self.length - 1
66 | end
67 | end
68 | if v.is_a?(Xml)
69 | y.self.name = v.slef.name
70 | elsif v.is_a?(XmlList)
71 | y.self.name = v.self.property_name
72 | else
73 | raise "invalid type"
74 | end
75 | end
76 | @x.self.append y
77 | end
78 | if ( !( v.is_a?(Xml) or v.is_a?(XmlList) ) or [:text, :attribute].include?(v.self.class) )
79 | v = v.to_s #to_String
80 | end
81 | if @x[i].self.class == :attribute
82 | @x[i].self.parent.self.put( x[i].self.name, v )
83 | attr = x[i].self.parent.self.get( x[i].self.name )
84 | x[i] = attr[0]
85 | elsif v.is_a?(XmlList)
86 | c = v.dup
87 | parent = x[i].self.parent
88 | if parent
89 | q = parent.self.index(@x[i])
90 | parent.self.replace( q, c )
91 | (0...c.self.length).each { |j| c[j] = parent[q+j] }
92 | end
93 | (c.self.length-1..i).each { |j| @x[j+c.self.length] = @x[j] }
94 | (0...c.self.length).each { |j| @x[i+j] = c[j] }
95 | elsif v.is_a?(Xml) or [:text, :comment, :instruction].include?(@x[i].self.class)
96 | parent = @x[i].self.parent
97 | if parent
98 | q = parent.self.index(@x[i])
99 | parent.self.replace( q, v )
100 | v = parent[q]
101 | end
102 | x[i] = v
103 | else
104 | x[i].self.put( '*', v )
105 | end
106 | else
107 | if length == 0
108 | r = @x.resolve_value
109 | return if !r or r.self.length != 1
110 | @x.self.append( r )
111 | end
112 | @x[0].self.put( prop, v )
113 | end
114 | return
115 | end
116 |
117 | def append( v )
118 | i = @x.self.length
119 | n = 1
120 | case v
121 | when XmlList
122 | @x.__target_object = v.self.target_object
123 | @x.__target_property = v.self.target_property
124 | n = v.self.length
125 | return if n == 0
126 | (0...v.self.length).each { |i| @x[i+j] = v[j] }
127 | when Xml
128 | @x.__target_object = v.self.parent
129 | if v.self.class == :instruction
130 | @x.__target_property = nil
131 | else
132 | @x.__target_property = v.self.name
133 | end
134 | @x[i] = v
135 | # @x.length += n
136 | else
137 | raise 'Xml or XmlList expected'
138 | end
139 | end
140 |
141 | def resolve_value
142 | return if length > 0
143 | unless target_object and target_property
144 | if target_property =~ /^[_@]/ or target_property.local_name == '*'
145 | return nil
146 | end
147 | end
148 | base = target_object.self.resolve_value # recursive
149 | return nil unless base
150 | target = base.self.get( target_property )
151 | if target.self.length == 0
152 | return nil if base.is_a?(XmlList) and base.self.length > 1
153 | base.self.put( target_property, '' )
154 | target = base.self.get( target_property )
155 | end
156 | return target
157 | end
158 |
159 | def length
160 | @x.__list.length
161 | end
162 |
163 | end
164 |
165 | end
166 |
--------------------------------------------------------------------------------
/work/re4x.rb:
--------------------------------------------------------------------------------
1 | require 'rexml/document'
2 | require 'rexml/xpath'
3 |
4 | require 'facet/module/basename'
5 | require 'facet/array/store'
6 |
7 |
8 | # Some careful modification to REXML
9 |
10 | class REXML::Attribute
11 | def replace( val )
12 | @value = val.to_s
13 | @normalized = @unnormalized = nil
14 | end
15 | end
16 |
17 |
18 | # This is used it identify strings that conform to canonical XML,
19 | # ie. "content".
20 |
21 | module XmlCanonical
22 | module_function
23 | def ===( str )
24 | str = str.to_s.strip
25 | #str[0,1] == '<' && str[-1,1] == '>' # should make more robust (TODO)
26 | md = (%r{\A \< (\w+) (.*?) \>}mix).match( str )
27 | return false unless md #[2] =~ %r{xml:cdata=['"]\d+['"]}
28 | ed = (%r{\< \/ #{md[1]} [ ]* \> \Z}mix).match(str)
29 | return false unless ed
30 | true
31 | end
32 | end
33 |
34 |
35 | # The Great Call
36 |
37 | def xml( x )
38 | case x
39 | when Xml
40 | x
41 | when REXML::Element
42 | XmlElement.new x
43 | when REXML::Text
44 | XmlText.new x
45 | when REXML::Attribute
46 | XmlAttribute.new x
47 | when REXML::Instruction
48 | XmlInstruction.new x
49 | when REXML::Comment
50 | XmlComment.new x
51 | when XmlCanonical
52 | XmlElement.new(REXML::Document.new(x).root)
53 | else
54 | raise TypeError, "non-canonical xml #{x}"
55 | # String ?
56 | # ? to_s
57 | end
58 | end
59 |
60 | # The Xml Class
61 |
62 | class Xml
63 | def node! ; @node ; end
64 | def name! ; @node.name ; end
65 | def class! ; @node.class.basename.downcase.to_sym ; end
66 | def text! ; @node.to_s ; end
67 | def value! ; @node.to_s ; end
68 |
69 | def to_s ; @node.to_s ; end
70 | def to_i ; @node.to_s.to_i ; end # ?
71 | end
72 |
73 |
74 | # The XmlText Virtual Class
75 |
76 | class XmlText < Xml
77 | def initialize( node )
78 | raise unless REXML::Text === node
79 | @node = node
80 | end
81 | def name! ; nil ; end
82 | end
83 |
84 | # The XmlAttribute Virtual Class
85 |
86 | class XmlAttribute < Xml
87 | def initialize( node )
88 | raise unless REXML::Attribute === node
89 | @node = node
90 | end
91 | end
92 |
93 | # The XmlElement Virtual Class
94 |
95 | class XmlElement < Xml
96 |
97 | def method_missing( name, *args )
98 | name = name.to_s
99 | name.gsub!( /^_/, '@' )
100 | if name =~ /=$/
101 | name.gsub!( /=$/, "" )
102 | put!( name, args[0] )
103 | else
104 | get!( name )
105 | end
106 | end
107 |
108 | def initialize( node )
109 | raise unless REXML::Element === node
110 | @node = node
111 | end
112 |
113 | def []( key ) ; get!( key ) ; end
114 | def []=( key, val ) ; put!( key, val ) ; end
115 |
116 | def each ; @node.each { |e| yield e } ; end
117 |
118 | def text! ; @node.text ; end
119 | def value! ; @node.text ; end
120 |
121 | def attributes!() @node.attributes ; end
122 |
123 | def get!( key )
124 | XmlList.new( xpath!( key.to_s ) )
125 | end
126 |
127 | def put!( key, val )
128 | key=key.to_s
129 | if key =~ /^@/
130 | @node.attributes[ key ] = val
131 | else
132 | r = get!( key )
133 | case r.size
134 | when 0
135 | r.put!( key, val )
136 | when 1
137 | r.replace!( val )
138 | else
139 | raise "how many?"
140 | end
141 | end
142 | end
143 |
144 | def add!( n )
145 | case n
146 | when Xml
147 | @node << n.node!
148 | when XmlList
149 | n.each { |e| self << e }
150 | else
151 | @node.add_text n.to_s
152 | end
153 | self
154 | end
155 |
156 | alias :<< :add!
157 | #alias :+ :add!
158 |
159 | def replace!( val )
160 | case @node
161 | when REXML::Attribute
162 | @node.replace( val )
163 | when REXML::Element
164 | @node.delete_element('*')
165 | @node.text = nil
166 | add!( val )
167 | end
168 | end
169 |
170 | def xpath!( name )
171 | children = XmlList.new()
172 | REXML::XPath.each( @node, "#{name}" ) { |elem|
173 | children.push( xml( elem ) )
174 | }
175 | children
176 | end
177 |
178 | end
179 |
180 |
181 | class XmlList < Array
182 |
183 | #def method_missing( sym, *args )
184 | # self[0].send( sym, *args )
185 | #end
186 |
187 | def to_s
188 | self.join('')
189 | end
190 |
191 | def get!( key )
192 | case key
193 | when Integer
194 | at(key)
195 | else
196 | case size
197 | when 0
198 | []
199 | when 1
200 | at(0).get!( key )
201 | else
202 | XmlList.new( collect{ |e| e.xpath!( key.to_s ) } )
203 | end
204 | end
205 | end
206 |
207 | def put!( key, val )
208 | if Integer === key and key >= size
209 | add!( xml(val) ) #?
210 | else
211 | r = get!( key )
212 | case r.size
213 | when 0
214 | return nil
215 | when 1
216 | r[0].replace!( val )
217 | else
218 | return nil
219 | end
220 | end
221 | end
222 |
223 | def add!( n )
224 | self.push(n)
225 | self
226 | end
227 |
228 | alias :<< :add!
229 |
230 | def []( key )
231 | get!( key )
232 | end
233 |
234 | def []=( key, val )
235 | put!( key, val )
236 | end
237 |
238 | end
239 |
240 |
241 | # internal testing
242 |
243 | if $0 == __FILE__
244 |
245 | q = %{
246 |
247 |
248 | 2004-12-18
249 | Santa
250 | 0.32
251 | 2.45
252 |
253 |
254 | 2003-12-18
255 | Bunny
256 | 0.32
257 | 1.20
258 |
259 |
260 | }
261 |
262 | x = xml( q )
263 |
264 | puts
265 | puts x
266 | puts
267 | puts x['stamp'][0]['face']
268 | x['stamp'][0]['face'] = "5.00"
269 | puts x['stamp'][0]['face']
270 |
271 | end
272 |
--------------------------------------------------------------------------------
/work/r4x.rb:
--------------------------------------------------------------------------------
1 | #
2 | # This key idea behingd this implementation is that the XML
3 | # is actually stored in String form throughout (albiet
4 | # the parserd form in cached for speed). as the XML is processed
5 | # it is parsed on the fly. Becuase of this, simply inserting
6 | # a valid XML string into a node will "automatically" take.
7 | #
8 | # Of course, that's the idea. Implementation is a little tricky.
9 | #
10 |
11 |
12 | require 'nano/string/shatter'
13 | require 'nano/string/shift'
14 | require 'nano/string/dequote'
15 |
16 |
17 | START_TAG_RE = %r{\A \< (\w+) (.*?) \>}mix
18 |
19 | # This is used it identify strings that conform to canonical XML element text.
20 | # It could afford to be made alittle more robust.
21 | #
22 | module XmlCanonical
23 | module_function
24 | def ===( str )
25 | str = str.to_s.strip
26 | #str[0,1] == '<' && str[-1,1] == '>' # should make more robust (TODO)
27 | md = (%r{\A \< (\w+) (.*?) \>}mix).match( str )
28 | return false unless md #[2] =~ %r{xml:cdata=['"]\d+['"]}
29 | ed = (%r{\< \/ #{md[1]} [ ]* \> \Z}mix).match(str)
30 | return false unless ed
31 | true
32 | end
33 | end
34 |
35 |
36 | def xml( str_or_arr )
37 | Xml.new( str_or_arr )
38 | end
39 |
40 | class Xml
41 |
42 | def initialize( x )
43 | case x
44 | when String
45 | raise unless XmlCanonical === x
46 | @canonical = x.strip
47 | children
48 | when Array
49 | @canonical = x.join('')
50 | @children = x
51 | else
52 | raise ArgumentError
53 | end
54 | end
55 |
56 | #def reset
57 | # @name = nil
58 | # @attributes = nil
59 | # @elements = nil
60 | #end
61 |
62 | def children
63 | @children ||= __parse__( @canonical )[0][1...-1]
64 | end
65 |
66 | def elements
67 | @elements ||= children.select { |e| XmlCanonical === e }
68 | end
69 |
70 | def texts
71 | @texts ||= children.reject { |e| XmlCanonical === e }
72 | end
73 |
74 | def elements_assoc
75 | @elements.collect { |e| [ START_TAG_RE.match( e[0] )[1], e ] }
76 | end
77 |
78 | def name
79 | @name ||= START_TAG_RE.match( @canonical )[1]
80 | end
81 |
82 | def attributes
83 | unless @attributes
84 | s = START_TAG_RE.match( @canonical )[2].strip
85 | a = s.split( %r{\s+|\=}x ).collect { |e| e.dequote }
86 | @attributes = Hash[ *a ]
87 | end
88 | @attributes
89 | end
90 |
91 | def value
92 | @children.join('')
93 | end
94 |
95 | def []( k )
96 | if Integer === k
97 | e = children[k]
98 | XmlCanonical === e ? xml( e ) : e
99 | elsif k == '*'
100 | xml( elements )
101 | elsif k == '@*'
102 | attributes
103 | elsif k =~ /^[@]/
104 | attributes[ k.shift ]
105 | else
106 | q = elements.select { |e| START_TAG_RE.match( e[0] )[1] == k }
107 | if q.length == 0
108 | nil
109 | elsif q.length == 1
110 | ::Xml.new( q[0] )
111 | else
112 | ::XmlList.new( q )
113 | end
114 | end
115 | end
116 |
117 | end
118 |
119 |
120 | class XmlList
121 |
122 | def initialize( a )
123 | @canonical = a.join('')
124 | @children = a
125 | end
126 |
127 | def children
128 | @children
129 | end
130 |
131 | def elements
132 | @elements ||= children.select { |e| ::XmlCanonical === e.join('') }
133 | end
134 |
135 | def texts
136 | @texts ||= children.reject { |e| ::XmlCanonical === e.join('') }
137 | end
138 |
139 | def elements_assoc
140 | @elements.collect { |e| [ START_TAG_RE.match( e[0] )[1], e ] }
141 | end
142 |
143 | def value
144 | @children.join('')
145 | end
146 |
147 | def []( k )
148 | case k
149 | when Integer
150 | q = @children[k]
151 | return q unless q
152 | if q.length == 1
153 | ::Xml.new( q )
154 | else
155 | ::XmlList.new( q )
156 | end
157 | when '*'
158 | when '@*'
159 | else
160 | elements.each { |e| START_TAG_RE.match( e[0] )[1] == k }
161 | end
162 | end
163 |
164 | end
165 |
166 |
167 | #module XmlUtil
168 |
169 | RETAG = %r{ \< (\/)? ([\w.:]+) (.*?) ([/])? \> }mix
170 | IDXEND = 1
171 | IDXNAME = 2
172 | IDXATTR = 3
173 | IDXUNIT = 4
174 |
175 | #module_function
176 |
177 | def __parse__(xmldata)
178 | if String === xmldata
179 | q = xmldata.strip.shatter(RETAG)
180 | else
181 | q = xmldata.dup
182 | end
183 | # setup
184 | build = []
185 | current = build
186 | stack = []
187 | # stack loop
188 | until q.empty?
189 | e = q.shift
190 | if md = RETAG.match( e )
191 | if md[IDXEND]
192 | #close-tag
193 | current << e
194 | current = stack.pop
195 | elsif md[IDXUNIT] == '/'
196 | #unit-tag
197 | current << e
198 | else
199 | #open-tag
200 | stack << current
201 | current << []
202 | current = current.last
203 | current << e
204 | end
205 | else
206 | current << e #if e != "\n"
207 | end
208 | end
209 | return build
210 | end
211 |
212 | #end
213 |
214 |
215 | if $0 == __FILE__
216 |
217 | xs = %{
218 |
219 |
220 | Tom
221 | 35
222 |
223 |
224 | George
225 | 30
226 |
227 |
228 | }
229 |
230 | x = xml( xs )
231 |
232 | puts
233 | p x
234 | puts
235 | p x.name
236 | puts
237 | p x.attributes
238 | puts
239 | p x.children
240 | puts
241 | p x.elements
242 | # puts
243 | # p x.texts
244 | # puts
245 | # p x.elements_assoc
246 | # puts
247 | # p x[1]
248 | # puts
249 | # p x['*']
250 | # puts
251 | # p x['@*']
252 | # puts
253 | # p x['@type']
254 | # puts
255 | # p x['person']
256 | # puts
257 | #
258 |
259 | puts
260 | p x['person']
261 | puts
262 | p x['person']['name']
263 |
264 | end
265 |
--------------------------------------------------------------------------------
/lib/r4x/xml_delegate.rb:
--------------------------------------------------------------------------------
1 |
2 | class Xml #< BlankSlate
3 |
4 | class XmlDelegate
5 |
6 | include Enumerable
7 |
8 | def initialize( x )
9 | @x = x
10 | end
11 |
12 | def node ; @x.__node ; end
13 | def name ; @x.__node.name ; end
14 | def text ; @x.__node.text ; end
15 |
16 | def klass ; @x.__class ; end
17 | def parent ; @x.__parent ; end
18 | def attributes ; @x.__node.attributes ; end
19 | def value ; @x.__node.children.join('') ; end
20 |
21 | #
22 | def get(prop)
23 | if Integer === prop
24 | l = to_XmlList
25 | return l.__get__(prop)
26 | end
27 | n = prop.self.to_XmlName
28 | l = XmlList.new([],@x,n)
29 | if AttributeName === n
30 | @x.attributes.each { |a|
31 | if ( ( n.name.local_name =='*' || n.name.local_name == a.name.local_name ) and
32 | ( n.name.uri == nil || n.name.uri == a.name.uri ) )
33 | l.append(a)
34 | end
35 | }
36 | return l
37 | end
38 | (0...length).each { |k|
39 | if ( (n.local_name == '*') or
40 | ((Element === @x[k]) and (@x[k].name.local_name == a.name.local_name)) ) and
41 | ( (n.uri == nil) or ((@x[k].__class__ == "element") and (n.uri == @x[k].name.uri)) )
42 | l.append(@x[k])
43 | end
44 | }
45 | return l
46 | end
47 |
48 | # def get( prop )
49 | # if prop.kind_of?(Integer)
50 | # l = to_XmlList
51 | # return l.self.get( prop )
52 | # end
53 | # #n = prop.to_XmlName
54 | # l = XmlList.new([], @x, prop)
55 | # # if prop =~ /^[@_]/
56 | # # @x.__node.attributes.each{ |a|
57 | # # l.self.append a
58 | # # }
59 | # # return l
60 | # # end
61 | # REXML::XPath.each( @x.__node, prop.to_s ) { |elem|
62 | # l.self.append( Xml.new( elem ) )
63 | # }
64 | # return l
65 | # end
66 |
67 | # def put( key, val )
68 | # if key =~ /^[@_]/
69 | # @x.__node.attributes[ key.shift ] = value
70 | # elsif gk = get(key)
71 | # case gk.size
72 | # when 0
73 | # add "<#{key}>#{val}#{key}>"
74 | # when 1
75 | # gk[0] #?
76 | # else
77 | # raise "unimplemented"
78 | # #? What to do then?
79 | # end
80 | # else
81 | # insert( key, val )
82 | # end
83 | # end
84 |
85 | #
86 | def put( prop, val )
87 | if !(Xml === val or XmlList === val) or ( [:text,:attribute].include?(val.self.class) )
88 | c = val.to_s
89 | else
90 | c = val.self.deepcopy
91 | end
92 | raise ArgumentError if Numeric === prop
93 | return if [:text,:attribute,:comment,:instruction].include?( klass )
94 | n = prop.to_XmlName
95 | default_namespace = get_default_namespace()
96 | if AttributeName === n
97 | return unless is_XmlName(n.self.name)
98 | if XmlList === c
99 | if c.length === 0
100 | c = ''
101 | else
102 | #s = c[0].to_s
103 | #(1...c.length).each { |i| s += " #{c[i].to_s}"
104 | s = c.join(' ')
105 | end
106 | else
107 | c = c.to_s
108 | end
109 | a = nil
110 | x.attributes.each { |j|
111 | if (n.name.local_name == j.name.local_name) and (n.name.uri == nil or n.name.uri == j.name.uri)
112 | a = j unless a
113 | else
114 | x.delete(j.name)
115 | end
116 | }
117 | unless a
118 | unless n.name.uri
119 | nons = Namespace.new
120 | name = QName.new( nons, n.name )
121 | else
122 | name = QName.new( n.name )
123 | end
124 | a = Xml.new { |s| s.name=name ; s.classification=:attribute ; s.parent=x }
125 | x.attributes << a
126 | ns = name.get_namespace
127 | x.add_in_scope_namespace(ns)
128 | end
129 | a.value = c
130 | return
131 | end
132 | is_valid_name = is_XmlName(n)
133 | return if !is_valid_name and n.local_name != '*'
134 | i = nil
135 | primitive_assign = ((!(Xml === c or XmlList === c)) and n.local_name != '*')
136 | (x.length-1).downto(0) { |k|
137 | if ( (n.local_name == '*') or ( (@x[k].classification == :element) and (@x[k].name.locall_name == n.local_name) ) ) and
138 | ( (n.uri == nil) or ( (@x[k].classification==:element) and (n.uri == @x[k].name.uri) ) )
139 | if i
140 | x.delete_by_index(i.to_s)
141 | i = k
142 | end
143 | end
144 | }
145 | unless i
146 | i = x.length
147 | if primitive_assign
148 | unless n.uri
149 | name = QName.new( default_namespace, n )
150 | else
151 | name = QName.new(n)
152 | end
153 | y=Xml.new{|s| s.name=name; s.classification=:element; s.parent=x}
154 | ns=name.get_namespace
155 | x.replace(i.to_s,y)
156 | y.add_in_scope_namespace(ns)
157 | end
158 | end
159 | if primitive_asign
160 | # x[i].delete_all_properties
161 | s = c.to_s
162 | x[i].replace("0",s) if s != ''
163 | else
164 | x.replace(i.to_s,c)
165 | end
166 | return
167 | end
168 |
169 | def add( nodes )
170 | case nodes
171 | when XmlList
172 | nodes.each { |n| @x.__node << n.__node }
173 | else
174 | @x.__node << nodes.__node
175 | end
176 | @x
177 | end
178 |
179 | #
180 | def delete(prop)
181 | raise ArgumentError if Numeric === prop
182 | n = prop.self.to_XmlName
183 | if AttributeName === n
184 | attribs = attributes.collect{|a|
185 | if ((n.name.local_name == '*') or (n.name.local_name == a.name.local_name)) and
186 | ((n.name.uri == nil) or (n.name.uri == a.name.uri))
187 | a.parent = nil
188 | nil
189 | else
190 | a
191 | end
192 | }.compact
193 | return true
194 | end
195 | dp = 0
196 | (0...length).each { |q|
197 | if ((n.local_name == '*') or
198 | (@x[q].self.class == :element and @x[q].self.name.local_namespace == n.local_name)) and
199 | ((n.uri == nil) or (@x[q].self.class == :element and n.uri == @x[q].self.name.uri))
200 | x[q].parent = nil
201 | x.delete_at(q)
202 | dp+=1
203 | else
204 | if dp > 0
205 | @x[q - dp] = x[q]
206 | @x.delete_at(q)
207 | end
208 | end
209 | }
210 | return true
211 | end
212 |
213 | #
214 | def delete_by_index(prop)
215 | end
216 |
217 | #
218 | def default_value
219 | end
220 |
221 | #
222 | def has_property
223 | end
224 |
225 | #
226 | def deep_copy
227 | end
228 |
229 | #
230 | def descendents(prop)
231 | end
232 |
233 | #
234 | def equals(value)
235 | end
236 |
237 | #
238 | def resolve_value
239 | @x
240 | end
241 |
242 | #
243 | def insert(prop,value)
244 | end
245 |
246 | #
247 | def replace(prop,value)
248 | end
249 |
250 | #
251 | def add_in_scope_namespace__(namespace)
252 | end
253 |
254 | def delete( key )
255 | @x.__node.delete_element( key ) #string key is an xpath
256 | end
257 |
258 |
259 | # Conversions
260 |
261 | def to_XmlList
262 | XmlList.new( @x )
263 | end
264 |
265 | # def to_XmlList
266 | # target_object = self.__parent__
267 | # target_poperty = self.__name__
268 | # l = XmlList.new([self], target_object, target_property)
269 | # end
270 |
271 | def to_XmlName
272 | s = to_String
273 | if s =~ /^[_@]/
274 | to_AttributeName( s.shift )
275 | else
276 | QName.new(s)
277 | end
278 | end
279 |
280 | def to_String
281 | return value if [:attribute, :text].include?(@x)
282 | if has_simple_content
283 | s = ''
284 | @x.each { |e| s << e unless [:comment,:instruction].include?(e.self.class) }
285 | return s
286 | else
287 | to_XmlString
288 | end
289 | end
290 |
291 | def to_XmlString( ancestor_namespaces=nil, indent_level=nil )
292 |
293 | end
294 |
295 | end
296 |
297 | end
298 |
--------------------------------------------------------------------------------
/work/e4x-old.rb:
--------------------------------------------------------------------------------
1 | #
2 | # E4X for Ruby
3 | #
4 | #
5 |
6 | require 'rexml/document'
7 | require 'rexml/xpath'
8 |
9 | def xml(xmldata)
10 | Xml.new(xmldata)
11 | end
12 |
13 | module EMCAScript
14 |
15 | def toXmlList
16 |
17 | end
18 |
19 | end
20 |
21 |
22 | class Xml
23 |
24 | # def method_missing( name, *args )
25 | # name = name.to_s
26 | # if ( name =~ /^_/ )
27 | # name.gsub!( /^_/, "" )
28 | # if ( name =~ /=$/ )
29 | # name.gsub!( /=$/, "" )
30 | # _write_attribute( name, args[0] )
31 | # else
32 | # _read_attribute( name )
33 | # end
34 | # else
35 | # xpath( "#{name}" )
36 | # end
37 | # end
38 |
39 | def initialize( node )
40 | #@node = node
41 | @node = REXML::Document.new(xmldata).root
42 | end
43 |
44 | def to_XmlList
45 | target_object = self.__parent__
46 | target_poperty = self.__name__
47 | l = XmlList.new([self], target_object, target_property)
48 | end
49 |
50 | def name
51 | @node.name
52 | end
53 |
54 | def parent
55 | @node.parent
56 | end
57 |
58 | def attributes
59 | @node.attributes
60 | end
61 |
62 | def in_scope_namspace
63 | @node.namespace
64 | end
65 |
66 | def length
67 | @node.children.length
68 | end
69 |
70 | #
71 | def get(prop)
72 | x = self
73 | if Integer === prop
74 | l = to_XmlList
75 | return l.__get__(prop)
76 | end
77 | n = prop.to_XmlName
78 | l = XmlList.new([],x,n)
79 | if AttributeName === n
80 | x.attributes.each { |a|
81 | if (( n.name.local_name =='*' || n.name.local_name == a.name.local_name )
82 | and ( n.name.uri == nil || n.name.uri == a.name.uri ))
83 | l.append(a)
84 | end
85 | }
86 | return l
87 | end
88 | (0...x.Length).each { |k|
89 | if ((n.local_name == '*')
90 | or ((Element === x[k]) and (x[k].name.local_name == a.name.local_name)))
91 | and ((n.uri == nil) or ((x[k].__class__ == "element") and (n.uri == x[k].name.uri)))
92 | l.append(x[k])
93 | end
94 | }
95 | return l
96 | end
97 |
98 | #
99 | def put( prop, val )
100 | x = self
101 | if !(Xml === val or XmlList === val) or ( [:text,:attribute].include?(val.classification) )
102 | c = val.to_s
103 | else
104 | c = val.deepcopy
105 | end
106 | raise ArgumentError if Numeric === prop
107 | return if [:text,:attribute,:comment,:processing_instruction].inlcude?( x.classification )
108 | n = prop.to_XmlName
109 | default_namespace = get_default_namespace
110 | if AttributeName === n
111 | return unless is_XmlName(n.name)
112 | if XmlList === c
113 | if c.length === 0
114 | c = ''
115 | else
116 | #s = c[0].to_s
117 | #(1...c.length).each { |i| s += " #{c[i].to_s}"
118 | s = c.join(' ')
119 | end
120 | else
121 | c = c.to_s
122 | end
123 | a = nil
124 | x.attributes.each { |j|
125 | if (n.name.local_name == j.name.local_name and (n.name.uri == nil or n.name.uri == j.name.uri)
126 | a = j unless a
127 | else
128 | x.delete(j.name)
129 | end
130 | }
131 | unless a
132 | unless n.name.uri
133 | nons = Namespace.new
134 | name = QName.new( nons, n.name )
135 | else
136 | name = QName.new( n.name )
137 | end
138 | a = Xml.new { |s| s.name=name ; s.classification=:attribute ; s.parent=x }
139 | x.attributes << a
140 | ns = name.get_namespace
141 | x.add_in_scope_namespace(ns)
142 | end
143 | a.value = c
144 | return
145 | end
146 | is_valid_name = is_XmlName(n)
147 | return if !is_valid_name and n.local_name != '*'
148 | i = nil
149 | primitive_assign = ((!(Xml === c or XmlList === c)) and n.local_name != '*')
150 | (x.length-1).downto(0) { |k|
151 | if ((n.local_name == '*') or (( x[k].classification == :element) and (x[k].name.locall_name == n.local_name)))
152 | and ((n.uri == nil) or ((x[k].classification==:element) and (n.uri == x[k].name.uri)))
153 | if i
154 | x.delete_by_index(i.to_s)
155 | i = k
156 | end
157 | end
158 | }
159 | unless i
160 | i = x.length
161 | if primitive_assign
162 | unless n.uri
163 | name = QName.new( default_namespace, n )
164 | else
165 | name = QName.new(n)
166 | end
167 | y=Xml.new{|s| s.name=name; s.classification=:element; s.parent=x}
168 | ns=name.get_namespace
169 | x.replace(i.to_s,y)
170 | y.add_in_scope_namespace(ns)
171 | end
172 | end
173 | if primitive_asign
174 | # x[i].delete_all_properties
175 | s = c.to_s
176 | x[i].replace("0",s) if s != ''
177 | else
178 | x.replace(i.to_s,c)
179 | end
180 | return
181 | end
182 |
183 | #
184 | def delete(prop)
185 | x = self
186 | raise ArgumentError if Numeric === prop
187 | n = to_XmlName(prop)
188 | if AttributeName === n
189 | x.attributes = x.attributes.collect{|a|
190 | if ((n.name.local_name == '*') or (n.name.local_name == a.name.local_name))
191 | and ((n.name.uri == nil) or (n.name.uri == a.name.uri))
192 | a.parent = nil
193 | nil
194 | else
195 | a
196 | end
197 | }.compact
198 | return true
199 | end
200 | dp = 0
201 | (0...x.length).each{|q|
202 | if ((n.local_name == '*')
203 | or (x[q].classification == :element and x[q].name.local_namespace == n.local_name))
204 | and ((n.uri == nil) or (x[q].classification == :element and n.uri == x[q].name.uri))
205 | x[q].parent = nil
206 | x.delete_at(q)
207 | dp+=1
208 | else
209 | if dp > 0
210 | x[q - dp] = x[q]
211 | x.delete_at(q)
212 | end
213 | end
214 | }
215 | x.length = x.length - dp # really need to do this?
216 | return true
217 | end
218 |
219 | #
220 | def delete_by_index(prop)
221 | end
222 |
223 | #
224 | def __default_value__
225 | end
226 |
227 | #
228 | def __has_property__
229 | end
230 |
231 | #
232 | def __deep_copy__
233 | end
234 |
235 | #
236 | def __descendents__(prop)
237 | end
238 |
239 | #
240 | def __equals__(value)
241 | end
242 |
243 | #
244 | def __resolve_value__
245 | end
246 |
247 | #
248 | def __insert__(prop,value)
249 | end
250 |
251 | #
252 | def __replace__(prop,value)
253 | end
254 |
255 | #
256 | def __add_in_scope_namespace__(namespace)
257 | end
258 |
259 |
260 |
261 |
262 |
263 |
264 | def __text() @node.text; end
265 |
266 | def to_s() @node.to_s; end
267 |
268 | def to_i() @node.to_s.to_i; end
269 |
270 | def _add ( nodes )
271 | @node << nodes._get_node
272 | self
273 | end
274 |
275 | alias :<< :_add
276 |
277 | alias :+ :_add
278 |
279 | def _get_node() @node; end
280 |
281 | def xpath( name )
282 | out = XmlList.new()
283 | @node.each_element( name ) { |elem|
284 | out.push( Xml.new( elem ) )
285 | }
286 | return out
287 | #children = XmlList.new()
288 | #REXML::XPath.each( @node, "#{name}" ) { |elem|
289 | # children.push( Xml.new( elem ) )
290 | #}
291 | #children
292 | end
293 |
294 | private
295 |
296 | def _read_attribute( name )
297 | @node.value.to_s if @node.class == REXML::Attribute
298 | @node.attributes[ name ].to_s if @node.class == REXML::Element
299 | end
300 |
301 | def _write_attribute( name, value )
302 | @node.attributes[ name ] = value
303 | end
304 |
305 | end
306 |
307 | class XmlList < Array
308 | def initialize( content, target_object, target_property )
309 | @target_object = target_object
310 | @target_property = target_poperty
311 | super( content )
312 | end
313 |
314 | def method_missing( name, *args )
315 | name = name.to_s
316 | if (args.size > 0)
317 | self[0].send( name, args )
318 | else
319 | self[0].send(name)
320 | end
321 | end
322 | end
323 |
324 | class AttributeName
325 | def initialize( name )
326 | @name = name
327 | end
328 |
329 | def to_s
330 | "@#{@name}"
331 | end
332 | end
333 |
334 |
335 | # test
336 |
337 | x = xml %Q{
338 |
339 |
340 | Tom
341 | 35
342 |
343 |
344 | Becky
345 | 32
346 |
347 |
348 | }
349 |
350 | p x
351 | puts x.people
352 |
353 |
354 |
--------------------------------------------------------------------------------
/lib/r4x/e4x.rb:
--------------------------------------------------------------------------------
1 |
2 | # E4X (Lite)
3 | #
4 | # This is a E4X library making it easy to parse and manipulate XML documents.
5 | # It is not a compliant implementaion of E4X, but it is very close to being so
6 | # from the end-user's point-of-view.
7 | #
8 | # This library uses REXML as a backend. An option to use libxml may be added in
9 | # the future for speed.
10 |
11 | require 'rexml/document'
12 | require 'rexml/xpath'
13 |
14 | #require 'facet/object/deepcopy'
15 | require 'facet/string/shift'
16 | require 'facet/string/pop'
17 |
18 | require 'e4x/qname'
19 | require 'e4x/xml_delegate'
20 | require 'e4x/xmllist_delegate'
21 |
22 |
23 | def xml( xmldata )
24 | Xml.new(xmldata)
25 | end
26 |
27 | class Xml
28 |
29 | # This is used it identify strings that conform to canonical XML element text.
30 | module XmlCanonical
31 | module_function
32 | def ===( str )
33 | str = str.to_s.strip
34 | #str[0,1] == '<' && str[-1,1] == '>' # should make more robust (TODO)
35 | md = (%r{\A \< (\w+) (.*?) \>}mix).match( str )
36 | return false unless md #[2] =~ %r{xml:cdata=['"]\d+['"]}
37 | ed = (%r{\< \/ #{md[1]} [ ]* \> \Z}mix).match(str)
38 | return false unless ed
39 | true
40 | end
41 | end
42 |
43 |
44 | VALID_CLASSES = [ :element, :text, :comment, :instruction, :attribute ]
45 |
46 | # These are for a special usage (non-standard XML); ignored for all standard purposes.
47 | #VERB_INDICATOR = '|'
48 | #VERB_REGEX = %r{ \< ([\w.:]+) (.*?) ([#{VERB_INDICATOR}]\d*) \> }mix
49 |
50 | class << self
51 | alias :__new :new
52 | def new( xmldata, parent=nil )
53 | case xmldata
54 | when nil, ''
55 | raise ArgumentError
56 | when Xml, Symbol, XmlCanonical
57 | __new( xmldata, parent )
58 | when REXML::Element, REXML::Text, REXML::Attribute, REXML::Instruction
59 | __new( xmldata, parent )
60 | else
61 | XmlList.new(xmldata, parent)
62 | end
63 | end
64 | end
65 |
66 | def initialize( xmldata, parent=nil )
67 | @parent = parent
68 | case xmldata
69 | when Xml
70 | @node = xmldata.__node.dup
71 | @class = xmldata.__class.dup
72 | @name = xmldata.__node.name.dup
73 | when Symbol
74 | #@node = REXML::Document.new( "<#{xmldata}>#{xmldata}>" ).root
75 | #@node = REXML::Element.new( "<#{xmldata}>#{xmldata}>" ).root
76 | @node = REXML::Element.new( xmldata )
77 | @class = :element
78 | @name = @node.name
79 | when XmlCanonical
80 | xmldata = xmldata.to_s
81 | @node = REXML::Document.new( xmldata.strip ).root
82 | #@node = REXML::Element.new( xmldata.strip )
83 | @class = :element
84 | @name = @node.name
85 | when REXML::Element
86 | @node = xmldata
87 | @class = :element
88 | @name = @node.name
89 | when REXML::Text
90 | @node = xmldata
91 | @class = :text
92 | @name = nil
93 | when REXML::Attribute
94 | @node = xmldata
95 | @class = :attribute
96 | @name = xmldata.name
97 | when REXML::Instruction
98 | @node = xmldata
99 | @class = :instruction
100 | @name = xmldata.target
101 | else
102 | raise ArgumentError, "invlaid xml"
103 | end
104 | @self ||= XmlDelegate.new(self)
105 | end
106 |
107 | # These are reserved tag names, i.e. they can't be used as xml tags
108 | # and then accessed via the call syntax of E4X.
109 | #
110 | # self
111 | # __node
112 | # __class
113 | # to_s
114 | # to_i
115 | # each
116 | #
117 |
118 | # This is how to access the underlying Xml object, i.e. via the delegate.
119 | def self ; @self ; end
120 |
121 | # This is how the delegate accesses the node.
122 | def __node ; @node ; end
123 |
124 | # This is how the delegate accesses the node classification.
125 | def __class ; @class ; end
126 |
127 | # Important for this to work in string interpolation.
128 | def to_s() @node.to_s ; end
129 |
130 | # ?
131 | def to_i() @node.to_s.to_i; end
132 |
133 | # (neccessary?) FIX!!!
134 | def each()
135 | @node.each_child { |c| yield(c) }
136 | end
137 |
138 | # Shortcut for add.
139 | def <<( n )
140 | @self.add( n )
141 | end
142 |
143 | # XPath for all elements.
144 | def * ; @self.get('*') ; end
145 |
146 | # Shortcut for XPath '@*', meaning all attributes.
147 | def _ ; @self.get('@*') ; end
148 |
149 | # XPath get operator.
150 | def []( key )
151 | @self.get( key )
152 | end
153 |
154 | #XPath put operator.
155 | def []=( key, val )
156 | @self.put( key, val )
157 | end
158 |
159 | # Here's where all the fun's at!
160 | # It's more complicated then it looks ;-)
161 | def method_missing( sym, *args )
162 | sym = sym.to_s
163 | if sym.slice(-1) == '='
164 | self["#{sym.pop}"] = args[0]
165 | else
166 | self["#{sym}"]
167 | end
168 | end
169 |
170 | end
171 |
172 | #
173 | # XmlList
174 | #
175 | class XmlList
176 |
177 | class << self
178 | alias_method( :__new, :new )
179 | def new( xd=[], to=nil, tp=nil )
180 | case xd
181 | when XmlList
182 | xd
183 | else
184 | __new( xd, to, tp )
185 | end
186 | end
187 | end
188 |
189 | def initialize( xd=[], to=nil, tp=nil )
190 | @self = XmlListDelegate.new(self)
191 | case xd
192 | when []
193 | @list = []
194 | @target_object = to
195 | @target_property = tp
196 | when Xml
197 | @list = [xd]
198 | @target_object = xd.self.parent
199 | @target_property = xd.self.name
200 | else
201 | xd = REXML::Document.new(%{<_>#{xd}}).root
202 | a = []; xd.each{ |n| a << Xml.new(n) }
203 | @list = a
204 | @target_object = nil
205 | @target_property = nil
206 | end
207 | end
208 |
209 | # This is how to access the underlying Xml object, i.e. via the delegate.
210 | def self ; @self ; end
211 |
212 | # This is how the delegate accesses the node.
213 | def __list ; @list ; end
214 |
215 | # This is how the delegate accesses the node classification.
216 | def __class ; :xmllist ; end
217 |
218 | # This is how the delegate accesses the node classification.
219 | def __target_object ; @target_object ; end
220 | def __target_object=(to) ; @target_object = to ; end
221 |
222 | # This is how the delegate accesses the node classification.
223 | def __target_property ; @target_property ; end
224 | def __target_property=(tp) ; @target_property = tp ; end
225 |
226 | # Important for this to work in string interpolation.
227 | def to_s() @list.to_s ; end
228 |
229 | # ?
230 | def to_i() @list.to_s.to_i; end
231 |
232 | # each
233 | def each(&blk) ; @list.each(&blk) ; end
234 |
235 | # Shortcut for add.
236 | def <<( n )
237 | @self.add( n )
238 | end
239 |
240 | # XPath for all elements.
241 | def * ; @self.get('*') ; end
242 |
243 | # Shortcut for XPath '@*', meaning all attributes.
244 | def _ ; @self.get('@*') ; end
245 |
246 | def []( v )
247 | @self.get( v )
248 | end
249 |
250 | def []=( prop, v )
251 | @self.put( prop , v )
252 | end
253 |
254 | #
255 | def method_missing( sym, *args )
256 | sym = sym.to_s
257 | p sym
258 | if (args.size > 0)
259 | self[0].send( sym, args )
260 | else
261 | self[0].send( sym )
262 | end
263 | end
264 |
265 | end
266 |
267 |
268 |
269 | # test
270 | if $0 == __FILE__
271 |
272 | XmlList.new('abc 123')
273 |
274 | x = xml %Q{
275 |
276 |
277 |
278 | Tom
279 | ...
280 | 123
281 |
282 | 35
283 |
284 |
285 | Becky
286 | 32
287 |
288 |
289 | }
290 |
291 | puts x.*
292 | puts x._
293 |
294 | puts x.self.name
295 | puts x.self.attributes
296 |
297 | puts x.person
298 | puts x['person']
299 | puts x._id
300 | puts x['@id']
301 | p x
302 | puts x[1] # skip whatespace?
303 | puts "HERE"
304 | x << xml(%{Timmy})
305 |
306 | puts x['@*']
307 |
308 | end
309 |
310 |
311 |
312 | # SCRAP
313 |
314 | # def __verb?(str)
315 | # str = str.strip
316 | # return nil unless __tag?(str)
317 | # md = (%r{\A \< (\w+) (.*?) \>}mix).match( str )
318 | # p md
319 | # return nil unless md[2] =~ %r{xml:cdata=['"]\d+['"]}
320 | # ed = (%r{\< \/ #{n} [ ]* \> \Z}mix).match(str)
321 | # return nil unless ed
322 | # c = md[0] + '' + ed[0]
323 | # p c
324 | # c
325 | # #str = str.sub( %r{\A \< (\w+) .*? \>}mix ) { |m| n=$1 ; "#{m} \Z}mix ) { |m| "]]>#{m}" }
327 | # # n << md.post_match.gsub(%r{\< \/ #{md[1]} [ ]* \> \Z}mix, '') #[0...(md.post_match.rindex('<'))] # not robust enough
328 | # # n << "]]>"
329 | # # n << "#{md[1]}>"
330 | # end
331 |
--------------------------------------------------------------------------------
/work/r4x2.rb:
--------------------------------------------------------------------------------
1 | require 'facet/string/shatter'
2 | require 'facet/string/dequote'
3 |
4 |
5 | def xml( x )
6 | R4X::Xml.newq( x )
7 | end
8 |
9 |
10 | module R4X
11 |
12 | START_TAG_RE = %r{\A \< (\w+) (.*?) \>}mix
13 |
14 | # This is used it identify strings that conform to canonical XML element text.
15 | # It could afford to be made alittle more robust.
16 | #
17 | module XmlCanonical
18 | def self.===( sa )
19 | #sa = sa.join('') if Array === sa
20 | str = sa.to_s #.strip
21 | stag = (%r{\A \< (\w+) (.*?) (\/)? \>}mix).match( str )
22 | return false unless stag
23 | return true if stag[3] # non-content
24 | etag = (%r{\< \/ #{stag[1]} [ ]* \> \Z}mix).match(str)
25 | return false unless etag
26 | true
27 | end
28 | end
29 |
30 | # Common routine
31 | define_method :get_namespace { |prefix|
32 |
33 | }
34 |
35 | #
36 | # QName
37 | #
38 |
39 | QName = Class.new {
40 |
41 | attr :name
42 | attr :namespace
43 | attr :prefix
44 |
45 | class << self
46 | def newq( unqualified_name )
47 | name, prefix = *unqualified_name.split(':').reverse
48 | new( name, prefix )
49 | end
50 | end
51 |
52 | define_method :initialize { |name, prefix|
53 | @name = name
54 | @prefix = prefix
55 | @namesapce = get_namespace( prefix )
56 | end
57 |
58 | def to_s
59 | return "#{@prefix}:#{@name}" if @prefix
60 | @name
61 | end
62 |
63 | }
64 |
65 |
66 | #
67 | # XmlTag
68 | #
69 | class XmlTag
70 | attr :name # QName
71 | attr :attributes # Hash { QName => String, ... }
72 |
73 | class << self
74 | def newq( name, attributes={} )
75 | new( QName.newq( name ), attributes )
76 | end
77 | end
78 |
79 | def initialize( name, attributes={} )
80 | @name = name.to_s
81 | @attributes = attributes
82 | end
83 |
84 | def to_s
85 | "#{@name}"
86 | end
87 | end
88 |
89 |
90 | class XmlList
91 | attr :list # Array [ Xml ; String , ... ]
92 |
93 | include Enumerable
94 |
95 | def initialize( list )
96 | @list = list
97 | end
98 |
99 | def each ; @list.each { |e| yield e } ; end
100 | def size ; @list.size ; end
101 | def at(*args) ; @list.at(*args) ; end
102 |
103 | def children ; @list ; end
104 |
105 | def elements
106 | return [] if @list.size == 0
107 | if @list.size == 1
108 | l = @list[0]
109 | else
110 | l = @list
111 | end
112 | l.select { |e| Xml === e }
113 | end
114 |
115 | # The clever query
116 | def [](q)
117 | case q
118 | when Integer
119 | return list.at(q)
120 | when '*'
121 | return elements
122 | when '@*'
123 | return attributes
124 | when /^@/
125 | return attributes.fetch(q)
126 | when /\:/
127 | return elements.select { |e| e.name == q }
128 | else
129 | return elements.select { |e| e.local_name == q }
130 | end
131 | end
132 |
133 | # The clever updater/inserter
134 | def []=(q,v)
135 | r = self[q]
136 | case r.size
137 | when 0
138 | @list << v.to_s
139 | when 1
140 | case q
141 | when Integer
142 | list.store(q,v)
143 | when '*'
144 | raise "not implemented"
145 | when '@*'
146 | raise "not implemented"
147 | when /^@/
148 | attributes[q] = v
149 | else
150 | r[0].replace( v )
151 | end
152 | else
153 | # more than one match
154 | return nil #?
155 | end
156 | end
157 |
158 | #def method_missing( sym, *args )
159 | # at(0).send( sym, *args )
160 | #end
161 | end
162 |
163 | #
164 | # Xml
165 | #
166 | class Xml < XmlList
167 | attr :tag # XmlTag
168 | #attr :list # Array [ Xml ; String , ... ]
169 |
170 | class << self
171 | def newq( str_or_arr )
172 | #a = ( String === str_or_arr ? parse(str_or_arr) : str_or_arr )
173 | a = ( Array === str_or_arr ? str_or_arr : parse(str_or_arr) )
174 |
175 | r = a.collect do |e|
176 | case e
177 | when Array
178 | if ::XmlCanonical === e.join('')
179 | tag = XmlTag.newq( name( e[0] ), attributes( e[0] ) )
180 | list = ( e.size > 1 ? xml( e[1...-1] ) : nil )
181 | Xml.new( tag, list )
182 | else
183 | xml( e )
184 | end
185 | else
186 | e # String === e
187 | end
188 | end
189 |
190 | if XmlCanonical === str_or_arr
191 | tag = XmlTag.newq( name( r[0] ), attributes( r[0] ) )
192 | list = ( r.size > 1 ? xml( r[1...-1] ) : nil )
193 | Xml.new( tag, list )
194 | else
195 | XmlList.new( r )
196 | end
197 | end
198 |
199 | def name( e0 )
200 | START_TAG_RE.match(e0)[1]
201 | end
202 |
203 | def attributes( e0 )
204 | s = START_TAG_RE.match( e0 )[2].strip
205 | a = s.split( %r{\s+|\=}x ).collect { |e| e.dequote }
206 | return Hash[ *a ]
207 | end
208 | end
209 |
210 | #
211 | def initialize( tag, list )
212 | @tag = tag
213 | super( list )
214 | end
215 |
216 | def name() @tag.to_s ; end
217 | def local_name() @tag.name ; end
218 | def attributes() @tag.attributes ; end
219 |
220 | def inspect
221 | "<#{tag}> ... >"
222 | end
223 |
224 | def to_s
225 | attrs = attributes.collect{ |k,v| "#{k}=#{v}" }.join(' ')
226 | attrs = " #{attrs}" unless attrs.empty?
227 |
228 | lstr = @list.collect { |e|
229 | case e
230 | when Xml
231 | e.to_s
232 | when Array
233 | e.collect { |ee| ee.to_s }.join('')
234 | else
235 | e.to_s
236 | end
237 | }.join('')
238 |
239 | %{<#{tag.name}#{attrs}>#{lstr}#{tag.name}>}
240 | end
241 |
242 | def replace( x )
243 | @list = [ x.to_s ]
244 | end
245 |
246 | end
247 |
248 | #
249 | # XmlInstruction
250 | #
251 | class XmlInstruction
252 | def initialize(name, data)
253 | end
254 | end
255 |
256 | #
257 | # XmlComment
258 | #
259 | class XmlComment
260 | def initialize(comment)
261 | end
262 | end
263 |
264 |
265 | #
266 | # R4X Parser
267 | #
268 |
269 | RETAG = %r{ \< (\/)? ([\w.:]+) (.*?) ([/])? \> }mix
270 | IDXEND = 1
271 | IDXNAME = 2
272 | IDXATTR = 3
273 | IDXUNIT = 4
274 |
275 | #module_function
276 |
277 | def parse(xmldata)
278 | if String === xmldata
279 | q = xmldata.strip.shatter(RETAG)
280 | else
281 | q = xmldata.dup
282 | end
283 | # setup
284 | build = []
285 | current = build
286 | stack = []
287 | # stack loop
288 | until q.empty?
289 | e = q.shift
290 | if md = RETAG.match( e )
291 | if md[IDXEND]
292 | #close-tag
293 | current << e
294 | current = stack.pop
295 | elsif md[IDXUNIT] == '/'
296 | #unit-tag
297 | current << e
298 | else
299 | #open-tag
300 | stack << current
301 | current << []
302 | current = current.last
303 | current << e
304 | end
305 | else
306 | current << e #if e != "\n"
307 | end
308 | end
309 | return build
310 | end
311 |
312 | end
313 |
314 |
315 | include R4X
316 |
317 | q = %{
318 |
319 |
320 | 2004-12-18
321 | Santa
322 | 0.32
323 | 2.45
324 |
325 |
326 | 2003-12-18
327 | Bunny
328 | 0.32
329 | 1.20
330 |
331 |
332 | }
333 |
334 | x = xml( q )
335 |
336 | puts
337 | puts x
338 |
339 | puts x['stamp']
340 | puts
341 | puts x['stamp'][0]['issued']
342 | puts
343 | x['stamp'][0]['issued'] = "2000-01-01"
344 | puts x['stamp'][0]['issued']
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 | # #
372 | # # XmlList
373 | # #
374 | # class XmlList
375 | #
376 | # class << self
377 | # alias_method :__new, :new
378 | # def new( xa )
379 | # XmlList === xa ? xa : __new( xa )
380 | # end
381 | # end
382 | #
383 | # def initialize( list )
384 | # @list = list
385 | # end
386 | #
387 | # def [](q)
388 | # case @list.size
389 | # when 0
390 | # []
391 | # when 1
392 | # @list.at(0)[q]
393 | # else
394 | # case q
395 | # when Integer
396 | # @list[q]
397 | # when String
398 | # XmlList.new( @list.collect { |e| e[q] } )
399 | # end
400 | # end
401 | # end
402 | #
403 | # def []=( q, v )
404 | # r = self[q]
405 | # p r
406 | # case r.size
407 | # when 1
408 | # p r
409 | # end
410 | # end
411 | #
412 | # def select( &blk )
413 | # XmlList.new( @list.select( &blk ) )
414 | # end
415 | #
416 | # def to_s
417 | # @list.collect { |e| e.to_s }.join("\n")
418 | # end
419 | #
420 | # def method_missing( meth, *args )
421 | # @list.send( meth, *args )
422 | # end
423 | #
424 | # end
425 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | .
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
204 |
205 |
--------------------------------------------------------------------------------