tokamak 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +27 -0
  4. data/Gemfile.lock +77 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +69 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/lib/tokamak.rb +21 -0
  10. data/lib/tokamak/atom.rb +8 -0
  11. data/lib/tokamak/atom/base.rb +87 -0
  12. data/lib/tokamak/atom/builder.rb +107 -0
  13. data/lib/tokamak/atom/helpers.rb +13 -0
  14. data/lib/tokamak/error.rb +6 -0
  15. data/lib/tokamak/json.rb +10 -0
  16. data/lib/tokamak/json/base.rb +83 -0
  17. data/lib/tokamak/json/builder.rb +98 -0
  18. data/lib/tokamak/json/helpers.rb +13 -0
  19. data/lib/tokamak/representation.rb +3 -0
  20. data/lib/tokamak/representation/atom.rb +18 -0
  21. data/lib/tokamak/representation/atom/atom.rng +597 -0
  22. data/lib/tokamak/representation/atom/base.rb +140 -0
  23. data/lib/tokamak/representation/atom/category.rb +39 -0
  24. data/lib/tokamak/representation/atom/entry.rb +56 -0
  25. data/lib/tokamak/representation/atom/factory.rb +48 -0
  26. data/lib/tokamak/representation/atom/feed.rb +108 -0
  27. data/lib/tokamak/representation/atom/link.rb +66 -0
  28. data/lib/tokamak/representation/atom/person.rb +46 -0
  29. data/lib/tokamak/representation/atom/source.rb +57 -0
  30. data/lib/tokamak/representation/atom/tag_collection.rb +36 -0
  31. data/lib/tokamak/representation/atom/xml.rb +94 -0
  32. data/lib/tokamak/representation/generic.rb +20 -0
  33. data/lib/tokamak/representation/json.rb +11 -0
  34. data/lib/tokamak/representation/json/base.rb +25 -0
  35. data/lib/tokamak/representation/json/keys_as_methods.rb +72 -0
  36. data/lib/tokamak/representation/json/link.rb +27 -0
  37. data/lib/tokamak/representation/json/link_collection.rb +21 -0
  38. data/lib/tokamak/representation/links.rb +9 -0
  39. data/lib/tokamak/values.rb +29 -0
  40. data/lib/tokamak/xml.rb +12 -0
  41. data/lib/tokamak/xml/base.rb +60 -0
  42. data/lib/tokamak/xml/builder.rb +115 -0
  43. data/lib/tokamak/xml/helpers.rb +13 -0
  44. data/lib/tokamak/xml/link.rb +31 -0
  45. data/lib/tokamak/xml/links.rb +35 -0
  46. data/spec/integration/atom/atom_spec.rb +191 -0
  47. data/spec/integration/full_atom.xml +92 -0
  48. data/spec/integration/full_json.js +46 -0
  49. data/spec/integration/json/json_spec.rb +172 -0
  50. data/spec/integration/xml/xml_spec.rb +203 -0
  51. data/spec/spec_helper.rb +12 -0
  52. metadata +248 -0
