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 |
---|