ape 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
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
|
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
|