Structural 3.0.0 Language Specification
Notational Conventions
Unicode
The specification makes reference to the Unicode character set which, at the time of writing, is at version 8.0.0. The specification often references specific Unicode characters, and does so using the standard notation U+NNNN, where N represents a hexadecimal digit. For example, U+03BB corresponds to the lowercase lambda symbol λ.
EBNF
The specification gives grammar definitions in ISO/IEC 14977:1996 Extended Backus-Naur form.
Haskell
Rather than rely on untyped and ambiguous mathematical notation, this documentation expresses all mathematics and type definitions in strict Haskell 2010 with no extensions. All Haskell sources are included along with the documentation and can therefore be executed from the command line GHCi tool in order to interactively check results and experiment with functions.
When used within prose, functions are referred to using fully qualified notation, such as (Vector3f.cross n t). This is the application of the cross function defined in the Vector3f module, to the arguments n and t.
S-Expressions
An s-expression is defined by the following grammar:
expression =
    symbol
  | quoted_string
  | "[" , { expression } , "]"
  | "(" , { expression } , ")" ;
The sequences U+000D U+000A and U+000A are recognized as line terminators for the purposes of tracking line and column numbers for diagnostic messages. Bare U+000D characters are not permitted to appear outside of quoted strings.
The terminals of the grammar are given as:
symbol_character =
  ? not (")" | "(" | "[" | "]" | U+0022 | WHITESPACE) ? ;

symbol =
  symbol_character , { symbol_character } ;

quoted_character =
  ? not U+0022 ? ;

quoted_string =
  U+0022 , (quoted_character | escape) , { (quoted_character | escape) } , U+0022 ;

escape =
    escape_carriage
  | escape_newline
  | escape_tab
  | escape_quote
  | escape_unicode4
  | escape_unicode8 ;

escape_carriage =
  "\r" ;

escape_newline =
  "\n" ;

escape_quote =
  "\" , U+0022 ;

escape_tab =
  "\t" ;

escape_unicode4 =
  "\u" ,
  hex_digit , hex_digit , hex_digit , hex_digit ;

escape_unicode8 =
  "\u" ,
  hex_digit , hex_digit , hex_digit , hex_digit ,
  hex_digit , hex_digit , hex_digit , hex_digit ;

hex_digit =
  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" |
  "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "E" | "f" | "F" ;
Due to limitations in the EBNF format, the definitions for symbol_character and quoted_character cannot be expressed directly. Informally, the symbol_character rule should be understood to specify any Unicode character that is not whitespace, is not U+0028 (, is not U+0029 ), and is not U+0022 ".
S-Expression Metasyntax
Overview
Because no formal standard exists to describe the actual structure of parsed s-expressions, a small language is introduced here to describe the forms used to describe the document elements specified later on in this publication. The syntax of the syntax rules are themselves given as s-expressions, and to avoid an infinite regression problem akin to trying to specify EBNF using EBNF itself, the language here is described informally with an executable Haskell specification [SEMatcher.hs] to make the semantics clear where English cannot.
Rules
A rule may take one of the following forms:
data Rule
  = MAnySymbol
  | MAnyQuoted
  | MAnyList
  | MExactSymbol String
  | MExactQuoted String
  | MExactList [Rule]
  | MChoice [Rule]
  | MListVariadic [Rule] Rule
  deriving Eq

The s-expression syntax of each rule may be inferred from the given Show instance:
instance Show Rule where
  show (MExactSymbol s)    = "(#exact-symbol " ++ s ++ ")"
  show (MExactQuoted s)    = "(#exact-quoted " ++ s ++ ")"
  show (MExactList s)      = "(#exact-list [" ++ (concatMap show s) ++ "])"
  show  MAnySymbol         = "#any-symbol"
  show  MAnyQuoted         = "#any-quoted"
  show  MAnyList           = "#any-list"
  show (MChoice s)         = "(#choice [" ++ (concatMap show s) ++ "])"
  show (MListVariadic s m) = "(#variadic [" ++ (concatMap show s) ++ "]" ++ (show m) ++ ")"

