| # ========================================================= |
| # |
| # (c) 2004, RenderX |
| # |
| # Author: Alexander Peshkov <peshkov@renderx.com> |
| # |
| # Permission is granted to use this document, copy and |
| # modify free of charge, provided that every derived work |
| # bear a reference to the present document. |
| # |
| # This document contains a computer program written in |
| # XSL Transformations Language. It is published with no |
| # warranty of any kind about its usability, as a mere |
| # example of XSL technology. RenderX shall not be |
| # considered liable for any damage or loss of data caused |
| # by use of this program. |
| # |
| # ========================================================= |
| |
| namespace local = "" |
| default namespace fo = "http://www.w3.org/1999/XSL/Format" |
| namespace rx = "http://www.renderx.com/XSL/Extensions" |
| |
| include "properties.rnc" |
| |
| # **************************************************************************************** |
| # Common content models used by content-bearing elements |
| # **************************************************************************************** |
| very-basic-inlines = |
| character |
| | external-graphic |
| | instream-foreign-object |
| | inline-container |
| | leader |
| | page-number |
| | page-number-citation |
| | multi-toggle #MEMO: To be strict, we have to control that this element is a descendant of an fo:multi-case. |
| | page-index |
| | begin-index-range |
| | end-index-range |
| |
| #NOTE: An absolute-container can be treated both as block and as outline. |
| basic-blocks = |
| block | block-container | table-and-caption | table | list-block |
| |
| #NOTE: Unlike other out-of-lines fo:footnote can be used only in the context where inlines are permitted |
| out-of-lines-block = before-float | side-float | absolute-container |
| out-of-lines = footnote | out-of-lines-block |
| |
| # As a compromise for intricated inline content model prescribed by XSL FO spec |
| # we define two types of inline content: |
| # first as restrictive as required by spec for descendants of an fo:leader or of an fo:inline |
| # child of an fo:footnote (and for some other cases where we believe it is reasonable), |
| # it permits inline level elements only, except for descendants of fo:inline-container; |
| # second as loose as prescribed by spec for the general cases |
| basic-inlines-inline = very-basic-inlines | basic-link-inline | inline-inline | bidi-override-inline |
| basic-inlines = very-basic-inlines | basic-link | inline | bidi-override |
| |
| # We have three content models for wrappers: |
| # first one allows inline content only (based on basic-inlines-inline described above); |
| # second one requires block-level elements to be at the top of it; |
| # third one is for mixed content (general case); |
| wrappers-inline = |
| multi-switch-inline | multi-properties-inline | wrapper-inline | retrieve-marker |
| wrappers-block = |
| multi-switch-block | multi-properties-block | wrapper-block | retrieve-marker |
| wrappers = |
| multi-switch | multi-properties | wrapper | retrieve-marker |
| |
| # We have two extended content models for inlines: |
| # first one is stricter, with inline elements only (exception for fo:inline-container descendants) |
| # and with no outlines (actually they are bared in main.rnc anyway); |
| # second one is loose, with all possible inlines and outlines. |
| # In general those content models corresponds very well with two possible contexts: |
| # block context and inline context |
| inlines-inline = text | basic-inlines-inline | wrappers-inline |
| inlines = text | basic-inlines | out-of-lines | wrappers |
| |
| # Content model for blocks including block-level outlines |
| blocks = basic-blocks | wrappers-block | out-of-lines-block |
| # Mixed content model - broadest one |
| mix = inlines | basic-blocks |
| |
| # **************************************************************************************** |
| # Element structure for content-bearing elements |
| # **************************************************************************************** |
| # =============================================================== |
| # Block is the base element for all content areas. |
| # =============================================================== |
| block = |
| element fo:block { |
| block.attlist, block.content |
| } |
| block.content = marker*, ( initial-property-set | mix )* |
| |
| # =============================================================== |
| # Block container |
| # =============================================================== |
| #MEMO: We are forced to create separate element 'absolute-container' in order |
| # to satisfy XSL FO spec requirements. Note that this is the *only* place where |
| # properties really interfer with element-level structure (well, actually fo:float is the second place). |
| # A separate fo:absolute-container is clearly necessary. |
| # Absolutely possitioned block-container cannot contain markers and and outlines. |
| # It's behaviour is quite similar to the outline elements such as float. |
| # 'Folint' do not control absolutely positioned container restriction |
| # (due to expressions that can result in absolute position) |
| # 'Folint' also permits empty block-containers, that is against the spec. |
| # Spec defines fo:block-container content as (%block;)+ |
| |
| absolute-container = notAllowed |
| absolute-container-real = |
| element fo:block-container { absolute-container.attlist, absolute-container.content } |
| absolute-container.content = blocks+ |
| |
| block-container = |
| element fo:block-container { block-container.attlist, block-container.content } |
| block-container.content = marker*, blocks+ |
| |
| # **************************************************************************************** |
| # Inline elements |
| # **************************************************************************************** |
| # =============================================================== |
| # Unicode bidi-override |
| # =============================================================== |
| #MEMO: According to spec this element CAN have block level children except for the cases listed below: |
| # XSL> An fo:bidi-override that is a descendant of an fo:leader or of an fo:inline child |
| # XSL> of an fo:footnote may not have block-level children, unless it has a nearer ancestor |
| # XSL> that is an fo:inline-container. |
| # NOTE: This is contradictory to the description of fo:leader element (6.6.9. fo:leader) that |
| # prohibits (some) block-level elements/outlines to be fo:leader descendants |
| # no matter if they wrapped in any fo:inline-containers and fo:bidi-override. |
| # We have two models: |
| # first (restrictive) used by descendants of an fo:title, fo:leader or of an fo:inline child of an fo:footnote; |
| # second (loose) as prescribed by spec for the general cases |
| # 'Folint' believes that no block level elements should be allowed in this element in either way. |
| bidi-override-inline = |
| element fo:bidi-override { bidi-override.attlist, bidi-override-inline.content } |
| bidi-override-inline.content = marker*, inlines-inline* |
| |
| bidi-override = |
| element fo:bidi-override { bidi-override.attlist, bidi-override.content } |
| bidi-override.content = marker*, mix* |
| |
| # =============================================================== |
| # Single character |
| # =============================================================== |
| character = element fo:character { character.attlist, empty } |
| |
| # =============================================================== |
| # Initial property set specifies properties for one or more lines |
| # =============================================================== |
| initial-property-set = |
| element fo:initial-property-set { |
| initial-property-set.attlist, empty |
| } |
| |
| # =============================================================== |
| # External graphic |
| # =============================================================== |
| external-graphic = |
| element fo:external-graphic { external-graphic.attlist, empty } |
| |
| # =============================================================== |
| # In-stream graphic |
| # =============================================================== |
| instream-foreign-object = |
| element fo:instream-foreign-object { |
| instream-foreign-object.attlist, any |
| } |
| |
| # =============================================================== |
| # Inline |
| # =============================================================== |
| #MEMO: This element used by content model that consists of inlines only |
| # with exception for descendants of inline-container |
| inline-inline = element fo:inline { inline.attlist, inline-inline.content } |
| inline-inline.content = marker*, inlines-inline* |
| |
| inline = element fo:inline { inline.attlist, inline.content } |
| inline.content = marker*, mix* |
| |
| # XSL> An fo:inline that is a child of an fo:footnote may not have block-level children. |
| # XSL> An fo:inline that is a descendant of an fo:leader or of the fo:inline child of |
| # XSL> an fo:footnote may not have block-level children, unless it has a nearer |
| # XSL> ancestor that is an fo:inline-container. |
| #NOTE: This definition is contradictory to the one of the fo:leader since latter prohibits |
| # fo:inline-container as a descendant. But it's the definition of fo:leader that should be fixed |
| # since content model described above is the only sane content model in the inline context. |
| # It should be the same for fo:bidi-override. However definition must be adjasted |
| # in order to mention fo:title since this element is a typical inline. |
| # |
| # 'Folint' believes that block elements are allowed here and thoroughly tests for |
| # all those tricky exceptions. This behavior seems to be quite inconsisten with the |
| # one regarding fo:bidi-override treatment. |
| |
| # =============================================================== |
| # Inline container |
| # =============================================================== |
| inline-container = |
| element fo:inline-container { inline-container.attlist, inline-container.content } |
| inline-container.content = marker*, blocks* |
| |
| # =============================================================== |
| # Leader |
| # =============================================================== |
| leader = element fo:leader { leader.attlist, leader.content } |
| leader.content = inlines-inline* |
| #MEMO: Following two lines used together with tricky redefinition in main.rnc |
| # in order to prevent fo:leader nesting. |
| #leader.content = notAllowed |
| #leader.content-real = inlines-inline* |
| |
| #MEMO: We use inline content model here which is consistent with |
| # such elements as fo:inline child of fo:footnote. It allows blocks/outlines, but only as a |
| # descendant of inline-container. XSL FO spec is quite uneven at this point (and should be fixed). |
| # According to spec, this element can contain inline level elements and text, but |
| # XSL> The content must not contain an fo:leader, fo:inline-container, fo:block-container, |
| # XSL> fo:float, fo:footnote, or fo:marker either as a direct child or as a descendant. |
| # NOTE: XSL FO spec DO NOT prohibit blocks or tables as descendants of fo:leader! |
| # NOTE: fo:leader constraints are contradictory to those of fo:inline since section "6.6.7. fo:inline" |
| # states implicitly that there could be an fo:inline-container that is a descendent of fo:leader. |
| # |
| # 'Folint' respects these constraints partially: it prohibits fo:block-container as a descendant, |
| # but permits fo:marker, fo:leader, fo:inline-container, fo:float, fo:footnote. |
| # It also prohibits use of fo:block as descendant. |
| |
| # =============================================================== |
| # Page Number |
| # =============================================================== |
| page-number = element fo:page-number { page-number.attlist, empty } |
| |
| # =============================================================== |
| # Page number citation |
| # =============================================================== |
| page-number-citation = |
| element fo:page-number-citation { |
| page-number-citation.attlist, empty |
| } |
| |
| # =============================================================== |
| # Atomic elements for index ranges markup |
| # =============================================================== |
| begin-index-range = |
| element rx:begin-index-range { begin-index-range.attlist, empty } |
| |
| end-index-range = |
| element rx:end-index-range { end-index-range.attlist, empty } |
| |
| # =============================================================== |
| # Page number list - index entry |
| # =============================================================== |
| page-index = element rx:page-index { page-index.attlist, page-index.content } |
| #MEMO: Currently page-index must contain at least one rx:index-item element, |
| # empty content is allowed for backward compatibility. |
| page-index.content = index-item* |
| |
| index-item = element rx:index-item { index-item.attlist, empty } |
| |
| # **************************************************************************************** |
| # Formatting objects for tables. |
| # **************************************************************************************** |
| |
| # =============================================================== |
| # Table & Caption is a wrapper to all the stuff pertinent to a |
| # given table. It generates a block consisting of two subblocks: |
| # one for the caption, another one for the table itself. The |
| # placement of these two blocks is controlled by the |
| # 'caption-side' property: if caption-side="before"|"after" (or |
| # their absolute orientation equivalents), the two blocks are |
| # drawn one after another; if it is "start"|"end", then the |
| # caption is displayed on the correspondent side of the table. |
| # In this case, the relative alignment of the two blocks is given |
| # by the 'relative-align'/'display-align' property. |
| # |
| # =============================================================== |
| table-and-caption = |
| element fo:table-and-caption { |
| table-and-caption.attlist, |
| table-and-caption.content |
| } |
| table-and-caption.content = marker*, table-caption?, table |
| |
| # =============================================================== |
| # Table caption is an area container. |
| # =============================================================== |
| table-caption = |
| element fo:table-caption { table-caption.attlist, table-caption.content } |
| table-caption.content = marker*, blocks+ |
| |
| # =============================================================== |
| # fo:table is the basic element for all tables. All the contents |
| # placed inside it is distributed over a single rectangular grid |
| # of rows and columns. |
| # =============================================================== |
| table = |
| element fo:table { |
| table.attlist, |
| table.content |
| } |
| table.content = |
| marker*, |
| table-column*, |
| table-header?, |
| table-footer?, |
| table-body+ |
| |
| # =============================================================== |
| # Table column specifies common properties to ascribe to all |
| # cells in a column *or a group of columns*. Note that, if both |
| # 'number-columns-repeated' and 'number-columns-spanned' exceed |
| # 1, the column counter is increased by 'number-columns-spanned'. |
| # it means that you only set properties for columns: |
| # 'column-number' |
| # 'column-number' + 'number-columns-spanned' |
| # 'column-number' + 2 * 'number-columns-spanned' |
| # and so on, leaving default properties for intermediate columns. |
| # =============================================================== |
| table-column = element fo:table-column { table-column.attlist, empty } |
| |
| # =============================================================== |
| # Table header, table footer, and table body are wrappers for |
| # groups of rows. They contain either one or more fo:table-rows, |
| # or one or more fo:table-cells; in the latter case, row breaks |
| # are specified in the cells by 'starts-row'/'ends-row'. |
| # All these elements are identical both in the content structure |
| # and in the attributes. |
| # =============================================================== |
| row-group = marker*, (table-row+ | table-cell+) |
| table-header = |
| element fo:table-header { table-header.attlist, table-header.content } |
| table-header.content = row-group |
| |
| table-footer = |
| element fo:table-footer { table-footer.attlist, table-footer.content } |
| table-footer.content = row-group |
| |
| table-body = element fo:table-body { table-body.attlist, table-body.content } |
| table-body.content = row-group |
| |
| # =============================================================== |
| # Table row. |
| # =============================================================== |
| table-row = element fo:table-row { table-row.attlist, table-row.content } |
| table-row.content = table-cell+ |
| #MEMO: We are more strict here, so this note is about 'Folint': |
| # 'Folint' permits empty fo:table-row, that is against the spec. |
| # XSL FO spec defines fo:table-row content as (table-cell+) |
| |
| # =============================================================== |
| # Table cell. |
| # =============================================================== |
| table-cell = element fo:table-cell { table-cell.attlist, table-cell.content } |
| table-cell.content = marker*, blocks+ |
| #MEMO: We are more strict here, so this note is about 'Folint': |
| # 'Folint' permits empty table-cells that is against the spec. Spec defines fo:table-cell |
| # content as (%block;)+ |
| # Note that 'Folint' is quite consistent regarding this matter - it simillary allows empty |
| # block-containers and table-rows |
| |
| # **************************************************************************************** |
| # Formatting objects for lists. |
| # **************************************************************************************** |
| # =============================================================== |
| # List block is a block, with some extra features to control the |
| # disposition of list items. |
| # =============================================================== |
| list-block = element fo:list-block { list-block.attlist, list-block.content } |
| list-block.content = marker*, list-item+ |
| |
| # =============================================================== |
| # List item is a coupling of item label and item body. |
| # =============================================================== |
| list-item = |
| element fo:list-item { |
| list-item.attlist, |
| list-item.content |
| } |
| list-item.content = marker*, list-item-label, list-item-body |
| |
| # =============================================================== |
| # List item label and list item body |
| # =============================================================== |
| list-item-label = |
| element fo:list-item-label { list-item-label.attlist, list-item-label.content } |
| list-item-label.content = marker*, blocks+ |
| |
| list-item-body = |
| element fo:list-item-body { list-item-body.attlist, list-item-body.content } |
| list-item-body.content = marker*, blocks+ |
| #MEMO: We are more strict here, so this note is about 'Folint': |
| # 'Folint' permits empty fo:list-item-label/body, that is clearly the spec. |
| # Spec defines fo:list-item-label/body content as (%block;)+ |
| |
| #**************************************************************************************** |
| # Out-of-lines. |
| #**************************************************************************************** |
| # =============================================================== |
| # Floats and footnotes resemble containers. Accordingly, we treat |
| # them as block sequences. |
| # =============================================================== |
| #MEMO: We do not allows absolutely positioned container as an outline descendant. |
| # 'Folint' is loose here - it do not check this condition. |
| #MEMO: We are forced to create two types of floats: side-floats and before-floats |
| # because they have different restrictions (side-floats can appear in static content, |
| # before-floats can't bear 'clear' property) |
| # NOTE: 'Folint' does not allows any floats inside absolutely positioned containers too. |
| side-float = notAllowed |
| side-float-real = element fo:float { side-float.attlist, float.content } |
| before-float = notAllowed |
| before-float-real = element fo:float { before-float.attlist, float.content } |
| float.content = blocks+ |
| |
| # XSL> It is an error if the fo:footnote occurs as a descendant of a flow that is not assigned |
| # XSL> to a region-body, or of an fo:block-container that generates absolutely positioned areas. |
| footnote = notAllowed |
| footnote-real = |
| element fo:footnote { footnote.attlist, footnote.content } |
| # XSL> An fo:inline that is a child of an fo:footnote may not have block-level children. |
| # XSL> An fo:inline that is a descendant of an fo:leader or of the fo:inline child of |
| # XSL> an fo:footnote may not have block-level children, unless it has a nearer |
| # XSL> ancestor that is an fo:inline-container. |
| # We do check here that first inline have no block-level children/descendants unlless |
| # they are wrapped into an inline-container. |
| # 'Folint' does the same. |
| footnote.content = inline-inline, footnote-body |
| |
| footnote-body = |
| element fo:footnote-body { footnote-body.attlist, footnote-body.content } |
| footnote-body.content = blocks+ |
| |
| # =============================================================== |
| # Simple link. From the formatting point of view, it's nothing |
| # but a regular inline sequence. |
| # =============================================================== |
| # This elment is for separate 'inline' content model |
| basic-link-inline = element fo:basic-link { basic-link.attlist, basic-link-inline.content } |
| basic-link-inline.content = marker*, inlines-inline* |
| |
| basic-link = element fo:basic-link { basic-link.attlist, basic-link.content } |
| basic-link.content = marker*, mix* |
| |
| # **************************************************************************************** |
| # Wrappers and Markers. |
| # **************************************************************************************** |
| # =============================================================== |
| # Wrapper. This may be useful but it seriously complicates validation of |
| # content models for blocks and inlines. |
| # =============================================================== |
| #There are 3 different kind of wrappers for different contexts |
| wrapper-inline = element fo:wrapper { wrapper.attlist, wrapper-inline.content } |
| wrapper-inline.content = marker*, inlines-inline* |
| |
| wrapper-block = element fo:wrapper { wrapper.attlist, wrapper-block.content } |
| wrapper-block.content = marker*, blocks* |
| |
| wrapper = element fo:wrapper { wrapper.attlist, wrapper.content } |
| wrapper.content = marker*, mix* |
| |
| # =============================================================== |
| # Marker. |
| # =============================================================== |
| marker = notAllowed |
| marker-real = element fo:marker { marker.attlist, marker.content } |
| marker.content = mix* |
| |
| # =============================================================== |
| # Marker retrieval. |
| # We are more strict here making retrieve-class-name attribute a mandatory, |
| # but marker with no retrieve-class-name is meaningless. |
| # =============================================================== |
| retrieve-marker = notAllowed |
| retrieve-marker-real = element fo:retrieve-marker { retrieve-marker.attlist, empty } |
| |
| # **************************************************************************************** |
| # Multistate stuff. |
| # All those elements are practically unused and XSL content model invloved is |
| # intricated. Therefor validation is not absolutely strict here. |
| # **************************************************************************************** |
| # =============================================================== |
| # Switch. This is a pure logical operator; no formatting may be |
| # conveyed through it. |
| # =============================================================== |
| #Thera are 3 different kind of multi-switch (because there are 3 kinds of multi-case) |
| multi-switch-inline = |
| element fo:multi-switch { multi-switch.attlist, multi-switch-inline.content } |
| multi-switch-inline.content = multi-case-inline+ |
| |
| multi-switch-block = |
| element fo:multi-switch { multi-switch.attlist, multi-switch-block.content } |
| multi-switch-block.content = multi-case-block+ |
| |
| multi-switch = |
| element fo:multi-switch { multi-switch.attlist, multi-switch.content } |
| multi-switch.content = multi-case+ |
| |
| # =============================================================== |
| # Single case. Block-level formatting may be conveyed. |
| # =============================================================== |
| #Thera are 3 different kind of multi-case (similar to fo:wrapper) |
| multi-case-inline = element fo:multi-case { multi-case.attlist, multi-case-inline.content } |
| multi-case-inline.content = inlines-inline* |
| |
| multi-case-block = element fo:multi-case { multi-case.attlist, multi-case-block.content } |
| multi-case-block.content = blocks* |
| |
| multi-case = element fo:multi-case { multi-case.attlist, multi-case.content } |
| multi-case.content = mix* |
| |
| # =============================================================== |
| # Toggle. This is a typical inline. |
| # =============================================================== |
| #MEMO: This element is only permitted as a descendant of an fo:multi-case. |
| multi-toggle = |
| element fo:multi-toggle { multi-toggle.attlist, multi-toggle.content } |
| multi-toggle.content = mix* |
| |
| # =============================================================== |
| # Multi-properties. |
| # =============================================================== |
| #Thera are 3 different kind of multi-properties (similar to fo:wrapper) |
| multi-properties-inline = |
| element fo:multi-properties { |
| multi-properties.attlist, multi-properties-inline.content |
| } |
| multi-properties-inline.content = multi-property-set+, wrapper-inline |
| |
| multi-properties-block = |
| element fo:multi-properties { |
| multi-properties.attlist, multi-properties-block.content |
| } |
| multi-properties-block.content = multi-property-set+, wrapper-block |
| |
| multi-properties = |
| element fo:multi-properties { |
| multi-properties.attlist, multi-properties.content |
| } |
| multi-properties.content = multi-property-set+, wrapper |
| |
| # =============================================================== |
| # Multi property set. |
| # =============================================================== |
| multi-property-set = |
| element fo:multi-property-set { multi-property-set.attlist, empty } |
| |
| # =============================================================== |
| # "Match anything" definition, used by fo:instream-foreign-object |
| # =============================================================== |
| #MEMO: Should we exclude elements which belongs to fo: namespace? |
| any = |
| (element * { |
| attribute * { text }*, |
| any |
| } |
| | text)* |