339 lines
6.6 KiB
Plaintext
339 lines
6.6 KiB
Plaintext
|
# -*- rnc -*-
|
||
|
# RELAX NG Compact Syntax Grammar for the
|
||
|
# Atom Format Specification Version 11
|
||
|
|
||
|
namespace atom = "http://www.w3.org/2005/Atom"
|
||
|
namespace xhtml = "http://www.w3.org/1999/xhtml"
|
||
|
namespace s = "http://www.ascc.net/xml/schematron"
|
||
|
namespace local = ""
|
||
|
|
||
|
start = atomFeed | atomEntry
|
||
|
|
||
|
# Common attributes
|
||
|
|
||
|
atomCommonAttributes =
|
||
|
attribute xml:base { atomUri }?,
|
||
|
attribute xml:lang { atomLanguageTag }?,
|
||
|
undefinedAttribute*
|
||
|
|
||
|
# Text Constructs
|
||
|
|
||
|
atomPlainTextConstruct =
|
||
|
atomCommonAttributes,
|
||
|
attribute type { "text" | "html" }?,
|
||
|
text
|
||
|
|
||
|
atomXHTMLTextConstruct =
|
||
|
atomCommonAttributes,
|
||
|
attribute type { "xhtml" },
|
||
|
xhtmlDiv
|
||
|
|
||
|
atomTextConstruct = atomPlainTextConstruct | atomXHTMLTextConstruct
|
||
|
|
||
|
# Person Construct
|
||
|
|
||
|
atomPersonConstruct =
|
||
|
atomCommonAttributes,
|
||
|
(element atom:name { text }
|
||
|
& element atom:uri { atomUri }?
|
||
|
& element atom:email { atomEmailAddress }?
|
||
|
& extensionElement*)
|
||
|
|
||
|
# Date Construct
|
||
|
|
||
|
atomDateConstruct =
|
||
|
atomCommonAttributes,
|
||
|
xsd:dateTime
|
||
|
|
||
|
# atom:feed
|
||
|
|
||
|
atomFeed =
|
||
|
[
|
||
|
s:rule [
|
||
|
context = "atom:feed"
|
||
|
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."
|
||
|
]
|
||
|
]
|
||
|
]
|
||
|
element atom:feed {
|
||
|
atomCommonAttributes,
|
||
|
(atomAuthor*
|
||
|
& atomCategory*
|
||
|
& atomContributor*
|
||
|
& atomGenerator?
|
||
|
& atomIcon?
|
||
|
& atomId
|
||
|
& atomLink*
|
||
|
& atomLogo?
|
||
|
& atomRights?
|
||
|
& atomSubtitle?
|
||
|
& atomTitle
|
||
|
& atomUpdated
|
||
|
& extensionElement*),
|
||
|
atomEntry*
|
||
|
}
|
||
|
|
||
|
# atom:entry
|
||
|
|
||
|
atomEntry =
|
||
|
[
|
||
|
s:rule [
|
||
|
context = "atom:entry"
|
||
|
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:rule [
|
||
|
context = "atom:entry"
|
||
|
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."
|
||
|
]
|
||
|
]
|
||
|
]
|
||
|
element atom:entry {
|
||
|
atomCommonAttributes,
|
||
|
(atomAuthor*
|
||
|
& atomCategory*
|
||
|
& atomContent?
|
||
|
& atomContributor*
|
||
|
& atomId
|
||
|
& atomLink*
|
||
|
& atomPublished?
|
||
|
& atomRights?
|
||
|
& atomSource?
|
||
|
& atomSummary?
|
||
|
& atomTitle
|
||
|
& atomUpdated
|
||
|
& extensionElement*)
|
||
|
}
|
||
|
|
||
|
# atom:content
|
||
|
|
||
|
atomInlineTextContent =
|
||
|
element atom:content {
|
||
|
atomCommonAttributes,
|
||
|
attribute type { "text" | "html" }?,
|
||
|
(text)*
|
||
|
}
|
||
|
|
||
|
atomInlineXHTMLContent =
|
||
|
element atom:content {
|
||
|
atomCommonAttributes,
|
||
|
attribute type { "xhtml" },
|
||
|
xhtmlDiv
|
||
|
}
|
||
|
|
||
|
atomInlineOtherContent =
|
||
|
element atom:content {
|
||
|
atomCommonAttributes,
|
||
|
attribute type { atomMediaType }?,
|
||
|
(text|anyElement)*
|
||
|
}
|
||
|
|
||
|
atomOutOfLineContent =
|
||
|
element atom:content {
|
||
|
atomCommonAttributes,
|
||
|
attribute type { atomMediaType }?,
|
||
|
attribute src { atomUri },
|
||
|
empty
|
||
|
}
|
||
|
|
||
|
atomContent = atomInlineTextContent
|
||
|
| atomInlineXHTMLContent
|
||
|
| atomInlineOtherContent
|
||
|
| atomOutOfLineContent
|
||
|
|
||
|
# atom:author
|
||
|
|
||
|
atomAuthor = element atom:author { atomPersonConstruct }
|
||
|
|
||
|
# atom:category
|
||
|
|
||
|
atomCategory =
|
||
|
element atom:category {
|
||
|
atomCommonAttributes,
|
||
|
attribute term { text },
|
||
|
attribute scheme { atomUri }?,
|
||
|
attribute label { text }?,
|
||
|
undefinedContent
|
||
|
}
|
||
|
|
||
|
# atom:contributor
|
||
|
|
||
|
atomContributor = element atom:contributor { atomPersonConstruct }
|
||
|
|
||
|
# atom:generator
|
||
|
|
||
|
atomGenerator = element atom:generator {
|
||
|
atomCommonAttributes,
|
||
|
attribute uri { atomUri }?,
|
||
|
attribute version { text }?,
|
||
|
text
|
||
|
}
|
||
|
|
||
|
# atom:icon
|
||
|
|
||
|
atomIcon = element atom:icon {
|
||
|
atomCommonAttributes,
|
||
|
(atomUri)
|
||
|
}
|
||
|
|
||
|
# atom:id
|
||
|
|
||
|
atomId = element atom:id {
|
||
|
atomCommonAttributes,
|
||
|
(atomUri)
|
||
|
}
|
||
|
|
||
|
# atom:logo
|
||
|
|
||
|
atomLogo = element atom:logo {
|
||
|
atomCommonAttributes,
|
||
|
(atomUri)
|
||
|
}
|
||
|
|
||
|
# atom:link
|
||
|
|
||
|
atomLink =
|
||
|
element atom:link {
|
||
|
atomCommonAttributes,
|
||
|
attribute href { atomUri },
|
||
|
attribute rel { atomNCName | atomUri }?,
|
||
|
attribute type { atomMediaType }?,
|
||
|
attribute hreflang { atomLanguageTag }?,
|
||
|
attribute title { text }?,
|
||
|
attribute length { text }?,
|
||
|
undefinedContent
|
||
|
}
|
||
|
|
||
|
# atom:published
|
||
|
|
||
|
atomPublished = element atom:published { atomDateConstruct }
|
||
|
|
||
|
# atom:rights
|
||
|
|
||
|
atomRights = element atom:rights { atomTextConstruct }
|
||
|
|
||
|
# atom:source
|
||
|
|
||
|
atomSource =
|
||
|
element atom:source {
|
||
|
atomCommonAttributes,
|
||
|
(atomAuthor*
|
||
|
& atomCategory*
|
||
|
& atomContributor*
|
||
|
& atomGenerator?
|
||
|
& atomIcon?
|
||
|
& atomId?
|
||
|
& atomLink*
|
||
|
& atomLogo?
|
||
|
& atomRights?
|
||
|
& atomSubtitle?
|
||
|
& atomTitle?
|
||
|
& atomUpdated?
|
||
|
& extensionElement*)
|
||
|
}
|
||
|
|
||
|
# atom:subtitle
|
||
|
|
||
|
atomSubtitle = element atom:subtitle { atomTextConstruct }
|
||
|
|
||
|
# atom:summary
|
||
|
|
||
|
atomSummary = element atom:summary { atomTextConstruct }
|
||
|
|
||
|
# atom:title
|
||
|
|
||
|
atomTitle = element atom:title { atomTextConstruct }
|
||
|
|
||
|
# atom:updated
|
||
|
|
||
|
atomUpdated = element atom:updated { atomDateConstruct }
|
||
|
|
||
|
# Low-level simple types
|
||
|
|
||
|
atomNCName = xsd:string { minLength = "1" pattern = "[^:]*" }
|
||
|
|
||
|
# Whatever a media type is, it contains at least one slash
|
||
|
atomMediaType = xsd:string { pattern = ".+/.+" }
|
||
|
|
||
|
# As defined in RFC 3066
|
||
|
atomLanguageTag = xsd:string {
|
||
|
pattern = "[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*"
|
||
|
}
|
||
|
|
||
|
# Unconstrained; it's not entirely clear how IRI fit into
|
||
|
# xsd:anyURI so let's not try to constrain it here
|
||
|
atomUri = text
|
||
|
|
||
|
# Whatever an email address is, it contains at least one @
|
||
|
atomEmailAddress = xsd:string { pattern = ".+@.+" }
|
||
|
|
||
|
# Simple Extension
|
||
|
|
||
|
simpleExtensionElement =
|
||
|
element * - atom:* {
|
||
|
text
|
||
|
}
|
||
|
|
||
|
# Structured Extension
|
||
|
|
||
|
structuredExtensionElement =
|
||
|
element * - atom:* {
|
||
|
(attribute * { text }+,
|
||
|
(text|anyElement)*)
|
||
|
| (attribute * { text }*,
|
||
|
(text?, anyElement+, (text|anyElement)*))
|
||
|
}
|
||
|
|
||
|
# Other Extensibility
|
||
|
|
||
|
extensionElement =
|
||
|
simpleExtensionElement | structuredExtensionElement
|
||
|
|
||
|
undefinedAttribute =
|
||
|
attribute * - (xml:base | xml:lang | local:*) { text }
|
||
|
|
||
|
undefinedContent = (text|anyForeignElement)*
|
||
|
|
||
|
anyElement =
|
||
|
element * {
|
||
|
(attribute * { text }
|
||
|
| text
|
||
|
| anyElement)*
|
||
|
}
|
||
|
|
||
|
anyForeignElement =
|
||
|
element * - atom:* {
|
||
|
(attribute * { text }
|
||
|
| text
|
||
|
| anyElement)*
|
||
|
}
|
||
|
|
||
|
# XHTML
|
||
|
|
||
|
anyXHTML = element xhtml:* {
|
||
|
(attribute * { text }
|
||
|
| text
|
||
|
| anyXHTML)*
|
||
|
}
|
||
|
|
||
|
xhtmlDiv = element xhtml:div {
|
||
|
(attribute * { text }
|
||
|
| text
|
||
|
| anyXHTML)*
|
||
|
}
|
||
|
|
||
|
# EOF
|