A rule is r said to match an expression e if, given the matches function defined below, matches e r == True.
  • The #any-symbol rule matches an expression e iff e is a symbol.
  • The #any-quoted rule matches an expression e iff e is a quoted string.
  • The #any-list rule matches an expression e iff e is a list.
  • The (#exact-symbol s) rule matches an expression e iff e is a symbol with the value s.
  • The (#exact-quoted s) rule matches an expression e iff e is a quoted string with the value s.
  • The (#exact-list (m₀ m₁ ... mₙ)) rule matches an expression e iff e is a list, the length of e is n + 1, and ∀k. 0 <= k <= n → e[k] matches mₖ.
  • The (#choice (m₀ ... mₙ)) rule matches an expression e iff exactly one rule in the given list (m₀ ... mₙ) matches e. Accordingly, the rule (#choice ()) never matches anything.
  • The (#variadic (m₀ m₁ ... mₙ) r) rule matches an expression e iff e is a list, the length of e is >= n + 1, ∀k. 0 <= k <= n → e[k] matches mₖ, and the remaining elements in e match r. Accordingly, the rule (#variadic () r) will check that every element of a given list matches r, and will always match for a given empty list.
Matching an arbitrary s-expression against a rule is a simple matter of checking to see if the structure of the given expression matches the structure allowed by the rule against which it is being matched. A complete definition of a matching function that encodes the above rules is as follows:
matches :: SE.Expr -> Rule -> Bool
matches (SE.ESymbol e) (MExactSymbol s)    = e == s
matches (SE.ESymbol _) (MExactQuoted _)    = False
matches (SE.ESymbol _) (MExactList _)      = False
matches (SE.ESymbol _) MAnySymbol          = True
matches (SE.ESymbol _) MAnyQuoted          = False
matches (SE.ESymbol _) MAnyList            = False
matches (SE.ESymbol _) (MListVariadic _ _) = False
matches (SE.EQuoted _) MAnySymbol          = False
matches (SE.EQuoted _) MAnyQuoted          = True
matches (SE.EQuoted _) MAnyList            = False
matches (SE.EQuoted e) (MExactQuoted s)    = e == s
matches (SE.EQuoted _) (MExactSymbol _)    = False
matches (SE.EQuoted _) (MExactList _)      = False
matches (SE.EQuoted _) (MListVariadic _ _) = False
matches (SE.EList _)   (MExactSymbol _) = False
matches (SE.EList _)   (MExactQuoted _) = False
matches (SE.EList _)   MAnySymbol       = False
matches (SE.EList _)   MAnyQuoted       = False
matches (SE.EList _)   MAnyList         = True
matches (SE.EList s) (MExactList m) =
  (length s) == (length m) && all (\(xe,xm) -> matches xe xm) (zip s m)
matches (SE.EList s) (MListVariadic m0 mr) =
  if (length s >= length m0)
  then
    let
      prefix_zip = take (length m0) (zip s m0)
      prefix_ok  = all (\(xe,xm) -> matches xe xm) prefix_zip
      suffix     = drop (length m0) s
      suffix_zip = zip suffix (replicate (length suffix) mr)
      suffix_ok  = all (\(xe,xm) -> matches xe xm) suffix_zip
    in
      prefix_ok && suffix_ok
  else
    False
matches e (MChoice m0)= 1 == length (filter (matches e) m0)
Examples
This section is informative. These results can be reproduced by evaluating the given terms in the SEMatcher module using Haskell's interactive command prompt.
The expression x is matched by the rule #any-symbol, but "x" is not:
> matches (SE.ESymbol "x") MAnySymbol
True
> matches (SE.EQuoted "x") MAnySymbol
False
The expression (x y z) is matched by the rule (#exact-list (#exact-symbol "x") (#exact-symbol "y") (#exact-symbol "z")), but (x y y) and (x y) are not:
> matches (SE.EList [SE.ESymbol "x", SE.ESymbol "y", SE.ESymbol "z"]) (MExactList [MExactSymbol "x", MExactSymbol "y", MExactSymbol "z"])
True
> matches (SE.EList [SE.ESymbol "x", SE.ESymbol "y", SE.ESymbol "y"]) (MExactList [MExactSymbol "x", MExactSymbol "y", MExactSymbol "z"])
False
> matches (SE.EList [SE.ESymbol "x", SE.ESymbol "y"]) (MExactList [MExactSymbol "x", MExactSymbol "y", MExactSymbol "z"])
False
Model
Overview
The definition of the structural language is given as an algebraic data type. Later parts of the specification define the concrete syntax that maps text to terms of the described types.
A structural document consists of nested block terms that, at the lowest level, contain inline terms.
Inline Content
Overview
An inline value is the smallest unit of content that can appear in a structural document. The type of inline content is given by the following definition:
data InlineContent
  = ICText          InlineText
  | ICTerm          InlineTerm
  | ICImage         InlineImage
  | ICVerbatim      InlineVerbatim
  | ICLink          InlineLinkInternal
  | ICLinkExternal  InlineLinkExternal
  | ICListOrdered   InlineListOrdered
  | ICListUnordered InlineListUnordered
  | ICFootnoteRef   InlineFootnoteRef
  | ICTable         InlineTable
  | ICInclude       InlineInclude
  deriving Eq
Types
Most elements defined here may have an associated type parameter that can be used to distinguish the element from other elements of the same type during document processing. As an example, the author of a document may tag all mentions of a software package with a type parameter value of package so that the mentions can be highlighted when the document is exported to one of the supported export formats. The values have no intrinsic meaning; their meaning is decided by the author of any given document.
Type identifiers are restricted to combinations of letters, numbers, and U+005F "_".
type_character =
  ? p{IsLetter} | p{isNumber} | U+005F ? ;

type =
  type_character , { type_character } ;
Text
The simplest type of inline content that appears in structural documents is the InlineText type. Terms of type InlineText are simply strings.
data InlineText =
  InlineText String
  deriving Eq

Term
The InlineTerm type denotes a significant element of a section of text. It is usually used to highlight or mark individual words.
data InlineTerm = InlineTerm {
  termType    :: Maybe String,
  termContent :: [InlineText]
} deriving Eq
As shown by the type definition, values of type InlineTerm may have an associated optional type parameter value.
Image
The InlineImage type denotes a reference to an image. The location of the image is given by the target parameter. The width and height of the image can be specified by the optional size parameter. The associated list of inline text elements are used as fallback text in the case that the image becomes unavailable.
data InlineImage = InlineImage {
  imageType    :: Maybe String,
  imageTarget  :: URI.T,
  imageSize    :: Maybe Size,
  imageContent :: [InlineText]
} deriving Eq
As shown by the type definition, values of type InlineImage may have an associated optional type parameter value.
Verbatim
The InlineVerbatim type denotes a section of text in which whitespace should be preserved exactly as it was written.
data InlineVerbatim = InlineVerbatim {
  verbatimType    :: Maybe String,
  verbatimContent :: InlineText
} deriving Eq
As shown by the type definition, values of type InlineVerbatim may have an associated optional type parameter value.
Link
The InlineLinkInternal type denotes a link to an element within the current document. The value of the given target parameter must be equal to the value of the id parameter on an existing block value.
data InlineLinkInternal = InlineLinkInternal {
  linkInternalTarget  :: ID.T,
  linkInternalContent :: [LinkContent]
} deriving Eq
Only a restricted subset of the available inline content types are allowed to appear as descendants of links. The subset is described by the LinkContent type:
data LinkContent
  = LCText  InlineText
  | LCImage InlineImage
  deriving Eq

Link External
The InlineLinkExternal type denotes a link to an external resource.
data InlineLinkExternal = InlineLinkExternal {
  linkExternalTarget  :: URI.T,
  linkExternalContent :: [LinkContent]
} deriving Eq
Footnote Reference
The InlineFootnoteRef type denotes a link to a footnote within the current document.
The value of the given target parameter must be equal to the value of the id parameter on an existing footnote value.
data InlineFootnoteRef = InlineFootnoteRef {
  footnoteTarget :: ID.T
} deriving Eq

Ordered List
The InlineListOrdered type denotes a list of elements that should be understood to be ordered. The individual elements of the list are denoted by values of the ListItem type.
data ListItem = ListItem {
  listItemContent :: [InlineContent]
} deriving Eq
data InlineListOrdered = InlineListOrdered {
  listOrderedItems :: [ListItem]
} deriving Eq
Unordered List
The InlineListUnordered type denotes a list of elements that should be understood to be in no specific order.
data InlineListUnordered = InlineListUnordered {
  listUnorderedItems :: [ListItem]
} deriving Eq
Table
The InlineTable type is a relatively complex type that describes a table consisting of rows, with each row consisting of a number of cells.
data TableCell = TableCell {
  tableCellContent :: [TableCellContent]
} deriving Eq
data TableRow = TableRow {
  tableRowCells :: [TableCell]
} deriving Eq
data InlineTable = InlineTable {
  tableType    :: Maybe String,
  tableSummary :: [InlineText],
  tableHead    :: Maybe TableHead,
  tableBody    :: TableBody
} deriving Eq

A table may have an optional head that describes the number and names of columns in the table.
data TableRow = TableRow {
  tableRowCells :: [TableCell]
} deriving Eq
Implementations are required to check that, if a head is defined, the number of cells in each table row is equal to the number of column names defined in the head.
tableCheck :: InlineTable -> Bool
tableCheck table =
  case (tableHead table) of
    Nothing -> True
    Just th ->
      let rows     = tableBodyRows $ tableBody table
          expected = length $ tableHeadNames th
      in all (\row -> length (tableRowCells row) == expected) rows

Tables may not be nested. That is, the inline content that may appear inside a table cell must not contain a table.
data TableCellContent
  = TCText          InlineText
  | TCTerm          InlineTerm
  | TCImage         InlineImage
  | TCVerbatim      InlineVerbatim
  | TCLink          InlineLinkInternal
  | TCLinkExternal  InlineLinkExternal
  | TCListOrdered   InlineListOrdered
  | TCListUnordered InlineListUnordered
  | TCFootnoteRef   InlineFootnoteRef
  | TCInclude       InlineInclude
  deriving Eq

Include
The InlineInclude type denotes a link to an external file. Values of type InlineInclude do not actually appear in documents directly: They are replaced with the contents of the referenced file as if they had been inserted as a single quoted string.
data InlineInclude = InlineInclude {
  includeFile :: String
} deriving Eq
Complete Inline Model
module InlineContent where

import qualified URI
import qualified ID

data InlineText =
  InlineText String
  deriving Eq

data InlineTerm = InlineTerm {
  termType    :: Maybe String,
  termContent :: [InlineText]
} deriving Eq

data Size = Size {
  sizeWidth  :: Integer,
  sizeHeight :: Integer
} deriving Eq

data InlineImage = InlineImage {
  imageType    :: Maybe String,
  imageTarget  :: URI.T,
  imageSize    :: Maybe Size,
  imageContent :: [InlineText]
} deriving Eq

data InlineVerbatim = InlineVerbatim {
  verbatimType    :: Maybe String,
  verbatimContent :: InlineText
} deriving Eq

data LinkContent
  = LCText  InlineText
  | LCImage InlineImage
  deriving Eq

data InlineLinkInternal = InlineLinkInternal {
  linkInternalTarget  :: ID.T,
  linkInternalContent :: [LinkContent]
} deriving Eq

data InlineLinkExternal = InlineLinkExternal {
  linkExternalTarget  :: URI.T,
  linkExternalContent :: [LinkContent]
} deriving Eq

data ListItem = ListItem {
  listItemContent :: [InlineContent]
} deriving Eq

data InlineListOrdered = InlineListOrdered {
  listOrderedItems :: [ListItem]
} deriving Eq

data InlineListUnordered = InlineListUnordered {
  listUnorderedItems :: [ListItem]
} deriving Eq

data InlineFootnoteRef = InlineFootnoteRef {
  footnoteTarget :: ID.T
} deriving Eq

type TableColumnName = [InlineText]

data TableHead = TableHead {
  tableHeadNames :: [TableColumnName]
} deriving Eq

data TableCell = TableCell {
  tableCellContent :: [TableCellContent]
} deriving Eq

data TableCellContent
  = TCText          InlineText
  | TCTerm          InlineTerm
  | TCImage         InlineImage
  | TCVerbatim      InlineVerbatim
  | TCLink          InlineLinkInternal
  | TCLinkExternal  InlineLinkExternal
  | TCListOrdered   InlineListOrdered
  | TCListUnordered InlineListUnordered
  | TCFootnoteRef   InlineFootnoteRef
  | TCInclude       InlineInclude
  deriving Eq

data TableRow = TableRow {
  tableRowCells :: [TableCell]
} deriving Eq

data TableBody = TableBody {
  tableBodyRows :: [TableRow]
} deriving Eq

data InlineTable = InlineTable {
  tableType    :: Maybe String,
  tableSummary :: [InlineText],
  tableHead    :: Maybe TableHead,
  tableBody    :: TableBody
} deriving Eq

tableCheck :: InlineTable -> Bool
tableCheck table =
  case (tableHead table) of
    Nothing -> True
    Just th ->
      let rows     = tableBodyRows $ tableBody table
          expected = length $ tableHeadNames th
      in all (\row -> length (tableRowCells row) == expected) rows

data InlineInclude = InlineInclude {
  includeFile :: String
} deriving Eq

data InlineContent
  = ICText          InlineText
  | ICTerm          InlineTerm
  | ICImage         InlineImage
  | ICVerbatim      InlineVerbatim
  | ICLink          InlineLinkInternal
  | ICLinkExternal  InlineLinkExternal
  | ICListOrdered   InlineListOrdered
  | ICListUnordered InlineListUnordered
  | ICFootnoteRef   InlineFootnoteRef
  | ICTable         InlineTable
  | ICInclude       InlineInclude
  deriving Eq
Block Content
Overview
A block value denotes a significant section of content within a document.
ID
All block values have an optional id parameter that, if present, must be unique within a document. The value of this parameter may be used by link elements to create intra-document links to content.
Identifiers are restricted to combinations of letters, numbers, U+005F "_", U+002D "-", and U+002E ".".
id_character =
  ? p{IsLetter} | p{isNumber} | U+005F | U+002D | U+002E ? ;

id =
  id_character , { id_character } ;
An id value k is said to exist if there is exactly one element in the document d such that (hasID k d == Just k):
module IDExistence where

import qualified ID
import qualified BlockContent as BC
import qualified Control.Monad as CM

class HasID a where
  hasID :: ID.T -> a -> Maybe ID.T

maybeEq :: Eq a => a -> Maybe a -> Maybe a
maybeEq x Nothing  = Nothing
maybeEq x (Just y) = if x == y then Just y else Nothing

instance HasID BC.BlockParagraph where
  hasID k b = maybeEq k (BC.para_id b)

instance HasID BC.BlockFormalItem where
  hasID k b = maybeEq k (BC.formal_id b)

instance HasID BC.BlockFootnote where
  hasID k b = maybeEq k (Just $ BC.footnote_id b)

instance HasID BC.SubsectionContent where
  hasID k (BC.SCParagraph b)  = hasID k b
  hasID k (BC.SCFormalItem b) = hasID k b
  hasID k (BC.SCFootnote b)   = hasID k b

instance HasID BC.BlockSubsection where
  hasID k b =
    case maybeEq k (BC.subsection_id b) of
      Just x  -> Just k
      Nothing -> CM.foldM hasID k (BC.subsection_content b)

instance HasID BC.BlockSection where
  hasID k b =
    case maybeEq k (BC.section_id b) of
      Just x  -> Just k
      Nothing ->
        case BC.section_content b of
          Left ss  -> CM.foldM hasID k ss
          Right sc -> CM.foldM hasID k sc

instance HasID BC.BlockPart where
  hasID k b =
    case maybeEq k (BC.part_id b) of
      Just x  -> Just k
      Nothing -> CM.foldM hasID k (BC.part_content b)

instance HasID BC.BlockDocument where
  hasID k b =
    case maybeEq k (BC.document_id b) of
      Just x  -> Just k
      Nothing ->
        case BC.document_content b of
          Left p  -> CM.foldM hasID k p
          Right s -> CM.foldM hasID k s
Implementations are required to check that all id values are unique within a document, and that all id values referenced by links within a document exist.
Paragraph
A paragraph is one of the lowest level block values in terms of structural significance. It is simply a container for inline content.
data BlockParagraph = BlockParagraph {
  para_type    :: Maybe String,
  para_id      :: Maybe ID.T,
  para_content :: [I.InlineContent]
}
Formal Item
A formal-item is similar to a paragraph except that it has an explicit title.
data BlockFormalItem = BlockFormalItem {
  formal_type    :: Maybe String,
  formal_id      :: Maybe ID.T,
  formal_title   :: [I.InlineText],
  formal_content :: [I.InlineContent]
}
Footnote
A footnote is similar to a paragraph except that it denotes content that should appear as supplemental information at the bottom of a page when the document is processed for presentation.
A footnote must have an id value specified, and may be referenced by any number of footnote-ref values.
data BlockFootnote = BlockFootnote {
  footnote_type    :: Maybe String,
  footnote_id      :: ID.T,
  footnote_content :: [I.InlineContent]
}
Subsection
A subsection is a container for subsection content. A subsection is required to have a title.
data SubsectionContent
  = SCParagraph  BlockParagraph
  | SCFormalItem BlockFormalItem
  | SCFootnote   BlockFootnote

data BlockSubsection = BlockSubsection {
  subsection_type    :: Maybe String,
  subsection_id      :: Maybe ID.T,
  subsection_title   :: [I.InlineText],
  subsection_content :: [SubsectionContent]
}
Section
A section is a container for either subsection content, or subsections, but not both at the same time. A section is required to have a title.
data BlockSection = BlockSection {
  section_type    :: Maybe String,
  section_id      :: Maybe ID.T,
  section_title   :: [I.InlineText],
  section_content :: Either [BlockSubsection] [SubsectionContent]
}
Part
A part is a container for sections. A part is required to have a title.
data BlockPart = BlockPart {
  part_type    :: Maybe String,
  part_id      :: Maybe ID.T,
  part_title   :: [I.InlineText],
  part_content :: [BlockSection]
}
Document
A document is the top-level container of other content. It may contain a list of parts, or a list of sections, but not both. A document is required to have a title.
data BlockDocument = BlockDocument {
  document_type    :: Maybe String,
  document_id      :: Maybe ID.T,
  document_title   :: [I.InlineText],
  document_content :: Either [BlockPart] [BlockSection]
}
Import
An import is somewhat analogous to the inline include type, except that the referenced file is actually parsed as a structural block value and inserted into the current document at the location of the import value.
data BlockImport = BlockImport {
  importFile :: String
}
Canonical Format
Overview
The structural language defines a number of different concrete syntaxes used to produce values of the types defined by the model. The primary canonical syntax is based on s-expressions.
Inline Elements
Overview
canon_inline =
  (#choice [
    canon_footnote_ref
    canon_image
    canon_include
    canon_link
    canon_link_external
    canon_list_ordered
    canon_list_unordered
    canon_term
    canon_text
    canon_verbatim
  ])
Text
The concrete syntax specified here maps text to values of the InlineText type. Most contexts in documents that accept text can also accept include values, so an additional rule is given here that allows choosing between values of the two types.
canon_text =
  (#choice [#any-symbol #any-quoted])

canon_text_or_include =
  (#choice [canon_text canon_include])
Term
The concrete syntax specified here maps text to values of the InlineTerm type.
canon_type =
  (#exact-list [#exact-symbol "type"] #any-symbol)

canon_term_name =
  (#exact-symbol "term")

canon_term =
  (#choice [
    (#variadic [canon_term_name] canon_text_or_include)
    (#variadic [canon_term_name canon_type] canon_text_or_include)
  ])
Image
The concrete syntax specified here maps text to values of the InlineImage type.
canon_target =
  (#exact-list [#exact-symbol "target"] canon_text)

canon_size =
  (#exact-list [#exact-symbol "size"] #any-symbol #any-symbol)

canon_image_name =
  (#exact-symbol "image")

canon_image =
  (#choice [
    (#variadic [canon_image_name canon_target] canon_text_or_include)
    (#variadic [canon_image_name canon_target canon_type] canon_text_or_include)
    (#variadic [canon_image_name canon_target canon_size] canon_text_or_include)
    (#variadic [canon_image_name canon_target canon_size canon_type] canon_text_or_include)
  ])
Verbatim
The concrete syntax specified here maps text to values of the InlineVerbatim type.
canon_verbatim_name =
  (#exact-symbol "verbatim")

canon_verbatim =
  (#choice [
    (#exact-list [canon_verbatim_name canon_text_or_include])
    (#exact-list [canon_verbatim_name canon_type canon_text_or_include])
  ])
Link
The concrete syntax specified here maps text to values of the InlineLinkInternal type.
canon_link_name =
  (#exact-symbol "link")

canon_link =
  (#variadic [canon_link_name canon_target] canon_text_or_include)
Link External
The concrete syntax specified here maps text to values of the InlineLinkExternal type.
canon_link_external_name =
  (#exact-symbol "link-ext")

canon_link_external =
  (#variadic [canon_link_external_name canon_target] canon_text_or_include)
Footnote Reference
The concrete syntax specified here maps text to values of the InlineFootnoteRef type.
canon_footnote_ref_name =
  (#exact-symbol "footnote-ref")

canon_footnote_ref =
  (#exact-list canon_footnote_ref_name canon_text)
Ordered List
The concrete syntax specified here maps text to values of the InlineListOrdered type.
canon_list_item_name =
  (#exact-symbol "item")

canon_list_item =
  (#variadic [canon_list_item_name] canon_inline)

canon_list_ordered_name =
  (#exact-symbol "list-ordered")

canon_list_ordered =
  (#variadic [canon_list_ordered_name] canon_list_item)
Unordered List
The concrete syntax specified here maps text to values of the InlineListUnordered type.
canon_list_unordered_name =
  (#exact-symbol "list-unordered")

canon_list_unordered =
  (#variadic [canon_list_unordered_name] canon_list_item)
Table
The concrete syntax specified here maps text to values of the InlineTable type.
canon_table_name =
  (#exact-symbol "table")

canon_table_summary_name =
  (#exact-symbol "summary")

canon_table_summary =
  (#variadic [canon_table_summary_name] canon_text_or_include)

canon_table_body_cell_name =
  (#exact-symbol "cell")

canon_table_body_cell =
  (#variadic [canon_table_body_cell_name] canon_inline)

canon_table_body_row_name =
  (#exact-symbol "row")

canon_table_body_row =
  (#variadic [canon_table_body_row_name] canon_table_body_cell)

canon_table_body_name =
  (#exact-symbol "body")

canon_table_body =
  (#variadic [canon_table_body_name] canon_table_body_row)

canon_table_body_head_cell_name =
  (#exact-symbol "name")

canon_table_body_head_cell =
  (#variadic [canon_table_body_head_cell_name] canon_text)

canon_table_head_name =
  (#exact-symbol "head")

canon_table_head =
  (#variadic [canon_table_head_name] canon_table_head_cell)

canon_table =
  (#choice [
    (#exact-list [canon_table_name canon_table_summary cannon_table_body])
    (#exact-list [canon_table_name canon_table_summary canon_type cannon_table_body])
    (#exact-list [canon_table_name canon_table_summary cannon_table_head cannon_table_body])
    (#exact-list [canon_table_name canon_table_summary canon_type cannon_table_head cannon_table_body])
  ])
Include
The concrete syntax specified here maps text to values of the InlineInclude type.
canon_include_name =
  (#exact-symbol "include")

canon_include =
  (#exact-list [canon_include_name #any-quoted])
Block Elements
Paragraph
The concrete syntax specified here maps text to values of the BlockParagraph type.
canon_id_name =
  (#exact-symbol "id")

canon_id =
  (#exact-list [canon_id_name canon_text])

canon_paragraph_name =
  (#exact-symbol "paragraph")

canon_paragraph =
  (#choice [
    (#variadic [canon_paragraph_name] canon_inline)
    (#variadic [canon_paragraph_name canon_id] canon_inline)
    (#variadic [canon_paragraph_name canon_id canon_type] canon_inline)
    (#variadic [canon_paragraph_name canon_type canon_id] canon_inline)
    (#variadic [canon_paragraph_name canon_type] canon_inline)
  ])
Formal Item
The concrete syntax specified here maps text to values of the BlockFormalItem type.
canon_title_name =
  (#exact-symbol "title")

canon_title =
  (#variadic [canon_title_name] canon_text)

canon_formal_item_name =
  (#exact-symbol "formal-item")

canon_formal_item =
  (#choice [
    (#variadic [canon_formal_item_name canon_title] canon_inline)
    (#variadic [canon_formal_item_name canon_title canon_id] canon_inline)
    (#variadic [canon_formal_item_name canon_title canon_id canon_type] canon_inline)
    (#variadic [canon_formal_item_name canon_title canon_type canon_id] canon_inline)
    (#variadic [canon_formal_item_name canon_title canon_type] canon_inline)
  ])
Footnote
The concrete syntax specified here maps text to values of the BlockFootnote type.
canon_footnote_name =
  (#exact-symbol "footnote")

canon_footnote =
  (#choice [
    (#variadic [canon_footnote_name canon_id] canon_inline)
    (#variadic [canon_footnote_name canon_id canon_type] canon_inline)
  ])
Subsection
The concrete syntax specified here maps text to values of the BlockSubsection type.
canon_subsection_name =
  (#exact-symbol "subsection")

canon_subsection_content =
  (#choice [canon_paragraph canon_footnote canon_formal_item])

canon_subsection =
  (#choice [
    (#variadic [canon_subsection_name canon_title] canon_subsection_content)
    (#variadic [canon_subsection_name canon_title canon_id] canon_subsection_content)
    (#variadic [canon_subsection_name canon_title canon_id canon_type] canon_subsection_content)
    (#variadic [canon_subsection_name canon_title canon_type canon_id] canon_subsection_content)
    (#variadic [canon_subsection_name canon_title canon_type] canon_subsection_content)
  ])
Section
The concrete syntax specified here maps text to values of the BlockSection type.
canon_section_name =
  (#exact-symbol "section")

canon_section_content =
  (#choice [canon_subsection canon_subsection_content])

canon_section =
  (#choice [
    (#variadic [canon_section_name canon_title] canon_section_content)
    (#variadic [canon_section_name canon_title canon_id] canon_section_content)
    (#variadic [canon_section_name canon_title canon_id canon_type] canon_section_content)
    (#variadic [canon_section_name canon_title canon_type canon_id] canon_section_content)
    (#variadic [canon_section_name canon_title canon_type] canon_section_content)
  ])
Part
The concrete syntax specified here maps text to values of the BlockPart type.
canon_part_name =
  (#exact-symbol "part")

canon_part =
  (#choice [
    (#variadic [canon_part_name canon_title] canon_section)
    (#variadic [canon_part_name canon_title canon_id] canon_section)
    (#variadic [canon_part_name canon_title canon_id canon_type] canon_section)
    (#variadic [canon_part_name canon_title canon_type canon_id] canon_section)
    (#variadic [canon_part_name canon_title canon_type] canon_section)
  ])
Document
The concrete syntax specified here maps text to values of the BlockDocument type.
canon_document_name =
  (#exact-symbol "document")

canon_document_content =
  (#choice [canon_section canon_part])

canon_document =
  (#choice [
    (#variadic [canon_document_name canon_title] canon_document_content)
    (#variadic [canon_document_name canon_title canon_id] canon_document_content)
    (#variadic [canon_document_name canon_title canon_id canon_type] canon_document_content)
    (#variadic [canon_document_name canon_title canon_type canon_id] canon_document_content)
    (#variadic [canon_document_name canon_title canon_type] canon_document_content)
  ])
Import
The concrete syntax specified here maps text to values of the BlockImport type.
canon_import_name =
  (#exact-symbol "import")

canon_import =
  (#exact-list [canon_import_name canon_text])
Imperative Format
Overview
One observation of all document languages that present a tree-like structure and syntax is that the writer spends a certain amount of time managing the tree structure itself. Although s-expressions represent about the most lightweight syntax possible for representing trees directly, it's possible to reduce the syntactic overhead even further by allowing the author to progressively define trees using a series of imperative commands.
The so-called imperative syntax combines the inline elements from the canonical syntax with a set of imperative block commands.
Block Commands
Overview
An imperative command begins the construction of a new block. Any block currently under construction that is of lesser than or equal to structural significance is completed on receipt of the command (or on end-of-file), prior to beginning the construction of a new block. Inline content is supplied to blocks that accept it by simply including the content between commands:
[subsection [title An example subsection]]
[paragraph]
This is some content for the first paragraph.
[paragraph]
This is some [term [type emphasis] content] for the second paragraph.

[subsection [title Another example subsection]]
[paragraph]
This is some content for the first paragraph of the next section.
An imperative command may take one of the following forms:
data ImperativeContent
  = ICParagraph  ImperativeParagraph
  | ICFormalItem ImperativeFormalItem
  | ICFootnote   ImperativeFootnote
  | ICSubsection ImperativeSubsection
  | ICSection    ImperativeSection
  | ICPart       ImperativePart
  | ICDocument   ImperativeDocument
  | ICImport     ImperativeImport
  deriving Eq

Imperative commands create values of the types specified in the model, and therefore the same rules apply with regards to where blocks can be created. For example, it is an error (by the definition of the section type) to first create a subsection inside a section and then attempt to follow it with the definition of a paragraph.
Structural Significance
In order for the receipt of a command to complete the construction of a block that is already under construction, it is necessary to define an ordering on the structural significance of each of the block types.
instance Ord ImperativeContent where
  compare (ICParagraph _) (ICParagraph _)   = EQ
  compare (ICParagraph _) (ICFormalItem _)  = EQ
  compare (ICParagraph _) (ICFootnote _)    = EQ
  compare (ICParagraph _) (ICSubsection _)  = LT
  compare (ICParagraph _) (ICSection _)     = LT
  compare (ICParagraph _) (ICPart _)        = LT
  compare (ICParagraph _) (ICDocument _)    = LT
  compare (ICFormalItem _) (ICParagraph _)  = EQ
  compare (ICFormalItem _) (ICFormalItem _) = EQ
  compare (ICFormalItem _) (ICFootnote _)   = EQ
  compare (ICFormalItem _) (ICSubsection _) = LT
  compare (ICFormalItem _) (ICSection _)    = LT
  compare (ICFormalItem _) (ICPart _)       = LT
  compare (ICFormalItem _) (ICDocument _)   = LT
  compare (ICFootnote _) (ICParagraph _)  = EQ
  compare (ICFootnote _) (ICFormalItem _) = EQ
  compare (ICFootnote _) (ICFootnote _)   = EQ
  compare (ICFootnote _) (ICSubsection _) = LT
  compare (ICFootnote _) (ICSection _)    = LT
  compare (ICFootnote _) (ICPart _)       = LT
  compare (ICFootnote _) (ICDocument _)   = LT
  compare (ICSubsection _) (ICParagraph _)  = GT
  compare (ICSubsection _) (ICFormalItem _) = GT
  compare (ICSubsection _) (ICFootnote _)   = GT
  compare (ICSubsection _) (ICSubsection _) = EQ
  compare (ICSubsection _) (ICSection _)    = LT
  compare (ICSubsection _) (ICPart _)       = LT
  compare (ICSubsection _) (ICDocument _)   = LT
  compare (ICSection _) (ICParagraph _)  = GT
  compare (ICSection _) (ICFormalItem _) = GT
  compare (ICSection _) (ICFootnote _)   = GT
  compare (ICSection _) (ICSubsection _) = GT
  compare (ICSection _) (ICSection _)    = EQ
  compare (ICSection _) (ICPart _)       = LT
  compare (ICSection _) (ICDocument _)   = LT
  compare (ICPart _) (ICParagraph _)  = GT
  compare (ICPart _) (ICFormalItem _) = GT
  compare (ICPart _) (ICFootnote _)   = GT
  compare (ICPart _) (ICSubsection _) = GT
  compare (ICPart _) (ICSection _)    = GT
  compare (ICPart _) (ICPart _)       = EQ
  compare (ICPart _) (ICDocument _)   = LT
  compare (ICDocument _) (ICParagraph _)  = GT
  compare (ICDocument _) (ICFormalItem _) = GT
  compare (ICDocument _) (ICFootnote _)   = GT
  compare (ICDocument _) (ICSubsection _) = GT
  compare (ICDocument _) (ICSection _)    = GT
  compare (ICDocument _) (ICPart _)       = GT
  compare (ICDocument _) (ICDocument _)   = EQ
  compare (ICImport i) e = compare (importContent i) e
  compare e (ICImport i) = compare e (importContent i)
The importContent function is a function that maps import blocks to their imported content. This is a function of the actual language implementation and so is left undefined in this specification.
importContent :: ImperativeImport -> ImperativeContent
importContent _ = undefined

Paragraph
A paragraph command begins a new paragraph in the current context.
data ImperativeParagraph = ImperativeParagraph {
  para_type    :: Maybe String,
  para_id      :: Maybe ID.T
} deriving Eq
The concrete syntax for the command is as follows:
imperative_paragraph =
  (#choice [
    (#exact-list [canon_paragraph_name])
    (#exact-list [canon_paragraph_name canon_id])
    (#exact-list [canon_paragraph_name canon_id canon_type])
    (#exact-list [canon_paragraph_name canon_type canon_id])
    (#exact-list [canon_paragraph_name canon_type])
  ])
Formal Item
A formal-item command begins a new formal item in the current context.
data ImperativeFormalItem = ImperativeFormalItem {
  formal_type  :: Maybe String,
  formal_id    :: Maybe ID.T,
  formal_title :: [I.InlineText]
} deriving Eq
The concrete syntax for the command is as follows:
imperative_formal_item =
  (#choice [
    (#exact-list [canon_formal_item_name canon_title])
    (#exact-list [canon_formal_item_name canon_title canon_id])
    (#exact-list [canon_formal_item_name canon_title canon_id canon_type])
    (#exact-list [canon_formal_item_name canon_title canon_type canon_id])
    (#exact-list [canon_formal_item_name canon_title canon_type])
  ])
Footnote
A footnote command begins a new footnote in the current context.
data ImperativeFootnote = ImperativeFootnote {
  footnote_type :: Maybe String,
  footnote_id   :: ID.T
} deriving Eq
The concrete syntax for the command is as follows:
imperative_footnote =
  (#choice [
    (#exact-list [canon_footnote_name canon_id])
    (#exact-list [canon_footnote_name canon_id canon_type])
  ])
Subsection
A subsection command begins a new subsection in the current context.
data ImperativeSubsection = ImperativeSubsection {
  subsection_type  :: Maybe String,
  subsection_id    :: Maybe ID.T,
  subsection_title :: [I.InlineText]
} deriving Eq
The concrete syntax for the command is as follows:
imperative_subsection =
  (#choice [
    (#exact-list [canon_subsection_name canon_title])
    (#exact-list [canon_subsection_name canon_title canon_id])
    (#exact-list [canon_subsection_name canon_title canon_id canon_type])
    (#exact-list [canon_subsection_name canon_title canon_type canon_id])
    (#exact-list [canon_subsection_name canon_title canon_type])
  ])
Section
A section command begins a new section in the current context.
data ImperativeSection = ImperativeSection {
  section_type  :: Maybe String,
  section_id    :: Maybe ID.T,
  section_title :: [I.InlineText]
} deriving Eq
The concrete syntax for the command is as follows:
imperative_section =
  (#choice [
    (#exact-list [canon_section_name canon_title])
    (#exact-list [canon_section_name canon_title canon_id])
    (#exact-list [canon_section_name canon_title canon_id canon_type])
    (#exact-list [canon_section_name canon_title canon_type canon_id])
    (#exact-list [canon_section_name canon_title canon_type])
  ])
Part
A part command begins a new part in the current context.
data ImperativePart = ImperativePart {
  part_type  :: Maybe String,
  part_id    :: Maybe ID.T,
  part_title :: [I.InlineText]
} deriving Eq
The concrete syntax for the command is as follows:
imperative_part =
  (#choice [
    (#exact-list [canon_part_name canon_title])
    (#exact-list [canon_part_name canon_title canon_id])
    (#exact-list [canon_part_name canon_title canon_id canon_type])
    (#exact-list [canon_part_name canon_title canon_type canon_id])
    (#exact-list [canon_part_name canon_title canon_type])
  ])
Document
A document command begins a new document in the current context.
data ImperativeDocument = ImperativeDocument {
  document_type  :: Maybe String,
  document_id    :: Maybe ID.T,
  document_title :: [I.InlineText]
} deriving Eq
The concrete syntax for the command is as follows:
imperative_document =
  (#choice [
    (#exact-list [canon_document_name canon_title])
    (#exact-list [canon_document_name canon_title canon_id])
    (#exact-list [canon_document_name canon_title canon_id canon_type])
    (#exact-list [canon_document_name canon_title canon_type canon_id])
    (#exact-list [canon_document_name canon_title canon_type])
  ])
XML Format
Overview
The XML format is defined as a simple encoding of the canonical format as XML. Instead of include and import elements, the user is expected to use XInclude.
RELAX-NG Schema
<?xml version="1.0" encoding="UTF-8"?>
<r:grammar
  xmlns:s="http://schemas.io7m.com/structural/3.0.0"
  xmlns:r="http://relaxng.org/ns/structure/1.0"
  datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

  <r:start combine="choice">
    <r:ref name="io7m.structural-3_0_0.block_content"/>
  </r:start>

  <r:define name="io7m.structural-3_0_0.xml-id">
    <r:attribute name="xml:id">
      <r:data type="ID"/>
    </r:attribute>
  </r:define>

  <r:define name="io7m.structural-3_0_0.standard-attributes">
    <r:optional>
      <r:attribute name="xml:base">
        <r:text/>
      </r:attribute>
    </r:optional>
    <r:optional>
      <r:attribute name="xml:lang">
        <r:text/>
      </r:attribute>
    </r:optional>
    <r:optional>
      <r:attribute name="s:type">
        <r:data type="token"/>
      </r:attribute>
    </r:optional>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_text">
    <r:text/>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_footnote_ref">
    <r:element name="s:footnote-ref">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:attribute name="s:target">
        <r:data type="IDREF"/>
      </r:attribute>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_term">
    <r:element name="s:term">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_text"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_verbatim">
    <r:element name="s:verbatim">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_text"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_image">
    <r:element name="s:image">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:attribute name="s:target">
        <r:data type="anyURI"/>
      </r:attribute>
      <r:optional>
        <r:attribute name="s:width">
          <r:data type="positiveInteger"/>
        </r:attribute>
        <r:attribute name="s:height">
          <r:data type="positiveInteger"/>
        </r:attribute>
      </r:optional>
      <r:text/>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.list_item">
    <r:element name="s:item">
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_list_ordered">
    <r:element name="s:list-ordered">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.list_item"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_list_unordered">
    <r:element name="s:list-unordered">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.list_item"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.table_head_column_name">
    <r:element name="s:name">
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_text"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.table_head">
    <r:element name="s:head">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.table_head_column_name"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.table_body_cell">
    <r:element name="s:cell">
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.table_body_row">
    <r:element name="s:row">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.table_body_cell"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.table_body">
    <r:element name="s:body">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.table_body_row"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_table">
    <r:element name="s:table">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:attribute name="s:summary">
        <r:text/>
      </r:attribute>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.table_head"/>
      </r:optional>
      <r:ref name="io7m.structural-3_0_0.table_body"/>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.link_content">
    <r:choice>
      <r:ref name="io7m.structural-3_0_0.inline_text"/>
      <r:ref name="io7m.structural-3_0_0.inline_image"/>
    </r:choice>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_link">
    <r:element name="s:link">
      <r:attribute name="s:target">
        <r:data type="IDREF"/>
      </r:attribute>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.link_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_link_external">
    <r:element name="s:link-external">
      <r:attribute name="s:target">
        <r:data type="anyURI"/>
      </r:attribute>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.link_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.inline_content">
    <r:choice>
      <r:ref name="io7m.structural-3_0_0.inline_footnote_ref"/>
      <r:ref name="io7m.structural-3_0_0.inline_image"/>
      <r:ref name="io7m.structural-3_0_0.inline_link"/>
      <r:ref name="io7m.structural-3_0_0.inline_link_external"/>
      <r:ref name="io7m.structural-3_0_0.inline_list_ordered"/>
      <r:ref name="io7m.structural-3_0_0.inline_list_unordered"/>
      <r:ref name="io7m.structural-3_0_0.inline_table"/>
      <r:ref name="io7m.structural-3_0_0.inline_term"/>
      <r:ref name="io7m.structural-3_0_0.inline_text"/>
      <r:ref name="io7m.structural-3_0_0.inline_verbatim"/>
    </r:choice>
  </r:define>

  <r:define name="io7m.structural-3_0_0.subsection_content">
    <r:choice>
      <r:ref name="io7m.structural-3_0_0.footnote"/>
      <r:ref name="io7m.structural-3_0_0.formal_item"/>
      <r:ref name="io7m.structural-3_0_0.paragraph"/>
    </r:choice>
  </r:define>

  <r:define name="io7m.structural-3_0_0.paragraph">
    <r:element name="s:paragraph">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.xml-id"/>
      </r:optional>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.formal_item">
    <r:element name="s:formal-item">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.xml-id"/>
      </r:optional>
      <r:attribute name="s:title">
        <r:text/>
      </r:attribute>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.footnote">
    <r:element name="s:footnote">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:ref name="io7m.structural-3_0_0.xml-id"/>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.inline_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.document">
    <r:element name="s:document">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.xml-id"/>
      </r:optional>
      <r:attribute name="s:title">
        <r:text/>
      </r:attribute>
      <r:choice>
        <r:zeroOrMore>
          <r:ref name="io7m.structural-3_0_0.part"/>
        </r:zeroOrMore>
        <r:zeroOrMore>
          <r:ref name="io7m.structural-3_0_0.section"/>
        </r:zeroOrMore>
      </r:choice>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.part">
    <r:element name="s:part">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.xml-id"/>
      </r:optional>
      <r:attribute name="s:title">
        <r:text/>
      </r:attribute>
      <r:choice>
        <r:zeroOrMore>
          <r:ref name="io7m.structural-3_0_0.section"/>
        </r:zeroOrMore>
      </r:choice>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.section">
    <r:element name="s:section">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.xml-id"/>
      </r:optional>
      <r:attribute name="s:title">
        <r:text/>
      </r:attribute>
      <r:choice>
        <r:zeroOrMore>
          <r:ref name="io7m.structural-3_0_0.subsection"/>
        </r:zeroOrMore>
        <r:zeroOrMore>
          <r:ref name="io7m.structural-3_0_0.subsection_content"/>
        </r:zeroOrMore>
      </r:choice>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.subsection">
    <r:element name="s:subsection">
      <r:ref name="io7m.structural-3_0_0.standard-attributes"/>
      <r:optional>
        <r:ref name="io7m.structural-3_0_0.xml-id"/>
      </r:optional>
      <r:attribute name="s:title">
        <r:text/>
      </r:attribute>
      <r:zeroOrMore>
        <r:ref name="io7m.structural-3_0_0.subsection_content"/>
      </r:zeroOrMore>
    </r:element>
  </r:define>

  <r:define name="io7m.structural-3_0_0.block_content">
    <r:choice>
      <r:ref name="io7m.structural-3_0_0.document"/>
      <r:ref name="io7m.structural-3_0_0.paragraph"/>
      <r:ref name="io7m.structural-3_0_0.part"/>
      <r:ref name="io7m.structural-3_0_0.subsection"/>
      <r:ref name="io7m.structural-3_0_0.section"/>
      <r:ref name="io7m.structural-3_0_0.footnote"/>
      <r:ref name="io7m.structural-3_0_0.formal_item"/>
    </r:choice>
  </r:define>

</r:grammar>