ape 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +19 -0
- data/Manifest +45 -0
- data/README +12 -0
- data/ape.gemspec +57 -0
- data/bin/ape_server +28 -0
- data/lib/ape.rb +982 -0
- data/lib/ape/atomURI.rb +73 -0
- data/lib/ape/auth/google_login_credentials.rb +96 -0
- data/lib/ape/auth/wsse_credentials.rb +25 -0
- data/lib/ape/authent.rb +42 -0
- data/lib/ape/categories.rb +95 -0
- data/lib/ape/collection.rb +51 -0
- data/lib/ape/crumbs.rb +39 -0
- data/lib/ape/entry.rb +151 -0
- data/lib/ape/escaper.rb +29 -0
- data/lib/ape/feed.rb +117 -0
- data/lib/ape/handler.rb +34 -0
- data/lib/ape/html.rb +17 -0
- data/lib/ape/invoker.rb +54 -0
- data/lib/ape/invokers/deleter.rb +31 -0
- data/lib/ape/invokers/getter.rb +80 -0
- data/lib/ape/invokers/poster.rb +57 -0
- data/lib/ape/invokers/putter.rb +46 -0
- data/lib/ape/layout/ape.css +56 -0
- data/lib/ape/layout/ape_logo.png +0 -0
- data/lib/ape/layout/index.html +54 -0
- data/lib/ape/layout/info.png +0 -0
- data/lib/ape/names.rb +24 -0
- data/lib/ape/print_writer.rb +21 -0
- data/lib/ape/samples.rb +180 -0
- data/lib/ape/samples/atom_schema.txt +338 -0
- data/lib/ape/samples/basic_entry.eruby +16 -0
- data/lib/ape/samples/categories_schema.txt +69 -0
- data/lib/ape/samples/mini_entry.eruby +8 -0
- data/lib/ape/samples/service_schema.txt +187 -0
- data/lib/ape/samples/unclean_xhtml_entry.eruby +21 -0
- data/lib/ape/server.rb +32 -0
- data/lib/ape/service.rb +12 -0
- data/lib/ape/validator.rb +65 -0
- data/lib/ape/version.rb +9 -0
- data/scripts/go.rb +29 -0
- data/test/test_helper.rb +17 -0
- data/test/unit/authent_test.rb +35 -0
- data/test/unit/invoker_test.rb +25 -0
- data/test/unit/samples_test.rb +36 -0
- metadata +111 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
h2 {
|
2
|
+
color: #086;
|
3
|
+
}
|
4
|
+
|
5
|
+
body {
|
6
|
+
margin-left: 50px;
|
7
|
+
margin-right: 100px;
|
8
|
+
font-family: verdana, arial, sans-serif;
|
9
|
+
}
|
10
|
+
|
11
|
+
.dialog {
|
12
|
+
border-left: 8px solid #eee;
|
13
|
+
}
|
14
|
+
.from {
|
15
|
+
padding: 0 10px 0 10px;
|
16
|
+
background: #ddf;
|
17
|
+
}
|
18
|
+
.to {
|
19
|
+
padding: 0 10px 0 10px;
|
20
|
+
background: #dfd;
|
21
|
+
}
|
22
|
+
.dialab {
|
23
|
+
padding: 3px 10px 3px 0px;
|
24
|
+
background: #eee;
|
25
|
+
}
|
26
|
+
|
27
|
+
a.diaref {
|
28
|
+
text-decoration: none;
|
29
|
+
font-weight: bold;
|
30
|
+
color: #086;
|
31
|
+
}
|
32
|
+
|
33
|
+
span.good {
|
34
|
+
font-size: 125%;
|
35
|
+
color: green;
|
36
|
+
}
|
37
|
+
span.warning {
|
38
|
+
font-size: 125%;
|
39
|
+
font-weight: bold;
|
40
|
+
color: #fa0;
|
41
|
+
}
|
42
|
+
span.error {
|
43
|
+
font-size: 125%;
|
44
|
+
font-weight: bold;
|
45
|
+
color: red;
|
46
|
+
}
|
47
|
+
|
48
|
+
#ape {
|
49
|
+
position: absolute; right: 100px; top: 8px;
|
50
|
+
padding-left: 20px;
|
51
|
+
padding-right: 10px;
|
52
|
+
|
53
|
+
width: 170px;
|
54
|
+
border: 1px solid #086;
|
55
|
+
}
|
56
|
+
|
Binary file
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Atom Protocol Exerciser</title>
|
4
|
+
<link rel='stylesheet' type='text/css' href='/layout/ape.css' />
|
5
|
+
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<img align="right" src="/ape/ape_logo.png" alt="The Ape logo by Greg Borenstein" />
|
9
|
+
<div id="main">
|
10
|
+
<h2>Atom Protocol Exerciser</h2>
|
11
|
+
|
12
|
+
<p>(Only the URI argument is required)</p>
|
13
|
+
<form action="/atompub/go" method="post">
|
14
|
+
<table>
|
15
|
+
<tr>
|
16
|
+
<td align="right">URI:</td>
|
17
|
+
<td align="left"><input name="uri" type="text" size="55" maxlength="255" /></td>
|
18
|
+
</tr>
|
19
|
+
<tr>
|
20
|
+
|
21
|
+
<td align="right">Username:</td>
|
22
|
+
<td align="left"><input name="username" type="text" size="55" maxlength="55" /></td>
|
23
|
+
</tr>
|
24
|
+
<tr>
|
25
|
+
<td align="right">Password:</td>
|
26
|
+
<td align="left"><input name="password" type="password" /></td>
|
27
|
+
</tr>
|
28
|
+
<tr>
|
29
|
+
|
30
|
+
<td></td>
|
31
|
+
<td align="left"><input type="submit" value="Exercise!" /></td>
|
32
|
+
</tr>
|
33
|
+
</table>
|
34
|
+
</form>
|
35
|
+
</div>
|
36
|
+
<!--
|
37
|
+
<div id="ape"><p>(It would be nice if there were a cute picture of an ape
|
38
|
+
here, ideally grooming another ape for fleas and parasites.
|
39
|
+
Got one?)</p></div>
|
40
|
+
-->
|
41
|
+
<hr/>
|
42
|
+
<p>The Ape source code may be found at
|
43
|
+
<a href="http://ape.dev.java.net">ape.dev.java.net</a>. It's a little
|
44
|
+
tricky to get going;
|
45
|
+
until I fix that, see this
|
46
|
+
<a href="http://rollerweblogger.org/roller/entry/atom_protocol_exerciser_ape_setup">discussion by Dave Johnson</a>.</p>
|
47
|
+
|
48
|
+
<hr/>
|
49
|
+
<p>Ape Logo by <a href="http://www.urbanhonking.com/ideasfordozens">Greg
|
50
|
+
Borenstein</a>.</p>
|
51
|
+
</div>
|
52
|
+
</body>
|
53
|
+
</html>
|
54
|
+
|
Binary file
|
data/lib/ape/names.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright © 2006 Sun Microsystems, Inc. All rights reserved
|
2
|
+
# Use is subject to license terms - see file "LICENSE"
|
3
|
+
|
4
|
+
module Ape
|
5
|
+
module Names
|
6
|
+
AtomNamespace = 'http://www.w3.org/2005/Atom' unless defined?(AtomNamespace)
|
7
|
+
AppNamespace = 'http://www.w3.org/2007/app' unless defined?(AppNamespace)
|
8
|
+
DcNamespace = 'http://purl.org/dc/elements/1.1/' unless defined?(DcNamespace)
|
9
|
+
XhtmlNamespace = 'http://www.w3.org/1999/xhtml' unless defined?(XhtmlNamespace)
|
10
|
+
XmlNamespaces = {
|
11
|
+
'app' => AppNamespace,
|
12
|
+
'atom' => AtomNamespace,
|
13
|
+
'dc' => DcNamespace,
|
14
|
+
'xhtml' => XhtmlNamespace
|
15
|
+
} unless defined?(XmlNamespaces)
|
16
|
+
|
17
|
+
AtomMediaType = 'application/atom+xml' unless defined?(AtomMediaType)
|
18
|
+
AtomEntryMediaType = 'application/atom+xml;type=entry' unless defined?(AtomEntryMediaType)
|
19
|
+
AppMediaType = 'application/atomsvc+xml' unless defined?(AppMediaType)
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright © 2006 Sun Microsystems, Inc. All rights reserved
|
2
|
+
# Use is subject to license terms - see file "LICENSE"
|
3
|
+
|
4
|
+
# this is a wrapper for the weird derived-from-PrintWriter class that comes
|
5
|
+
# out of HttpResponse.getWriter
|
6
|
+
|
7
|
+
module Ape
|
8
|
+
class Printwriter
|
9
|
+
def initialize(java_writer)
|
10
|
+
@w = java_writer
|
11
|
+
end
|
12
|
+
|
13
|
+
def puts(s)
|
14
|
+
@w.println s
|
15
|
+
end
|
16
|
+
|
17
|
+
def << (s)
|
18
|
+
@w.print s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/ape/samples.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# Copyright © 2006 Sun Microsystems, Inc. All rights reserved
|
2
|
+
# Use is subject to license terms - see file "LICENSE"
|
3
|
+
require 'rexml/xpath'
|
4
|
+
require 'date'
|
5
|
+
require 'base64'
|
6
|
+
require 'erubis'
|
7
|
+
|
8
|
+
module Ape
|
9
|
+
class Samples
|
10
|
+
|
11
|
+
@@service_schema = nil
|
12
|
+
@@categories_schema = nil
|
13
|
+
@@atom_schema = nil
|
14
|
+
@@home = nil
|
15
|
+
|
16
|
+
def Samples.home=(home)
|
17
|
+
@@home = home
|
18
|
+
end
|
19
|
+
|
20
|
+
def Samples.foreign_child
|
21
|
+
'subject'
|
22
|
+
end
|
23
|
+
def Samples.foreign_namespace
|
24
|
+
Names::DcNamespace
|
25
|
+
end
|
26
|
+
def Samples.foreign_child_content
|
27
|
+
'Simians'
|
28
|
+
end
|
29
|
+
|
30
|
+
def Samples.load_schema(file_name)
|
31
|
+
schema = ""
|
32
|
+
File.open(File.join(File.dirname(__FILE__), "/samples/#{file_name}_schema.txt")) do |file|
|
33
|
+
while(line = file.gets)
|
34
|
+
schema << line
|
35
|
+
end
|
36
|
+
end
|
37
|
+
schema
|
38
|
+
end
|
39
|
+
|
40
|
+
def Samples.service_RNC
|
41
|
+
@@service_schema = load_schema('service') unless @@service_schema
|
42
|
+
@@service_schema
|
43
|
+
end
|
44
|
+
|
45
|
+
def Samples.categories_RNC
|
46
|
+
@@categories_schema = load_schema('categories') unless @@categories_schema
|
47
|
+
@@categories_schema
|
48
|
+
end
|
49
|
+
|
50
|
+
def Samples.atom_RNC
|
51
|
+
@@atom_schema = load_schema('atom') unless @@atom_schema
|
52
|
+
@@atom_schema
|
53
|
+
end
|
54
|
+
|
55
|
+
#recipe from cap
|
56
|
+
def Samples.home_directory
|
57
|
+
ENV["HOME"] || (ENV["HOMEPATH"] && "#{ENV["HOMEDRIVE"]}#{ENV["HOMEPATH"]}") ||
|
58
|
+
"/"
|
59
|
+
end
|
60
|
+
|
61
|
+
def Samples.home
|
62
|
+
@@home || ENV["APE_HOME"] || File.join(home_directory,".ape")
|
63
|
+
end
|
64
|
+
|
65
|
+
def Samples.make_id
|
66
|
+
id = ''
|
67
|
+
5.times { id += rand(1000000).to_s }
|
68
|
+
"tag:tbray.org,2005:#{id}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def Samples.entry_path(type)
|
72
|
+
File.exist?(File.join(home, "/#{type}.eruby"))?
|
73
|
+
File.join(home, "/#{type}.eruby") :
|
74
|
+
File.join(File.dirname(__FILE__), "/samples/#{type}.eruby")
|
75
|
+
end
|
76
|
+
|
77
|
+
def Samples.load_template(type)
|
78
|
+
entry_path = entry_path(type)
|
79
|
+
input = File.read(entry_path)
|
80
|
+
eruby = Erubis::Eruby.new(input)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def Samples.mini_entry
|
85
|
+
eruby = load_template('mini_entry')
|
86
|
+
|
87
|
+
now = DateTime::now.strftime("%Y-%m-%dT%H:%M:%S%z").sub(/(..)$/, ':\1')
|
88
|
+
id = make_id
|
89
|
+
|
90
|
+
eruby.result(binding())
|
91
|
+
end
|
92
|
+
|
93
|
+
def Samples.basic_entry
|
94
|
+
eruby = load_template('basic_entry')
|
95
|
+
|
96
|
+
id = make_id
|
97
|
+
now = DateTime::now.strftime("%Y-%m-%dT%H:%M:%S%z").sub(/(..)$/, ':\1')
|
98
|
+
title = Escaper.escape('From the <APE> (サル)')
|
99
|
+
summary = "Summary from the <b>&lt;&nbsp;APE&nbsp;></b> at #{now}"
|
100
|
+
subject = Names::DcNamespace
|
101
|
+
|
102
|
+
eruby.result(binding())
|
103
|
+
end
|
104
|
+
|
105
|
+
def Samples.unclean_xhtml_entry
|
106
|
+
eruby = load_template('unclean_xhtml_entry')
|
107
|
+
|
108
|
+
id = make_id
|
109
|
+
now = DateTime::now.strftime("%Y-%m-%dT%H:%M:%S%z").sub(/(..)$/, ':\1')
|
110
|
+
|
111
|
+
eruby.result(binding())
|
112
|
+
end
|
113
|
+
|
114
|
+
def Samples.cat_test_entry
|
115
|
+
e = retitled_entry('Testing category posting')
|
116
|
+
end
|
117
|
+
|
118
|
+
def Samples.retitled_entry(new_title, new_id = nil)
|
119
|
+
e = basic_entry
|
120
|
+
e.gsub!(/<title>.*<\/title>/, "<title>#{new_title}</title>")
|
121
|
+
new_id = make_id unless new_id
|
122
|
+
e.gsub(/<id>.*<\/id>/, "<id>#{new_id}</id>")
|
123
|
+
end
|
124
|
+
|
125
|
+
def Samples.picture
|
126
|
+
b64 =<<END_OF_PICTURE
|
127
|
+
/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQE
|
128
|
+
BQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/
|
129
|
+
2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU
|
130
|
+
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAA8AEYDASIAAhEBAxEB/8QA
|
131
|
+
HwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF
|
132
|
+
BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
|
133
|
+
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1
|
134
|
+
dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
|
135
|
+
x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEB
|
136
|
+
AQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAEC
|
137
|
+
AxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRom
|
138
|
+
JygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE
|
139
|
+
hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU
|
140
|
+
1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5fgS0knaT
|
141
|
+
7C4UddzHINab3lrboz/2ezop5LAnj3qtbK1xJbwbcZYZwc4GeprpZLNZY5Tu
|
142
|
+
Ai8skhjgHk5FfJNtWVm/m/8Agn7M6dOGzSdvzdvKxl2VzaAec2n7uMqDnBHr
|
143
|
+
W1FPEY7YDTrVYXUNl5fw/wAf0qjps0NzbCEMUZMBhnJz9PwqzZbISIpQj27s
|
144
|
+
A+4ZK99w/wAKycU229fm/wDM9aVDlhF09uv9eRrG6jmgeGLTrR2kPG2T5uMe
|
145
|
+
/wDnNcnrGuxpdGMWCM4cR7V+bkehzXSatJBo4S3sZFkmkQ75x0QZ7H1965z7
|
146
|
+
MjIxDsAEJyTkgY5b9KjlitV+N/yuXSoyrO/T835FKe/Ms8khsMFRtIwR2780
|
147
|
+
77bGqQObHZORwgz8wHGRz6/yqOxkZmnO1isjYXeMZB4yPyqvrSJa30DF2bdu
|
148
|
+
4TtycZq7Nbp2stdTgapyqciaerTXp899uhFc6qLmQg23X5iTxz9aKZes0RRX
|
149
|
+
yxA+7n9aK6YcvKrq/wAzkr4W1R8rsu1rnSWD2UcLPIgE3BIDHJPt7ZqBXmiv
|
150
|
+
ZnuSTaMCpUAHy89P8j1pdKtGe7jllI+i84H9TW7JIt/PLYCGREyfKbachu5P
|
151
|
+
P/6q578rf3/1/X/B6mkopTV2/wAv6X4fNRp4ZitLQXsLZlUL8p5LAjg/XFVz
|
152
|
+
fRKky+YMbCd7L19himadPLat9lD5jALKqtyuPT2961bfT4LlELQA+ZuyVXJz
|
153
|
+
nrWMlKKbk9j0KOIVLlp2321f/D9bmH9uihxNJgKNqnjJxjJx+NFuh1RONjRE
|
154
|
+
gkgYIHOFH+eK0tV0m3adDFEjgEbuM5yAc5z+lVpA+nRGOMrGGOPNPAXHO0de
|
155
|
+
abkqvNKP9alLETgoULJfPy+X6kGqWovJRaQqqxx4DzoM9Ow9ag8iNmeN4wXG
|
156
|
+
V3tgluevsa0WlSw0uS5hj82RW2kOp2ITzuPHX6etQ3CJcWkdyymJpGLbTxsI
|
157
|
+
/iXjp9aiOiv8vnv+Wv8AWtT9m6iw6Wq6+d7Wt2vp6+W3NyqtlIEm6c7XKZ9O
|
158
|
+
MGirjz/aUDOFkOfvOOG9+aK9OnhnUipXt8m/0PCq5p7Cbpyim115kv1ROzSy
|
159
|
+
SR3UK5jx8yg8tzXW3Gtw3Gm26QQBbtkCO6DmQjp2yP61yGk34SQIGco5ypHY
|
160
|
+
9s1q2MS2l1LdKCNg3le3ORj8a5uTbmt5f1/XT5ae1UVZpvr3/r0/4ZpNp76X
|
161
|
+
Os2AZW6KTgZJ6Y9OKgOszpAyu6IEPAKA5IPT2qxFeG/Xz5mbzpAQikFsL6/l
|
162
|
+
WXcp5832e2KuZPmKsCNo9/50KN07nalCmvaTev8AwxqrqNxe2kzI0RkGAFMa
|
163
|
+
7j1PXHHpVqKZLm3WK+aOUld5IbAb6+9Zl5af2WqnzQ1lN0lQcbsY4PXr61Qa
|
164
|
+
5JixvIJbCgDGCO9KUFq1szWm4VaSS0kvw/H8jcivItPlSDasqEfJuAAYd1PH
|
165
|
+
A9aoavOt3O4wTC5y74+97cDoMdRUEc39p2brONoiOHOcYb1pmrShII7W2Oc8
|
166
|
+
LzyB2rPka1fb+v8AP8fSXiVN8qXv7X8lv/lfsmvWhqBF5MiWsqQhF+ZiePoK
|
167
|
+
KpzfuI1C/OqkqV2d/WiuqMqkFaLsjklh8K3erFN9/wCmSaNqBSPdNE5KkMML
|
168
|
+
1561tJrqSSylbaQh49oXgdjyea5S21W5ReJPb8KvW2sXQlzvByhPI+tdUqDb
|
169
|
+
TaX3v/I+bjjHy2v+C/UmfWjazbYopHToQeorSj1WGGzkRSwuZT+8kdSSB/d6
|
170
|
+
dKw/t0skr7tp2kAfKKsapqs4kiAKjChshRnOBS9k7ar8f+AavFyqa30Xl/wT
|
171
|
+
RjvtkDW8zs9q+NyMh+96ism4umR9kSSSgEqrn+Jc/pSf23ds0zFwdvIBUYzV
|
172
|
+
aLU55DG5Khj3CipdKTbdlr5/8A1hifZ2af8AX3luDUC0dxCySoJG3byBj8fy
|
173
|
+
qG71KW4nSRomwq7CV4OO2KonVLgblDAAcDAqAanO8+0kADngURoXbdvxZM8Y
|
174
|
+
001+n/Dk41B8ZaFmx8oyx6UVVn1m5jRCGXOMfdorRU2lqvx/4BhPFzlK6lb5
|
175
|
+
I//Z
|
176
|
+
END_OF_PICTURE
|
177
|
+
Base64.decode64(b64)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,338 @@
|
|
1
|
+
# -*- rnc -*-
|
2
|
+
# RELAX NG Compact Syntax Grammar for the
|
3
|
+
# Atom Format Specification Version 11
|
4
|
+
|
5
|
+
namespace atom = "http://www.w3.org/2005/Atom"
|
6
|
+
namespace xhtml = "http://www.w3.org/1999/xhtml"
|
7
|
+
namespace s = "http://www.ascc.net/xml/schematron"
|
8
|
+
namespace local = ""
|
9
|
+
|
10
|
+
start = atomFeed | atomEntry
|
11
|
+
|
12
|
+
# Common attributes
|
13
|
+
|
14
|
+
atomCommonAttributes =
|
15
|
+
attribute xml:base { atomUri }?,
|
16
|
+
attribute xml:lang { atomLanguageTag }?,
|
17
|
+
undefinedAttribute*
|
18
|
+
|
19
|
+
# Text Constructs
|
20
|
+
|
21
|
+
atomPlainTextConstruct =
|
22
|
+
atomCommonAttributes,
|
23
|
+
attribute type { "text" | "html" }?,
|
24
|
+
text
|
25
|
+
|
26
|
+
atomXHTMLTextConstruct =
|
27
|
+
atomCommonAttributes,
|
28
|
+
attribute type { "xhtml" },
|
29
|
+
xhtmlDiv
|
30
|
+
|
31
|
+
atomTextConstruct = atomPlainTextConstruct | atomXHTMLTextConstruct
|
32
|
+
|
33
|
+
# Person Construct
|
34
|
+
|
35
|
+
atomPersonConstruct =
|
36
|
+
atomCommonAttributes,
|
37
|
+
(element atom:name { text }
|
38
|
+
& element atom:uri { atomUri }?
|
39
|
+
& element atom:email { atomEmailAddress }?
|
40
|
+
& extensionElement*)
|
41
|
+
|
42
|
+
# Date Construct
|
43
|
+
|
44
|
+
atomDateConstruct =
|
45
|
+
atomCommonAttributes,
|
46
|
+
xsd:dateTime
|
47
|
+
|
48
|
+
# atom:feed
|
49
|
+
|
50
|
+
atomFeed =
|
51
|
+
[
|
52
|
+
s:rule [
|
53
|
+
context = "atom:feed"
|
54
|
+
s:assert [
|
55
|
+
test = "atom:author or not(atom:entry[not(atom:author)])"
|
56
|
+
"An atom:feed must have an atom:author unless all "
|
57
|
+
~ "of its atom:entry children have an atom:author."
|
58
|
+
]
|
59
|
+
]
|
60
|
+
]
|
61
|
+
element atom:feed {
|
62
|
+
atomCommonAttributes,
|
63
|
+
(atomAuthor*
|
64
|
+
& atomCategory*
|
65
|
+
& atomContributor*
|
66
|
+
& atomGenerator?
|
67
|
+
& atomIcon?
|
68
|
+
& atomId
|
69
|
+
& atomLink*
|
70
|
+
& atomLogo?
|
71
|
+
& atomRights?
|
72
|
+
& atomSubtitle?
|
73
|
+
& atomTitle
|
74
|
+
& atomUpdated
|
75
|
+
& extensionElement*),
|
76
|
+
atomEntry*
|
77
|
+
}
|
78
|
+
|
79
|
+
# atom:entry
|
80
|
+
|
81
|
+
atomEntry =
|
82
|
+
[
|
83
|
+
s:rule [
|
84
|
+
context = "atom:entry"
|
85
|
+
s:assert [
|
86
|
+
test = "atom:link[@rel='alternate'] "
|
87
|
+
~ "or atom:link[not(@rel)] "
|
88
|
+
~ "or atom:content"
|
89
|
+
"An atom:entry must have at least one atom:link element "
|
90
|
+
~ "with a rel attribute of 'alternate' "
|
91
|
+
~ "or an atom:content."
|
92
|
+
]
|
93
|
+
]
|
94
|
+
s:rule [
|
95
|
+
context = "atom:entry"
|
96
|
+
s:assert [
|
97
|
+
test = "atom:author or "
|
98
|
+
~ "../atom:author or atom:source/atom:author"
|
99
|
+
"An atom:entry must have an atom:author "
|
100
|
+
~ "if its feed does not."
|
101
|
+
]
|
102
|
+
]
|
103
|
+
]
|
104
|
+
element atom:entry {
|
105
|
+
atomCommonAttributes,
|
106
|
+
(atomAuthor*
|
107
|
+
& atomCategory*
|
108
|
+
& atomContent?
|
109
|
+
& atomContributor*
|
110
|
+
& atomId
|
111
|
+
& atomLink*
|
112
|
+
& atomPublished?
|
113
|
+
& atomRights?
|
114
|
+
& atomSource?
|
115
|
+
& atomSummary?
|
116
|
+
& atomTitle
|
117
|
+
& atomUpdated
|
118
|
+
& extensionElement*)
|
119
|
+
}
|
120
|
+
|
121
|
+
# atom:content
|
122
|
+
|
123
|
+
atomInlineTextContent =
|
124
|
+
element atom:content {
|
125
|
+
atomCommonAttributes,
|
126
|
+
attribute type { "text" | "html" }?,
|
127
|
+
(text)*
|
128
|
+
}
|
129
|
+
|
130
|
+
atomInlineXHTMLContent =
|
131
|
+
element atom:content {
|
132
|
+
atomCommonAttributes,
|
133
|
+
attribute type { "xhtml" },
|
134
|
+
xhtmlDiv
|
135
|
+
}
|
136
|
+
|
137
|
+
atomInlineOtherContent =
|
138
|
+
element atom:content {
|
139
|
+
atomCommonAttributes,
|
140
|
+
attribute type { atomMediaType }?,
|
141
|
+
(text|anyElement)*
|
142
|
+
}
|
143
|
+
|
144
|
+
atomOutOfLineContent =
|
145
|
+
element atom:content {
|
146
|
+
atomCommonAttributes,
|
147
|
+
attribute type { atomMediaType }?,
|
148
|
+
attribute src { atomUri },
|
149
|
+
empty
|
150
|
+
}
|
151
|
+
|
152
|
+
atomContent = atomInlineTextContent
|
153
|
+
| atomInlineXHTMLContent
|
154
|
+
| atomInlineOtherContent
|
155
|
+
| atomOutOfLineContent
|
156
|
+
|
157
|
+
# atom:author
|
158
|
+
|
159
|
+
atomAuthor = element atom:author { atomPersonConstruct }
|
160
|
+
|
161
|
+
# atom:category
|
162
|
+
|
163
|
+
atomCategory =
|
164
|
+
element atom:category {
|
165
|
+
atomCommonAttributes,
|
166
|
+
attribute term { text },
|
167
|
+
attribute scheme { atomUri }?,
|
168
|
+
attribute label { text }?,
|
169
|
+
undefinedContent
|
170
|
+
}
|
171
|
+
|
172
|
+
# atom:contributor
|
173
|
+
|
174
|
+
atomContributor = element atom:contributor { atomPersonConstruct }
|
175
|
+
|
176
|
+
# atom:generator
|
177
|
+
|
178
|
+
atomGenerator = element atom:generator {
|
179
|
+
atomCommonAttributes,
|
180
|
+
attribute uri { atomUri }?,
|
181
|
+
attribute version { text }?,
|
182
|
+
text
|
183
|
+
}
|
184
|
+
|
185
|
+
# atom:icon
|
186
|
+
|
187
|
+
atomIcon = element atom:icon {
|
188
|
+
atomCommonAttributes,
|
189
|
+
(atomUri)
|
190
|
+
}
|
191
|
+
|
192
|
+
# atom:id
|
193
|
+
|
194
|
+
atomId = element atom:id {
|
195
|
+
atomCommonAttributes,
|
196
|
+
(atomUri)
|
197
|
+
}
|
198
|
+
|
199
|
+
# atom:logo
|
200
|
+
|
201
|
+
atomLogo = element atom:logo {
|
202
|
+
atomCommonAttributes,
|
203
|
+
(atomUri)
|
204
|
+
}
|
205
|
+
|
206
|
+
# atom:link
|
207
|
+
|
208
|
+
atomLink =
|
209
|
+
element atom:link {
|
210
|
+
atomCommonAttributes,
|
211
|
+
attribute href { atomUri },
|
212
|
+
attribute rel { atomNCName | atomUri }?,
|
213
|
+
attribute type { atomMediaType }?,
|
214
|
+
attribute hreflang { atomLanguageTag }?,
|
215
|
+
attribute title { text }?,
|
216
|
+
attribute length { text }?,
|
217
|
+
undefinedContent
|
218
|
+
}
|
219
|
+
|
220
|
+
# atom:published
|
221
|
+
|
222
|
+
atomPublished = element atom:published { atomDateConstruct }
|
223
|
+
|
224
|
+
# atom:rights
|
225
|
+
|
226
|
+
atomRights = element atom:rights { atomTextConstruct }
|
227
|
+
|
228
|
+
# atom:source
|
229
|
+
|
230
|
+
atomSource =
|
231
|
+
element atom:source {
|
232
|
+
atomCommonAttributes,
|
233
|
+
(atomAuthor*
|
234
|
+
& atomCategory*
|
235
|
+
& atomContributor*
|
236
|
+
& atomGenerator?
|
237
|
+
& atomIcon?
|
238
|
+
& atomId?
|
239
|
+
& atomLink*
|
240
|
+
& atomLogo?
|
241
|
+
& atomRights?
|
242
|
+
& atomSubtitle?
|
243
|
+
& atomTitle?
|
244
|
+
& atomUpdated?
|
245
|
+
& extensionElement*)
|
246
|
+
}
|
247
|
+
|
248
|
+
# atom:subtitle
|
249
|
+
|
250
|
+
atomSubtitle = element atom:subtitle { atomTextConstruct }
|
251
|
+
|
252
|
+
# atom:summary
|
253
|
+
|
254
|
+
atomSummary = element atom:summary { atomTextConstruct }
|
255
|
+
|
256
|
+
# atom:title
|
257
|
+
|
258
|
+
atomTitle = element atom:title { atomTextConstruct }
|
259
|
+
|
260
|
+
# atom:updated
|
261
|
+
|
262
|
+
atomUpdated = element atom:updated { atomDateConstruct }
|
263
|
+
|
264
|
+
# Low-level simple types
|
265
|
+
|
266
|
+
atomNCName = xsd:string { minLength = "1" pattern = "[^:]*" }
|
267
|
+
|
268
|
+
# Whatever a media type is, it contains at least one slash
|
269
|
+
atomMediaType = xsd:string { pattern = ".+/.+" }
|
270
|
+
|
271
|
+
# As defined in RFC 3066
|
272
|
+
atomLanguageTag = xsd:string {
|
273
|
+
pattern = "[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*"
|
274
|
+
}
|
275
|
+
|
276
|
+
# Unconstrained; it's not entirely clear how IRI fit into
|
277
|
+
# xsd:anyURI so let's not try to constrain it here
|
278
|
+
atomUri = text
|
279
|
+
|
280
|
+
# Whatever an email address is, it contains at least one @
|
281
|
+
atomEmailAddress = xsd:string { pattern = ".+@.+" }
|
282
|
+
|
283
|
+
# Simple Extension
|
284
|
+
|
285
|
+
simpleExtensionElement =
|
286
|
+
element * - atom:* {
|
287
|
+
text
|
288
|
+
}
|
289
|
+
|
290
|
+
# Structured Extension
|
291
|
+
|
292
|
+
structuredExtensionElement =
|
293
|
+
element * - atom:* {
|
294
|
+
(attribute * { text }+,
|
295
|
+
(text|anyElement)*)
|
296
|
+
| (attribute * { text }*,
|
297
|
+
(text?, anyElement+, (text|anyElement)*))
|
298
|
+
}
|
299
|
+
|
300
|
+
# Other Extensibility
|
301
|
+
|
302
|
+
extensionElement =
|
303
|
+
simpleExtensionElement | structuredExtensionElement
|
304
|
+
|
305
|
+
undefinedAttribute =
|
306
|
+
attribute * - (xml:base | xml:lang | local:*) { text }
|
307
|
+
|
308
|
+
undefinedContent = (text|anyForeignElement)*
|
309
|
+
|
310
|
+
anyElement =
|
311
|
+
element * {
|
312
|
+
(attribute * { text }
|
313
|
+
| text
|
314
|
+
| anyElement)*
|
315
|
+
}
|
316
|
+
|
317
|
+
anyForeignElement =
|
318
|
+
element * - atom:* {
|
319
|
+
(attribute * { text }
|
320
|
+
| text
|
321
|
+
| anyElement)*
|
322
|
+
}
|
323
|
+
|
324
|
+
# XHTML
|
325
|
+
|
326
|
+
anyXHTML = element xhtml:* {
|
327
|
+
(attribute * { text }
|
328
|
+
| text
|
329
|
+
| anyXHTML)*
|
330
|
+
}
|
331
|
+
|
332
|
+
xhtmlDiv = element xhtml:div {
|
333
|
+
(attribute * { text }
|
334
|
+
| text
|
335
|
+
| anyXHTML)*
|
336
|
+
}
|
337
|
+
|
338
|
+
# EOF
|