@@ -0,0 +1,13 @@
1
+ module Tokamak
2
+ module Atom
3
+ module Helpers
4
+ def collection(obj, *args, &block)
5
+ Tokamak::Atom.to_atom(obj, :atom_type => :feed, &block)
6
+ end
7
+
8
+ def member(obj, *args, &block)
9
+ Tokamak::Atom.to_atom(obj, :atom_type => :entry, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module Tokamak
2
+ class Error < StandardError
3
+ end
4
+ class ConverterError < Error
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'json'
2
+
3
+ module Tokamak
4
+ module Json
5
+ autoload :Base, 'tokamak/json/base'
6
+ autoload :Builder, 'tokamak/json/builder'
7
+ autoload :Helpers, 'tokamak/json/helpers'
8
+ extend Base::ClassMethods
9
+ end
10
+ end
@@ -0,0 +1,83 @@
1
+ module Tokamak
2
+ module Json
3
+ module Base
4
+ module ClassMethods
5
+ mattr_reader :media_type_name
6
+ @@media_type_name = 'application/json'
7
+
8
+ mattr_reader :headers
9
+ @@headers = {
10
+ :get => { 'Accept' => media_type_name },
11
+ :post => { 'Content-Type' => media_type_name }
12
+ }
13
+
14
+ mattr_reader :recipes
15
+ @@recipes = {}
16
+
17
+ def describe_recipe(recipe_name, options={}, &block)
18
+ raise 'Undefined recipe' unless block_given?
19
+ raise 'Undefined recipe_name' unless recipe_name
20
+ @@recipes[recipe_name] = block
21
+ end
22
+
23
+ def to_json(obj = nil, options = {:root => {}}, &block)
24
+ # just instantiate the string with the atom factory
25
+ return Tokamak::Representation::Json.create(obj) if obj.kind_of?(String)
26
+
27
+ if block_given?
28
+ recipe = block
29
+ else
30
+ recipe = options[:recipe]
31
+ end
32
+
33
+ # Check if the object is already an json
34
+ unless recipe
35
+ if obj.kind_of?(Hash) || obj.kind_of?(Array)
36
+ return Tokamak::Representation::Json.create(obj)
37
+ else
38
+ raise Tokamak::ConverterError.new("Recipe required")
39
+ end
40
+ end
41
+
42
+ # Get recipe already described
43
+ recipe = @@recipes[recipe] unless recipe.respond_to?(:call)
44
+
45
+ # Create representation and proxy
46
+ builder = Tokamak::Json::Builder.new(obj, (options[:root] || {}))
47
+
48
+ # Check recipe arity size before calling it
49
+ recipe.call(*[builder, obj, options][0,recipe.arity])
50
+
51
+ builder.representation
52
+ end
53
+
54
+ alias_method :unmarshal, :to_json
55
+
56
+ def to_hash(obj)
57
+ return obj if obj.kind_of?(Hash) || obj.kind_of?(Array)
58
+
59
+ if obj.kind_of?(::String)
60
+ Tokamak::Representation::Json.create(obj)
61
+ else
62
+ raise Tokamak::ConverterError.new("It was not possible to convert this object to a Hash")
63
+ end
64
+ end
65
+
66
+ def to_s(obj)
67
+ return obj if obj.kind_of?(String)
68
+ Tokamak::Representation::Json.create(obj).to_s
69
+ end
70
+
71
+ def marshal(obj, options = nil)
72
+ return obj if obj.kind_of? String
73
+ to_json(obj, options).to_json
74
+ end
75
+
76
+ # returns the current helper
77
+ def helper
78
+ Helpers
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,98 @@
1
+ module Tokamak
2
+ module Json
3
+ class Builder
4
+ def initialize(obj, initial_obj = {})
5
+ @doc = initial_obj
6
+ @obj = obj
7
+ @current = @doc
8
+ end
9
+
10
+ def values(options = nil, &block)
11
+ yield Values.new(self)
12
+ end
13
+
14
+ def members(options = {}, &block)
15
+ collection = options[:collection] || @obj
16
+ raise Error::BuilderError.new("Members method require a collection to execute") unless collection.respond_to?(:each)
17
+ root = options[:root] || Tokamak.root_element_for(collection)
18
+
19
+ collection.each do |member|
20
+ node = {}
21
+
22
+ parent = @current
23
+ @current = node
24
+ block.call(self, member)
25
+ @current = parent
26
+
27
+ add_to_current(root, node)
28
+ end
29
+ end
30
+
31
+ def link(relationship, uri, options = {})
32
+ options["rel"] = relationship.to_s
33
+ options["href"] = uri
34
+ options["type"] ||= "application/json"
35
+ insert_value("link", nil, options)
36
+ end
37
+
38
+ def insert_value(name, prefix, *args, &block)
39
+ node = create_element(block_given?, *args)
40
+
41
+ if block_given?
42
+ parent = @current
43
+ @current = node
44
+ block.call
45
+ @current = parent
46
+ end
47
+
48
+ add_to_current(name, node)
49
+ end
50
+
51
+ def representation
52
+ Tokamak::Representation::Json.create(@doc).to_json
53
+ end
54
+
55
+ private
56
+
57
+ def create_element(has_block, *args)
58
+ vals = []
59
+ hashes = []
60
+
61
+ args.each do |arg|
62
+ arg.kind_of?(Hash) ? hashes << arg : vals << arg
63
+ end
64
+
65
+ if hashes.empty?
66
+ # only simple values
67
+ unless vals.empty?
68
+ vals = vals.first if vals.size == 1
69
+ node = has_block ? {} : vals
70
+ else
71
+ node = has_block ? {} : nil
72
+ end
73
+ else
74
+ # yes we have hashes
75
+ node = {}
76
+ hashes.each { |hash| node.merge!(hash) }
77
+ unless vals.empty?
78
+ vals = vals.first if vals.size == 1
79
+ node = has_block ? {} : [node, vals]
80
+ end
81
+ node
82
+ end
83
+ end
84
+
85
+ def add_to_current(name, value)
86
+ if @current[name]
87
+ if @current[name].kind_of?(Array)
88
+ @current[name] << value
89
+ else
90
+ @current[name] = [@current[name], value]
91
+ end
92
+ else
93
+ @current[name] = value
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,13 @@
1
+ module Tokamak
2
+ module Json
3
+ module Helpers
4
+ def collection(obj, *args, &block)
5
+ Tokamak::Json.to_json(obj, &block)
6
+ end
7
+
8
+ def member(obj, *args, &block)
9
+ Tokamak::Json.to_json(obj, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Tokamak::Representation
2
+ Dir["#{File.dirname(__FILE__)}/representation/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'nokogiri'
2
+
3
+ module Tokamak
4
+ module Representation
5
+ module Atom
6
+ autoload :Factory, 'tokamak/representation/atom/factory'
7
+ autoload :XML, 'tokamak/representation/atom/xml'
8
+ autoload :Base, 'tokamak/representation/atom/base'
9
+ autoload :TagCollection, 'tokamak/representation/atom/tag_collection'
10
+ autoload :Link, 'tokamak/representation/atom/link'
11
+ autoload :Person, 'tokamak/representation/atom/person'
12
+ autoload :Category, 'tokamak/representation/atom/category'
13
+ autoload :Feed, 'tokamak/representation/atom/feed'
14
+ autoload :Entry, 'tokamak/representation/atom/entry'
15
+ autoload :Source, 'tokamak/representation/atom/source'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,597 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ -*- rnc -*-
4
+ RELAX NG Compact Syntax Grammar for the
5
+ Atom Format Specification Version 11
6
+ -->
7
+ <grammar xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:s="http://www.ascc.net/xml/schematron" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
8
+ <start>
9
+ <choice>
10
+ <ref name="atomFeed"/>
11
+ <ref name="atomEntry"/>
12
+ </choice>
13
+ </start>
14
+ <!-- Common attributes -->
15
+ <define name="atomCommonAttributes">
16
+ <optional>
17
+ <attribute name="xml:base">
18
+ <ref name="atomUri"/>
19
+ </attribute>
20
+ </optional>
21
+ <optional>
22
+ <attribute name="xml:lang">
23
+ <ref name="atomLanguageTag"/>
24
+ </attribute>
25
+ </optional>
26
+ <zeroOrMore>
27
+ <ref name="undefinedAttribute"/>
28
+ </zeroOrMore>
29
+ </define>
30
+ <!-- Text Constructs -->
31
+ <define name="atomPlainTextConstruct">
32
+ <ref name="atomCommonAttributes"/>
33
+ <optional>
34
+ <attribute name="type">
35
+ <choice>
36
+ <value>text</value>
37
+ <value>html</value>
38
+ </choice>
39
+ </attribute>
40
+ </optional>
41
+ <text/>
42
+ </define>
43
+ <define name="atomXHTMLTextConstruct">
44
+ <ref name="atomCommonAttributes"/>
45
+ <attribute name="type">
46
+ <value>xhtml</value>
47
+ </attribute>
48
+ <ref name="xhtmlDiv"/>
49
+ </define>
50
+ <define name="atomTextConstruct">
51
+ <choice>
52
+ <ref name="atomPlainTextConstruct"/>
53
+ <ref name="atomXHTMLTextConstruct"/>
54
+ </choice>
55
+ </define>
56
+ <!-- Person Construct -->
57
+ <define name="atomPersonConstruct">
58
+ <ref name="atomCommonAttributes"/>
59
+ <interleave>
60
+ <element name="atom:name">
61
+ <text/>
62
+ </element>
63
+ <optional>
64
+ <element name="atom:uri">
65
+ <ref name="atomUri"/>
66
+ </element>
67
+ </optional>
68
+ <optional>
69
+ <element name="atom:email">
70
+ <ref name="atomEmailAddress"/>
71
+ </element>
72
+ </optional>
73
+ <zeroOrMore>
74
+ <ref name="extensionElement"/>
75
+ </zeroOrMore>
76
+ </interleave>
77
+ </define>
78
+ <!-- Date Construct -->
79
+ <define name="atomDateConstruct">
80
+ <ref name="atomCommonAttributes"/>
81
+ <data type="dateTime"/>
82
+ </define>
83
+ <!-- atom:feed -->
84
+ <define name="atomFeed">
85
+ <element name="atom:feed">
86
+ <s:rule context="atom:feed">
87
+ <s:assert test="atom:author or not(atom:entry[not(atom:author)])">An atom:feed must have an atom:author unless all of its atom:entry children have an atom:author.</s:assert>
88
+ </s:rule>
89
+ <ref name="atomCommonAttributes"/>
90
+ <interleave>
91
+ <zeroOrMore>
92
+ <ref name="atomAuthor"/>
93
+ </zeroOrMore>
94
+ <zeroOrMore>
95
+ <ref name="atomCategory"/>
96
+ </zeroOrMore>
97
+ <zeroOrMore>
98
+ <ref name="atomContributor"/>
99
+ </zeroOrMore>
100
+ <optional>
101
+ <ref name="atomGenerator"/>
102
+ </optional>
103
+ <optional>
104
+ <ref name="atomIcon"/>
105
+ </optional>
106
+ <ref name="atomId"/>
107
+ <zeroOrMore>
108
+ <ref name="atomLink"/>
109
+ </zeroOrMore>
110
+ <optional>
111
+ <ref name="atomLogo"/>
112
+ </optional>
113
+ <optional>
114
+ <ref name="atomRights"/>
115
+ </optional>
116
+ <optional>
117
+ <ref name="atomSubtitle"/>
118
+ </optional>
119
+ <ref name="atomTitle"/>
120
+ <ref name="atomUpdated"/>
121
+ <zeroOrMore>
122
+ <ref name="extensionElement"/>
123
+ </zeroOrMore>
124
+ </interleave>
125
+ <zeroOrMore>
126
+ <ref name="atomEntry"/>
127
+ </zeroOrMore>
128
+ </element>
129
+ </define>
130
+ <!-- atom:entry -->
131
+ <define name="atomEntry">
132
+ <element name="atom:entry">
133
+ <s:rule context="atom:entry">
134
+ <s:assert test="atom:link[@rel='alternate'] or atom:link[not(@rel)] or atom:content">An atom:entry must have at least one atom:link element with a rel attribute of 'alternate' or an atom:content.</s:assert>
135
+ </s:rule>
136
+ <s:rule context="atom:entry">
137
+ <s:assert test="atom:author or ../atom:author or atom:source/atom:author">An atom:entry must have an atom:author if its feed does not.</s:assert>
138
+ </s:rule>
139
+ <ref name="atomCommonAttributes"/>
140
+ <interleave>
141
+ <zeroOrMore>
142
+ <ref name="atomAuthor"/>
143
+ </zeroOrMore>
144
+ <zeroOrMore>
145
+ <ref name="atomCategory"/>
146
+ </zeroOrMore>
147
+ <optional>
148
+ <ref name="atomContent"/>
149
+ </optional>
150
+ <zeroOrMore>
151
+ <ref name="atomContributor"/>
152
+ </zeroOrMore>
153
+ <ref name="atomId"/>
154
+ <zeroOrMore>
155
+ <ref name="atomLink"/>
156
+ </zeroOrMore>
157
+ <optional>
158
+ <ref name="atomPublished"/>
159
+ </optional>
160
+ <optional>
161
+ <ref name="atomRights"/>
162
+ </optional>
163
+ <optional>
164
+ <ref name="atomSource"/>
165
+ </optional>
166
+ <optional>
167
+ <ref name="atomSummary"/>
168
+ </optional>
169
+ <ref name="atomTitle"/>
170
+ <ref name="atomUpdated"/>
171
+ <zeroOrMore>
172
+ <ref name="extensionElement"/>
173
+ </zeroOrMore>
174
+ </interleave>
175
+ </element>
176
+ </define>
177
+ <!-- atom:content -->
178
+ <define name="atomInlineTextContent">
179
+ <element name="atom:content">
180
+ <ref name="atomCommonAttributes"/>
181
+ <optional>
182
+ <attribute name="type">
183
+ <choice>
184
+ <value>text</value>
185
+ <value>html</value>
186
+ </choice>
187
+ </attribute>
188
+ </optional>
189
+ <zeroOrMore>
190
+ <text/>
191
+ </zeroOrMore>
192
+ </element>
193
+ </define>
194
+ <define name="atomInlineXHTMLContent">
195
+ <element name="atom:content">
196
+ <ref name="atomCommonAttributes"/>
197
+ <attribute name="type">
198
+ <value>xhtml</value>
199
+ </attribute>
200
+ <ref name="xhtmlDiv"/>
201
+ </element>
202
+ </define>
203
+ <define name="atomInlineOtherContent">
204
+ <element name="atom:content">
205
+ <ref name="atomCommonAttributes"/>
206
+ <optional>
207
+ <attribute name="type">
208
+ <ref name="atomMediaType"/>
209
+ </attribute>
210
+ </optional>
211
+ <zeroOrMore>
212
+ <choice>
213
+ <text/>
214
+ <ref name="anyElement"/>
215
+ </choice>
216
+ </zeroOrMore>
217
+ </element>
218
+ </define>
219
+ <define name="atomOutOfLineContent">
220
+ <element name="atom:content">
221
+ <ref name="atomCommonAttributes"/>
222
+ <optional>
223
+ <attribute name="type">
224
+ <ref name="atomMediaType"/>
225
+ </attribute>
226
+ </optional>
227
+ <attribute name="src">
228
+ <ref name="atomUri"/>
229
+ </attribute>
230
+ <empty/>
231
+ </element>
232
+ </define>
233
+ <define name="atomContent">
234
+ <choice>
235
+ <ref name="atomInlineTextContent"/>
236
+ <ref name="atomInlineXHTMLContent"/>
237
+ <ref name="atomInlineOtherContent"/>
238
+ <ref name="atomOutOfLineContent"/>
239
+ </choice>
240
+ </define>
241
+ <!-- atom:author -->
242
+ <define name="atomAuthor">
243
+ <element name="atom:author">
244
+ <ref name="atomPersonConstruct"/>
245
+ </element>
246
+ </define>
247
+ <!-- atom:category -->
248
+ <define name="atomCategory">
249
+ <element name="atom:category">
250
+ <ref name="atomCommonAttributes"/>
251
+ <attribute name="term"/>
252
+ <optional>
253
+ <attribute name="scheme">
254
+ <ref name="atomUri"/>
255
+ </attribute>
256
+ </optional>
257
+ <optional>
258
+ <attribute name="label"/>
259
+ </optional>
260
+ <ref name="undefinedContent"/>
261
+ </element>
262
+ </define>
263
+ <!-- atom:contributor -->
264
+ <define name="atomContributor">
265
+ <element name="atom:contributor">
266
+ <ref name="atomPersonConstruct"/>
267
+ </element>
268
+ </define>
269
+ <!-- atom:generator -->
270
+ <define name="atomGenerator">
271
+ <element name="atom:generator">
272
+ <ref name="atomCommonAttributes"/>
273
+ <optional>
274
+ <attribute name="uri">
275
+ <ref name="atomUri"/>
276
+ </attribute>
277
+ </optional>
278
+ <optional>
279
+ <attribute name="version"/>
280
+ </optional>
281
+ <text/>
282
+ </element>
283
+ </define>
284
+ <!-- atom:icon -->
285
+ <define name="atomIcon">
286
+ <element name="atom:icon">
287
+ <ref name="atomCommonAttributes"/>
288
+ <ref name="atomUri"/>
289
+ </element>
290
+ </define>
291
+ <!-- atom:id -->
292
+ <define name="atomId">
293
+ <element name="atom:id">
294
+ <ref name="atomCommonAttributes"/>
295
+ <ref name="atomUri"/>
296
+ </element>
297
+ </define>
298
+ <!-- atom:logo -->
299
+ <define name="atomLogo">
300
+ <element name="atom:logo">
301
+ <ref name="atomCommonAttributes"/>
302
+ <ref name="atomUri"/>
303
+ </element>
304
+ </define>
305
+ <!-- atom:link -->
306
+ <define name="atomLink">
307
+ <element name="atom:link">
308
+ <ref name="atomCommonAttributes"/>
309
+ <attribute name="href">
310
+ <ref name="atomUri"/>
311
+ </attribute>
312
+ <optional>
313
+ <attribute name="rel">
314
+ <choice>
315
+ <ref name="atomNCName"/>
316
+ <ref name="atomUri"/>
317
+ </choice>
318
+ </attribute>
319
+ </optional>
320
+ <optional>
321
+ <attribute name="type">
322
+ <ref name="atomMediaType"/>
323
+ </attribute>
324
+ </optional>
325
+ <optional>
326
+ <attribute name="hreflang">
327
+ <ref name="atomLanguageTag"/>
328
+ </attribute>
329
+ </optional>
330
+ <optional>
331
+ <attribute name="title"/>
332
+ </optional>
333
+ <optional>
334
+ <attribute name="length"/>
335
+ </optional>
336
+ <ref name="undefinedContent"/>
337
+ </element>
338
+ </define>
339
+ <!-- atom:published -->
340
+ <define name="atomPublished">
341
+ <element name="atom:published">
342
+ <ref name="atomDateConstruct"/>
343
+ </element>
344
+ </define>
345
+ <!-- atom:rights -->
346
+ <define name="atomRights">
347
+ <element name="atom:rights">
348
+ <ref name="atomTextConstruct"/>
349
+ </element>
350
+ </define>
351
+ <!-- atom:source -->
352
+ <define name="atomSource">
353
+ <element name="atom:source">
354
+ <ref name="atomCommonAttributes"/>
355
+ <interleave>
356
+ <zeroOrMore>
357
+ <ref name="atomAuthor"/>
358
+ </zeroOrMore>
359
+ <zeroOrMore>
360
+ <ref name="atomCategory"/>
361
+ </zeroOrMore>
362
+ <zeroOrMore>
363
+ <ref name="atomContributor"/>
364
+ </zeroOrMore>
365
+ <optional>
366
+ <ref name="atomGenerator"/>
367
+ </optional>
368
+ <optional>
369
+ <ref name="atomIcon"/>
370
+ </optional>
371
+ <optional>
372
+ <ref name="atomId"/>
373
+ </optional>
374
+ <zeroOrMore>
375
+ <ref name="atomLink"/>
376
+ </zeroOrMore>
377
+ <optional>
378
+ <ref name="atomLogo"/>
379
+ </optional>
380
+ <optional>
381
+ <ref name="atomRights"/>
382
+ </optional>
383
+ <optional>
384
+ <ref name="atomSubtitle"/>
385
+ </optional>
386
+ <optional>
387
+ <ref name="atomTitle"/>
388
+ </optional>
389
+ <optional>
390
+ <ref name="atomUpdated"/>
391
+ </optional>
392
+ <zeroOrMore>
393
+ <ref name="extensionElement"/>
394
+ </zeroOrMore>
395
+ </interleave>
396
+ </element>
397
+ </define>
398
+ <!-- atom:subtitle -->
399
+ <define name="atomSubtitle">
400
+ <element name="atom:subtitle">
401
+ <ref name="atomTextConstruct"/>
402
+ </element>
403
+ </define>
404
+ <!-- atom:summary -->
405
+ <define name="atomSummary">
406
+ <element name="atom:summary">
407
+ <ref name="atomTextConstruct"/>
408
+ </element>
409
+ </define>
410
+ <!-- atom:title -->
411
+ <define name="atomTitle">
412
+ <element name="atom:title">
413
+ <ref name="atomTextConstruct"/>
414
+ </element>
415
+ </define>
416
+ <!-- atom:updated -->
417
+ <define name="atomUpdated">
418
+ <element name="atom:updated">
419
+ <ref name="atomDateConstruct"/>
420
+ </element>
421
+ </define>
422
+ <!-- Low-level simple types -->
423
+ <define name="atomNCName">
424
+ <data type="string">
425
+ <param name="minLength">1</param>
426
+ <param name="pattern">[^:]*</param>
427
+ </data>
428
+ </define>
429
+ <!-- Whatever a media type is, it contains at least one slash -->
430
+ <define name="atomMediaType">
431
+ <data type="string">
432
+ <param name="pattern">.+/.+</param>
433
+ </data>
434
+ </define>
435
+ <!-- As defined in RFC 3066 -->
436
+ <define name="atomLanguageTag">
437
+ <data type="string">
438
+ <param name="pattern">[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*</param>
439
+ </data>
440
+ </define>
441
+ <!--
442
+ Unconstrained; it's not entirely clear how IRI fit into
443
+ xsd:anyURI so let's not try to constrain it here
444
+ -->
445
+ <define name="atomUri">
446
+ <text/>
447
+ </define>
448
+ <!-- Whatever an email address is, it contains at least one @ -->
449
+ <define name="atomEmailAddress">
450
+ <data type="string">
451
+ <param name="pattern">.+@.+</param>
452
+ </data>
453
+ </define>
454
+ <!-- Simple Extension -->
455
+ <define name="simpleExtensionElement">
456
+ <element>
457
+ <anyName>
458
+ <except>
459
+ <nsName ns="http://www.w3.org/2005/Atom"/>
460
+ </except>
461
+ </anyName>
462
+ <text/>
463
+ </element>
464
+ </define>
465
+ <!-- Structured Extension -->
466
+ <define name="structuredExtensionElement">
467
+ <element>
468
+ <anyName>
469
+ <except>
470
+ <nsName ns="http://www.w3.org/2005/Atom"/>
471
+ </except>
472
+ </anyName>
473
+ <choice>
474
+ <group>
475
+ <oneOrMore>
476
+ <attribute>
477
+ <anyName/>
478
+ </attribute>
479
+ </oneOrMore>
480
+ <zeroOrMore>
481
+ <choice>
482
+ <text/>
483
+ <ref name="anyElement"/>
484
+ </choice>
485
+ </zeroOrMore>
486
+ </group>
487
+ <group>
488
+ <zeroOrMore>
489
+ <attribute>
490
+ <anyName/>
491
+ </attribute>
492
+ </zeroOrMore>
493
+ <group>
494
+ <optional>
495
+ <text/>
496
+ </optional>
497
+ <oneOrMore>
498
+ <ref name="anyElement"/>
499
+ </oneOrMore>
500
+ <zeroOrMore>
501
+ <choice>
502
+ <text/>
503
+ <ref name="anyElement"/>
504
+ </choice>
505
+ </zeroOrMore>
506
+ </group>
507
+ </group>
508
+ </choice>
509
+ </element>
510
+ </define>
511
+ <!-- Other Extensibility -->
512
+ <define name="extensionElement">
513
+ <choice>
514
+ <ref name="simpleExtensionElement"/>
515
+ <ref name="structuredExtensionElement"/>
516
+ </choice>
517
+ </define>
518
+ <define name="undefinedAttribute">
519
+ <attribute>
520
+ <anyName>
521
+ <except>
522
+ <name>xml:base</name>
523
+ <name>xml:lang</name>
524
+ <nsName ns=""/>
525
+ </except>
526
+ </anyName>
527
+ </attribute>
528
+ </define>
529
+ <define name="undefinedContent">
530
+ <zeroOrMore>
531
+ <choice>
532
+ <text/>
533
+ <ref name="anyForeignElement"/>
534
+ </choice>
535
+ </zeroOrMore>
536
+ </define>
537
+ <define name="anyElement">
538
+ <element>
539
+ <anyName/>
540
+ <zeroOrMore>
541
+ <choice>
542
+ <attribute>
543
+ <anyName/>
544
+ </attribute>
545
+ <text/>
546
+ <ref name="anyElement"/>
547
+ </choice>
548
+ </zeroOrMore>
549
+ </element>
550
+ </define>
551
+ <define name="anyForeignElement">
552
+ <element>
553
+ <anyName>
554
+ <except>
555
+ <nsName ns="http://www.w3.org/2005/Atom"/>
556
+ </except>
557
+ </anyName>
558
+ <zeroOrMore>
559
+ <choice>
560
+ <attribute>
561
+ <anyName/>
562
+ </attribute>
563
+ <text/>
564
+ <ref name="anyElement"/>
565
+ </choice>
566
+ </zeroOrMore>
567
+ </element>
568
+ </define>
569
+ <!-- XHTML -->
570
+ <define name="anyXHTML">
571
+ <element>
572
+ <nsName ns="http://www.w3.org/1999/xhtml"/>
573
+ <zeroOrMore>
574
+ <choice>
575
+ <attribute>
576
+ <anyName/>
577
+ </attribute>
578
+ <text/>
579
+ <ref name="anyXHTML"/>
580
+ </choice>
581
+ </zeroOrMore>
582
+ </element>
583
+ </define>
584
+ <define name="xhtmlDiv">
585
+ <element name="xhtml:div">
586
+ <zeroOrMore>
587
+ <choice>
588
+ <attribute>
589
+ <anyName/>
590
+ </attribute>
591
+ <text/>
592
+ <ref name="anyXHTML"/>
593
+ </choice>
594
+ </zeroOrMore>
595
+ </element>
596
+ </define>
597
+ </grammar>