# ========================================================= # # (c) 2004, RenderX # # Author: Alexander Peshkov # # 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)*