+The design of the detail XML format is not what one would end up with
+for describing pivot tables. This is because it is a special case
+of a much more general format (``visualization XML'' or ``VizML'')
+that can describe a wide range of visualizations. Most of this
+generality is overkill for tables, and so we end up with a funny
+subset of a general-purpose format.
+
+An XML Schema for VizML is available, distributed with SPSS binaries,
+under a nonfree license. It contains documentation that is
+occasionally helpful.
+
+This section describes the detail XML format using the same notation
+already used for the structure XML format (@pxref{SPV Structure Member
+Format}). See @file{src/output/spv/detail-xml.grammar} in the PSPP
+source tree for the full grammar that it uses for parsing.
+
+The important elements of the detail XML format are:
+
+@itemize @bullet
+@item
+Variables. @xref{SPV Detail Variable Elements}.
+
+@item
+Assignment of variables to axes. A variable can appear as columns, or
+rows, or layers. The @code{faceting} element and its sub-elements
+describe this assignment.
+
+@item
+Styles and other annotations.
+@end itemize
+
+This description is not detailed enough to write legacy tables.
+Instead, write tables in the light binary format.
+
+@menu
+* SPV Detail visualization Element::
+* SPV Detail Variable Elements::
+* SPV Detail extension Element::
+* SPV Detail graph Element::
+* SPV Detail location Element::
+* SPV Detail faceting Element::
+* SPV Detail facetLayout Element::
+* SPV Detail label Element::
+* SPV Detail setCellProperties Element::
+* SPV Detail setFormat Element::
+* SPV Detail interval Element::
+* SPV Detail style Element::
+* SPV Detail labelFrame Element::
+* SPV Detail Legacy Properties::
+@end menu
+
+@node SPV Detail visualization Element
+@subsection The @code{visualization} Element
+
+@example
+visualization
+ :creator
+ :date
+ :lang
+ :name
+ :style[style_ref]=ref style
+ :type
+ :version
+ :schemaLocation?
+=> visualization_extension?
+ userSource
+ (sourceVariable | derivedVariable)+
+ categoricalDomain?
+ graph
+ labelFrame[lf1]*
+ container?
+ labelFrame[lf2]*
+ style+
+ layerController?
+
+extension[visualization_extension]
+ :numRows=int?
+ :showGridline=bool?
+ :minWidthSet=(true)?
+ :maxWidthSet=(true)?
+=> EMPTY
+
+userSource :missing=(listwise | pairwise)? => EMPTY
+
+categoricalDomain => variableReference simpleSort
+
+simpleSort :method[sort_method]=(custom) => categoryOrder
+
+container :style=ref style => container_extension? location+ labelFrame*
+
+extension[container_extension] :combinedFootnotes=(true) => EMPTY
+
+layerController
+ :source=(tableData)
+ :target=ref label?
+=> EMPTY
+@end example
+
+The @code{visualization} element is the root of detail XML member. It
+has the following attributes:
+
+@defvr {Attribute} creator
+The version of the software that created this SPV file, as a string of
+the form @code{xxyyzz}, which represents software version xx.yy.zz,
+e.g.@: @code{160001} is version 16.0.1. The corpus includes major
+versions 16 through 19.
+@end defvr
+
+@defvr {Attribute} date
+The date on the which the file was created, as a string of the form
+@code{YYYY-MM-DD}.
+@end defvr
+
+@defvr {Attribute} lang
+The locale used for output, in Windows format, which is similar to the
+format used in Unix with the underscore replaced by a hyphen, e.g.@:
+@code{en-US}, @code{en-GB}, @code{el-GR}, @code{sr-Cryl-RS}.
+@end defvr
+
+@defvr {Attribute} name
+The title of the pivot table, localized to the output language.
+@end defvr
+
+@defvr {Attribute} style
+The base style for the pivot table. In every example in the corpus,
+the @code{style} element has no attributes other than @code{id}.
+@end defvr
+
+@defvr {Attribute} type
+A floating-point number. The meaning is unknown.
+@end defvr
+
+@defvr {Attribute} version
+The visualization schema version number. In the corpus, the value is
+one of 2.4, 2.5, 2.7, and 2.8.
+@end defvr
+
+The @code{userSource} element has no visible effect.
+
+The @code{extension} element as a child of @code{visualization} has
+the following attributes.
+
+@defvr {Attribute} numRows
+An integer that presumably defines the number of rows in the displayed
+pivot table.
+@end defvr
+
+@defvr {Attribute} showGridline
+Always set to @code{false} in the corpus.
+@end defvr
+
+@defvr {Attribute} minWidthSet
+@defvrx {Attribute} maxWidthSet
+Always set to @code{true} in the corpus.
+@end defvr
+
+The @code{extension} element as a child of @code{container} has the
+following attribute
+
+@defvr {Attribute} combinedFootnotes
+Meaning unknown.
+@end defvr
+
+The @code{categoricalDomain} and @code{simpleSort} elements have no
+visible effect.
+
+The @code{layerController} element has no visible effect.
+
+@node SPV Detail Variable Elements
+@subsection Variable Elements
+
+A ``variable'' in detail XML is a 1-dimensional array of data. Each
+element of the array may, independently, have string or numeric
+content. All of the variables in a given detail XML member either
+have the same number of elements or have zero elements.
+
+Two different elements define variables and their content:
+
+@table @code
+@item sourceVariable
+These variables' data comes from the associated @code{tableData.bin}
+member.
+
+@item derivedVariable
+These variables are defined in terms of a mapping function from a
+source variable, or they are empty.
+@end table
+
+A variable named @code{cell} always exists. This variable holds the
+data displayed in the table.
+
+Variables in detail XML roughly correspond to the dimensions in a
+light detail member. Each dimension has the following variables with
+stylized names, where @var{n} is a number for the dimension starting
+from 0:
+
+@table @code
+@item dimension@var{n}categories
+The dimension's leaf categories (@pxref{SPV Light Member Categories}).
+
+@item dimension@var{n}group0
+Present only if the dimension's categories are grouped, this variable
+holds the group labels for the categories. Grouping is inferred
+through adjacent identical labels. Categories that are not part of a
+group have empty-string data in this variable.
+
+@item dimension@var{n}group1
+Present only if the first-level groups are further grouped, this
+variable holds the labels for the second-level groups. There can be
+additional variables with further levels of grouping.
+
+@item dimension@var{n}
+An empty variable.
+@end table
+
+Determining the data for a (non-empty) variable is a multi-step
+process:
+
+@enumerate
+@item
+Draw initial data from its source, for a @code{sourceVariable}, or
+from another named variable, for a @code{derivedVariable}.
+
+@item
+Apply mappings from @code{valueMapEntry} elements within the
+@code{derivedVariable} element, if any.
+
+@item
+Apply mappings from @code{relabel} elements within a @code{format} or
+@code{stringFormat} element in the @code{sourceVariable} or
+@code{derivedVariable} element, if any.
+
+@item
+If the variable is a @code{sourceVariable} with a @code{labelVariable}
+attribute, and there were no mappings to apply in previous steps, then
+replace each element of the variable by the corresponding value in the
+label variable.
+@end enumerate
+
+A single variable's data can be modified in two of the steps, if both
+@code{valueMapEntry} and @code{relabel} are used. The following
+example from the corpus maps several integers to 2, then maps 2 in
+turn to the string ``Input'':
+
+@example
+<derivedVariable categorical="true" dependsOn="dimension0categories"
+ id="dimension0group0map" value="map(dimension0group0)">
+ <stringFormat>
+ <relabel from="2" to="Input"/>
+ <relabel from="10" to="Missing Value Handling"/>
+ <relabel from="14" to="Resources"/>
+ <relabel from="0" to=""/>
+ <relabel from="1" to=""/>
+ <relabel from="13" to=""/>
+ </stringFormat>
+ <valueMapEntry from="2;3;5;6;7;8;9" to="2"/>
+ <valueMapEntry from="10;11" to="10"/>
+ <valueMapEntry from="14;15" to="14"/>
+ <valueMapEntry from="0" to="0"/>
+ <valueMapEntry from="1" to="1"/>
+ <valueMapEntry from="13" to="13"/>
+</derivedVariable>
+@end example
+
+@menu
+* SPV Detail sourceVariable Element::
+* SPV Detail derivedVariable Element::
+* SPV Detail valueMapEntry Element::
+@end menu
+
+@node SPV Detail sourceVariable Element
+@subsubsection The @code{sourceVariable} Element
+
+@example
+sourceVariable
+ :id
+ :categorical=(true)
+ :source
+ :domain=ref categoricalDomain?
+ :sourceName
+ :dependsOn=ref sourceVariable?
+ :label?
+ :labelVariable=ref sourceVariable?
+=> variable_extension* (format | stringFormat)?
+@end example
+
+This element defines a variable whose data comes from the
+@file{tableData.bin} member that corresponds to this @file{.xml}.
+
+This element has the following attributes.
+
+@defvr {Attribute} id
+An @code{id} is always present because this element exists to be
+referenced from other elements.
+@end defvr
+
+@defvr {Attribute} categorical
+Always set to @code{true}.
+@end defvr
+
+@defvr {Attribute} source
+Always set to @code{tableData}, the @code{source-name} in the
+corresponding @file{tableData.bin} member (@pxref{SPV Legacy Member
+Metadata}).
+@end defvr
+
+@defvr {Attribute} sourceName
+The name of a variable within the source, corresponding to the
+@code{variable-name} in the @file{tableData.bin} member (@pxref{SPV
+Legacy Member Numeric Data}).
+@end defvr
+
+@defvr {Attribute} label
+The variable label, if any.
+@end defvr
+
+@defvr {Attribute} labelVariable
+The @code{variable-name} of a variable whose string values correspond
+one-to-one with the values of this variable and are suitable for use
+as value labels.
+@end defvr
+
+@defvr {Attribute} dependsOn
+This attribute doesn't affect the display of a table.
+@end defvr
+
+@node SPV Detail derivedVariable Element
+@subsubsection The @code{derivedVariable} Element
+
+@example
+derivedVariable
+ :id
+ :categorical=(true)
+ :value
+ :dependsOn=ref sourceVariable?
+=> variable_extension* (format | stringFormat)? valueMapEntry*
+@end example
+
+Like @code{sourceVariable}, this element defines a variable whose
+values can be used elsewhere in the visualization. Instead of being
+read from a data source, the variable's data are defined by a
+mathematical expression.
+
+This element has the following attributes.
+
+@defvr {Attribute} id
+An @code{id} is always present because this element exists to be
+referenced from other elements.
+@end defvr
+
+@defvr {Attribute} categorical
+Always set to @code{true}.
+@end defvr
+
+@defvr {Attribute} value
+An expression that defines the variable's value. In theory this could
+be an arbitrary expression in terms of constants, functions, and other
+variables, e.g.@: @math{(@var{var1} + @var{var2}) / 2}. In practice,
+the corpus contains only the following forms of expressions:
+
+@table @code
+@item constant(0)
+@itemx constant(@var{variable})
+All zeros. The reason why a variable is sometimes named is unknown.
+Sometimes the ``variable name'' has spaces in it.
+
+@item map(@var{variable})
+Transforms the values in the named @var{variable} using the
+@code{valueMapEntry}s contained within the element.
+@end table
+@end defvr
+
+@defvr {Attribute} dependsOn
+This attribute doesn't affect the display of a table.
+@end defvr
+
+@node SPV Detail valueMapEntry Element
+@subsubsection The @code{valueMapEntry} Element
+
+@example
+valueMapEntry :from :to => EMPTY
+@end example
+
+A @code{valueMapEntry} element defines a mapping from one or more
+values of a source expression to a target value. (In the corpus, the
+source expression is always just the name of a variable.) Each target
+value requires a separate @code{valueMapEntry}. If multiple source
+values map to the same target value, they can be combined or separate.
+
+In the corpus, all of the source and target values are integers.
+
+@code{valueMapEntry} has the following attributes.
+
+@defvr {Attribute} from
+A source value, or multiple source values separated by semicolons,
+e.g.@: @code{0} or @code{13;14;15;16}.
+@end defvr
+
+@defvr {Attribute} to
+The target value, e.g.@: @code{0}.
+@end defvr
+
+@node SPV Detail extension Element
+@subsection The @code{extension} Element
+
+This is a general-purpose ``extension'' element. Readers that don't
+understand a given extension should be able to safely ignore it. The
+attributes on this element, and their meanings, vary based on the
+context. Each known usage is described separately below. The current
+extensions use attributes exclusively, without any nested elements.
+
+@subsubheading @code{container} Parent Element
+
+@example
+extension[container_extension] :combinedFootnotes=(true) => EMPTY
+@end example
+
+With @code{container} as its parent element, @code{extension} has the
+following attributes.
+
+@defvr {Attribute} combinedFootnotes
+Always set to @code{true} in the corpus.
+@end defvr
+
+@subsubheading @code{sourceVariable} and @code{derivedVariable} Parent Element
+
+@example
+extension[variable_extension] :from :helpId => EMPTY
+@end example
+
+With @code{sourceVariable} or @code{derivedVariable} as its parent
+element, @code{extension} has the following attributes. A given
+parent element often contains several @code{extension} elements that
+specify the meaning of the source data's variables or sources, e.g.@:
+
+@example
+<extension from="0" helpId="corrected_model"/>
+<extension from="3" helpId="error"/>
+<extension from="4" helpId="total_9"/>
+<extension from="5" helpId="corrected_total"/>
+@end example
+
+More commonly they are less helpful, e.g.@:
+
+@example
+<extension from="0" helpId="notes"/>
+<extension from="1" helpId="notes"/>
+<extension from="2" helpId="notes"/>
+<extension from="5" helpId="notes"/>
+<extension from="6" helpId="notes"/>
+<extension from="7" helpId="notes"/>
+<extension from="8" helpId="notes"/>
+<extension from="12" helpId="notes"/>
+<extension from="13" helpId="no_help"/>
+<extension from="14" helpId="notes"/>
+@end example
+
+@defvr {Attribute} from
+An integer or a name like ``dimension0''.
+@end defvr
+
+@defvr {Attribute} helpId
+An identifier.
+@end defvr
+
+@node SPV Detail graph Element
+@subsection The @code{graph} Element
+
+@example
+graph
+ :cellStyle=ref style
+ :style=ref style
+=> location+ coordinates faceting facetLayout interval
+
+coordinates => EMPTY
+@end example
+
+@code{graph} has the following attributes.
+
+@defvr {Attribute} cellStyle
+@defvrx {Attribute} style
+Each of these is the @code{id} of a @code{style} element (@pxref{SPV
+Detail style Element}). The former is the default style for
+individual cells, the latter for the entire table.
+@end defvr
+
+@node SPV Detail location Element
+@subsection The @code{location} Element
+
+@example
+location
+ :part=(height | width | top | bottom | left | right)
+ :method=(sizeToContent | attach | fixed | same)
+ :min=dimension?
+ :max=dimension?
+ :target=ref (labelFrame | graph | container)?
+ :value?
+=> EMPTY
+@end example
+
+Each instance of this element specifies where some part of the table
+frame is located. All the examples in the corpus have four instances
+of this element, one for each of the parts @code{height},
+@code{width}, @code{left}, and @code{top}. Some examples in the
+corpus add a fifth for part @code{bottom}, even though it is not clear
+how all of @code{top}, @code{bottom}, and @code{height} can be honored
+at the same time. In any case, @code{location} seems to have little
+importance in representing tables; a reader can safely ignore it.
+
+@defvr {Attribute} part
+The part of the table being located.
+@end defvr
+
+@defvr {Attribute} method
+How the location is determined:
+
+@table @code
+@item sizeToContent
+Based on the natural size of the table. Observed only for
+parts @code{height} and @code{width}.
+
+@item attach
+Based on the location specified in @code{target}. Observed only for
+parts @code{top} and @code{bottom}.
+
+@item fixed
+Using the value in @code{value}. Observed only for parts @code{top},
+@code{bottom}, and @code{left}.
+
+@item same
+Same as the specified @code{target}. Observed only for part
+@code{left}.
+@end table
+@end defvr
+
+@defvr {Attribute} min
+Minimum size. Only observed with value @code{100pt}. Only observed
+for part @code{width}.
+@end defvr
+
+@defvr {Dependent} target
+Required when @code{method} is @code{attach} or @code{same}, not
+observed otherwise. This identifies an element to attach to.
+Observed with the ID of @code{title}, @code{footnote}, @code{graph},
+and other elements.
+@end defvr
+
+@defvr {Dependent} value
+Required when @code{method} is @code{fixed}, not observed otherwise.
+Observed values are @code{0%}, @code{0px}, @code{1px}, and @code{3px}
+on parts @code{top} and @code{left}, and @code{100%} on part
+@code{bottom}.
+@end defvr
+
+@node SPV Detail faceting Element
+@subsection The @code{faceting} Element
+
+@example
+faceting => layer[layers1]* cross layer[layers2]*
+
+cross => (unity | nest) (unity | nest)
+
+unity => EMPTY
+
+nest => variableReference[vars]+
+
+variableReference :ref=ref (sourceVariable | derivedVariable) => EMPTY
+
+layer
+ :variable=ref (sourceVariable | derivedVariable)
+ :value
+ :visible=bool?
+ :method[layer_method]=(nest)?
+ :titleVisible=bool?
+=> EMPTY
+@end example
+
+The @code{faceting} element describes the row, column, and layer
+structure of the table. Its @code{cross} child determines the row and
+column structure, and each @code{layer} child (if any) represents a
+layer. Layers may appear before or after @code{cross}.
+
+The @code{cross} element describes the row and column structure of the
+table. It has exactly two children, the first of which describes the
+table's columns and the second the table's rows. Each child is a
+@code{nest} element if the table has any dimensions along the axis in
+question, otherwise a @code{unity} element.
+
+A @code{nest} element contains of one or more dimensions listed from
+innermost to outermost, each represented by @code{variableReference}
+child elements. Each variable in a dimension is listed in order.
+@xref{SPV Detail Variable Elements}, for information on the variables
+that comprise a dimension.
+
+A @code{nest} can contain a single dimension, e.g.:
+
+@example
+<nest>
+ <variableReference ref="dimension0categories"/>
+ <variableReference ref="dimension0group0"/>
+ <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+@noindent
+A @code{nest} can contain multiple dimensions, e.g.:
+
+@example
+<nest>
+ <variableReference ref="dimension1categories"/>
+ <variableReference ref="dimension1group0"/>
+ <variableReference ref="dimension1"/>
+ <variableReference ref="dimension0categories"/>
+ <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+A @code{nest} may have no dimensions, in which case it still has one
+@code{variableReference} child, which references a
+@code{derivedVariable} whose @code{value} attribute is
+@code{constant(0)}. In the corpus, such a @code{derivedVariable} has
+@code{row} or @code{column}, respectively, as its @code{id}. This is
+equivalent to using a @code{unity} element in place of @code{nest}.
+
+A @code{variableReference} element refers to a variable through its
+@code{ref} attribute.
+
+Each @code{layer} element represents a dimension, e.g.:
+
+@example
+<layer value="0" variable="dimension0categories" visible="true"/>
+<layer value="dimension0" variable="dimension0" visible="false"/>
+@end example
+
+@noindent
+@code{layer} has the following attributes.
+
+@defvr {Attribute} variable
+Refers to a @code{sourceVariable} or @code{derivedVariable} element.
+@end defvr
+
+@defvr {Attribute} value
+The value to select. For a category variable, this is always
+@code{0}; for a data variable, it is the same as the @code{variable}
+attribute.
+@end defvr
+
+@defvr {Attribute} visible
+Whether the layer is visible. Generally, category layers are visible
+and data layers are not, but sometimes this attribute is omitted.
+@end defvr
+
+@defvr {Attribute} method
+When present, this is always @code{nest}.
+@end defvr
+
+@node SPV Detail facetLayout Element
+@subsection The @code{facetLayout} Element
+
+@example
+facetLayout => tableLayout setCellProperties[scp1]*
+ facetLevel+ setCellProperties[scp2]*
+
+tableLayout
+ :verticalTitlesInCorner=bool
+ :style=ref style?
+ :fitCells=(ticks both)?
+=> EMPTY
+@end example
+
+The @code{facetLayout} element and its descendants control styling for
+the table.
+
+Its @code{tableLayout} child has the following attributes
+
+@defvr {Attribute} verticalTitlesInCorner
+If true, in the absence of corner text, row headings will be displayed
+in the corner.
+@end defvr
+
+@defvr {Attribute} style
+Refers to a @code{style} element.
+@end defvr
+
+@defvr {Attribute} fitCells
+Meaning unknown.
+@end defvr
+
+@subsubheading The @code{facetLevel} Element
+
+@example
+facetLevel :level=int :gap=dimension? => axis
+
+axis :style=ref style => label? majorTicks
+
+majorTicks
+ :labelAngle=int
+ :length=dimension
+ :style=ref style
+ :tickFrameStyle=ref style
+ :labelFrequency=int?
+ :stagger=bool?
+=> gridline?
+
+gridline
+ :style=ref style
+ :zOrder=int
+=> EMPTY
+@end example
+
+Each @code{facetLevel} describes a @code{variableReference} or
+@code{layer}, and a table has one @code{facetLevel} element for
+each such element. For example, an SPV detail member that contains
+four @code{variableReference} elements and two @code{layer} elements
+will contain six @code{facetLevel} elements.
+
+In the corpus, @code{facetLevel} elements and the elements that they
+describe are always in the same order. The correspondence may also be
+observed in two other ways. First, one may use the @code{level}
+attribute, described below. Second, in the corpus, a
+@code{facetLevel} always has an @code{id} that is the same as the
+@code{id} of the element it describes with @code{_facetLevel}
+appended. One should not formally rely on this, of course, but it is
+usefully indicative.
+
+@defvr {Attribute} level
+A 1-based index into the @code{variableReference} and @code{layer}
+elements, e.g.@: a @code{facetLayout} with a @code{level} of 1
+describes the first @code{variableReference} in the SPV detail member,
+and in a member with four @code{variableReference} elements, a
+@code{facetLayout} with a @code{level} of 5 describes the first
+@code{layer} in the member.
+@end defvr
+
+@defvr {Attribute} gap
+Always observed as @code{0pt}.
+@end defvr
+
+Each @code{facetLevel} contains an @code{axis}, which in turn may
+contain a @code{label} for the @code{facetLevel} (@pxref{SPV Detail
+label Element}) and does contain a @code{majorTicks} element.
+
+@defvr {Attribute} labelAngle
+Normally 0. The value -90 causes inner column or outer row labels to
+be rotated vertically.
+@end defvr
+
+@defvr {Attribute} style
+@defvrx {Attribute} tickFrameStyle
+Each refers to a @code{style} element. @code{style} is the style of
+the tick labels, @code{tickFrameStyle} the style for the frames around
+the labels.
+@end defvr
+
+@node SPV Detail label Element
+@subsection The @code{label} Element
+
+@example
+label
+ :style=ref style
+ :textFrameStyle=ref style?
+ :purpose=(title | subTitle | subSubTitle | layer | footnote)?
+=> text+ | descriptionGroup
+
+descriptionGroup
+ :target=ref faceting
+ :separator?
+=> (description | text)+
+
+description :name=(variable | value) => EMPTY
+
+text
+ :usesReference=int?
+ :definesReference=int?
+ :position=(subscript | superscript)?
+ :style=ref style
+=> TEXT
+@end example
+
+This element represents a label on some aspect of the table.
+
+@defvr {Attribute} style
+@defvrx {Attribute} textFrameStyle
+Each of these refers to a @code{style} element. @code{style} is the
+style of the label text, @code{textFrameStyle} the style for the frame
+around the label.
+@end defvr
+
+@defvr {Attribute} purpose
+The kind of entity being labeled.
+@end defvr
+
+A @code{descriptionGroup} concatenates one or more elements to form a
+label. Each element can be a @code{text} element, which contains
+literal text, or a @code{description} element that substitutes a value
+or a variable name.
+
+@defvr {Attribute} target
+The @code{id} of an element being described. In the corpus, this is
+always @code{faceting}.
+@end defvr
+
+@defvr {Attribute} separator
+A string to separate the description of multiple groups, if the
+@code{target} has more than one. In the corpus, this is always a
+new-line.
+@end defvr
+
+Typical contents for a @code{descriptionGroup} are a value by itself:
+@example
+<description name="value"/>
+@end example
+@noindent or a variable and its value, separated by a colon:
+@example
+<description name="variable"/><text>:</text><description name="value"/>
+@end example
+
+A @code{description} is like a macro that expands to some property of
+the target of its parent @code{descriptionGroup}. The @code{name}
+attribute specifies the property.
+
+@node SPV Detail setCellProperties Element
+@subsection The @code{setCellProperties} Element
+
+@example
+setCellProperties
+ :applyToConverse=bool?
+=> (setStyle | setFrameStyle | setFormat | setMetaData)* union[union_]?
+@end example
+
+The @code{setCellProperties} element sets style properties of cells or
+row or column labels.
+
+Interpreting @code{setCellProperties} requires answering two
+questions: which cells or labels to style, and what styles to use.
+
+@subsubheading Which Cells?
+
+@example
+union => intersect+
+
+intersect => where+ | intersectWhere | alternating | EMPTY
+
+where
+ :variable=ref (sourceVariable | derivedVariable)
+ :include
+=> EMPTY
+
+intersectWhere
+ :variable=ref (sourceVariable | derivedVariable)
+ :variable2=ref (sourceVariable | derivedVariable)
+=> EMPTY
+
+alternating => EMPTY
+@end example
+
+When @code{union} is present with @code{intersect} children, each of
+those children specifies a group of cells that should be styled, and
+the total group is all those cells taken together. When @code{union}
+is absent, every cell is styled. One attribute on
+@code{setCellProperties} affects the choice of cells:
+
+@defvr {Attribute} applyToConverse
+If true, this inverts the meaning of the cell selection: the selected
+cells are the ones @emph{not} designated. This is confusing, given
+the additional restrictions of @code{union}, but in the corpus
+@code{applyToConverse} is never present along with @code{union}.
+@end defvr
+
+An @code{intersect} specifies restrictions on the cells to be matched.
+Each @code{where} child specifies which values of a given variable to
+include. The attributes of @code{intersect} are:
+
+@defvr {Attribute} variable
+Refers to a variable, e.g.@: @code{dimension0categories}. Only
+``categories'' variables make sense here, but other variables, e.g.@:
+@code{dimension0group0map}, are sometimes seen. The reader may ignore
+these.
+@end defvr
+
+@defvr {Attribute} include
+A value, or multiple values separated by semicolons,
+e.g.@: @code{0} or @code{13;14;15;16}.
+@end defvr
+
+PSPP ignores @code{setCellProperties} when @code{intersectWhere} is
+present.
+
+@subsubheading What Styles?
+
+@example
+setStyle
+ :target=ref (labeling | graph | interval | majorTicks)
+ :style=ref style
+=> EMPTY
+
+setMetaData :target=ref graph :key :value => EMPTY
+
+setFormat
+ :target=ref (majorTicks | labeling)
+ :reset=bool?
+=> format | numberFormat | stringFormat+ | dateTimeFormat | elapsedTimeFormat
+
+setFrameStyle
+ :style=ref style
+ :target=ref majorTicks
+=> EMPTY
+@end example
+
+The @code{set*} children of @code{setCellProperties} determine the
+styles to set.
+
+When @code{setCellProperties} contains a @code{setFormat} whose
+@code{target} references a @code{labeling} element, or if it contains
+a @code{setStyle} that references a @code{labeling} or @code{interval}
+element, the @code{setCellProperties} sets the style for table cells.
+The format from the @code{setFormat}, if present, replaces the cells'
+format. The style from the @code{setStyle} that references
+@code{labeling}, if present, replaces the label's font and cell
+styles, except that the background color is taken instead from the
+@code{interval}'s style, if present.
+
+When @code{setCellProperties} contains a @code{setFormat} whose
+@code{target} references a @code{majorTicks} element, or if it
+contains a @code{setStyle} whose @code{target} references a
+@code{majorTicks}, or if it contains a @code{setFrameStyle} element,
+the @code{setCellProperties} sets the style for row or column labels.
+In this case, the @code{setCellProperties} always contains a single
+@code{where} element whose @code{variable} designates the variable
+whose labels are to be styled. The format from the @code{setFormat},
+if present, replaces the labels' format. The style from the
+@code{setStyle} that references @code{majorTicks}, if present,
+replaces the labels' font and cell styles, except that the background
+color is taken instead from the @code{setFrameStyle}'s style, if
+present.
+
+When @code{setCellProperties} contains a @code{setStyle} whose
+@code{target} references a @code{graph} element, and one that
+references a @code{labeling} element, and the @code{union} element
+contains @code{alternating}, the @code{setCellProperties} sets the
+alternate foreground and background colors for the data area. The
+foreground color is taken from the style referenced by the
+@code{setStyle} that targets the @code{graph}, the background color
+from the @code{setStyle} for @code{labeling}.
+
+A reader may ignore a @code{setCellProperties} that only contains
+@code{setMetaData}, as well as @code{setMetaData} within other
+@code{setCellProperties}.
+
+A reader may ignore a @code{setCellProperties} whose only @code{set*}
+child is a @code{setStyle} that targets the @code{graph} element.
+
+@subsubheading The @code{setStyle} Element
+
+@example
+setStyle
+ :target=ref (labeling | graph | interval | majorTicks)
+ :style=ref style
+=> EMPTY
+@end example
+
+This element associates a style with the target.
+
+@defvr {Attribute} target
+The @code{id} of an element whose style is to be set.
+@end defvr
+
+@defvr {Attribute} style
+The @code{id} of a @code{style} element that identifies the style to
+set on the target.
+@end defvr
+
+@node SPV Detail setFormat Element
+@subsection The @code{setFormat} Element
+
+@example
+setFormat
+ :target=ref (majorTicks | labeling)
+ :reset=bool?
+=> format | numberFormat | stringFormat+ | dateTimeFormat | elapsedTimeFormat
+@end example
+
+This element sets the format of the target, ``format'' in this case
+meaning the SPSS print format for a variable.
+
+The details of this element vary depending on the schema version, as
+declared in the root @code{visualization} element's @code{version}
+attribute (@pxref{SPV Detail visualization Element}). A reader can
+interpret the content without knowing the schema version.
+
+The @code{setFormat} element itself has the following attributes.
+
+@defvr {Attribute} target
+Refers to an element whose style is to be set.
+@end defvr
+
+@defvr {Attribute} reset
+If this is @code{true}, this format replaces the target's previous
+format. If it is @code{false}, the modifies the previous format.
+@end defvr
+
+@menu
+* SPV Detail numberFormat Element::
+* SPV Detail stringFormat Element::
+* SPV Detail dateTimeFormat Element::
+* SPV Detail elapsedTimeFormat Element::
+* SPV Detail format Element::
+* SPV Detail affix Element::
+@end menu
+
+@node SPV Detail numberFormat Element
+@subsubsection The @code{numberFormat} Element
+
+@example
+numberFormat
+ :minimumIntegerDigits=int?
+ :maximumFractionDigits=int?
+ :minimumFractionDigits=int?
+ :useGrouping=bool?
+ :scientific=(onlyForSmall | whenNeeded | true | false)?
+ :small=real?
+ :prefix?
+ :suffix?
+=> affix*
+@end example
+
+Specifies a format for displaying a number. The available options are
+a superset of those available from PSPP print formats. PSPP chooses a
+print format type for a @code{numberFormat} as follows:
+
+@enumerate
+@item
+If @code{scientific} is @code{true}, uses @code{E} format.
+
+@item
+If @code{prefix} is @code{$}, uses @code{DOLLAR} format.
+
+@item
+If @code{suffix} is @code{%}, uses @code{PCT} format.
+
+@item
+If @code{useGrouping} is @code{true}, uses @code{COMMA} format.
+
+@item
+Otherwise, uses @code{F} format.
+@end enumerate
+
+For translating to a print format, PSPP uses
+@code{maximumFractionDigits} as the number of decimals, unless that
+attribute is missing or out of the range [0,15], in which case it uses
+2 decimals.
+
+@defvr {Attribute} minimumIntegerDigits
+Minimum number of digits to display before the decimal point. Always
+observed as @code{0}.
+@end defvr
+
+@defvr {Attribute} maximumFractionDigits
+@defvrx {Attribute} minimumFractionDigits
+Maximum or minimum, respectively, number of digits to display after
+the decimal point. The observed values of each attribute range from 0
+to 9.
+@end defvr
+
+@defvr {Attribute} useGrouping
+Whether to use the grouping character to group digits in large
+numbers.
+@end defvr
+
+@defvr {Attribute} scientific
+This attribute controls when and whether the number is formatted in
+scientific notation. It takes the following values:
+
+@table @code
+@item onlyForSmall
+Use scientific notation only when the number's magnitude is smaller
+than the value of the @code{small} attribute.
+
+@item whenNeeded
+Use scientific notation when the number will not otherwise fit in the
+available space.
+
+@item true
+Always use scientific notation. Not observed in the corpus.
+
+@item false
+Never use scientific notation. A number that won't otherwise fit will
+be replaced by an error indication (see the @code{errorCharacter}
+attribute). Not observed in the corpus.
+@end table
+@end defvr
+
+@defvr {Attribute} small
+Only present when the @code{scientific} attribute is
+@code{onlyForSmall}, this is a numeric magnitude below which the
+number will be formatted in scientific notation. The values @code{0}
+and @code{0.0001} have been observed. The value @code{0} seems like a
+pathological choice, since no real number has a magnitude less than 0;
+perhaps in practice such a choice is equivalent to setting
+@code{scientific} to @code{false}.
+@end defvr
+
+@defvr {Attribute} prefix
+@defvrx {Attribute} suffix
+Specifies a prefix or a suffix to apply to the formatted number. Only
+@code{suffix} has been observed, with value @samp{%}.
+@end defvr
+
+@node SPV Detail stringFormat Element
+@subsubsection The @code{stringFormat} Element
+
+@example
+stringFormat => relabel* affix*
+
+relabel :from=real :to => EMPTY
+@end example
+
+The @code{stringFormat} element specifies how to display a string. By
+default, a string is displayed verbatim, but @code{relabel} can change
+it.
+
+The @code{relabel} element appears as a child of @code{stringFormat}
+(and of @code{format}, when it is used to format strings). It
+specifies how to display a given value. It is used to implement value
+labels and to display the system-missing value in a human-readable
+way. It has the following attributes:
+
+@defvr {Attribute} from
+The value to map. In the corpus this is an integer or the
+system-missing value @code{-1.797693134862316E300}.
+@end defvr
+
+@defvr {Attribute} to
+The string to display in place of the value of @code{from}. In the
+corpus this is a wide variety of value labels; the system-missing
+value is mapped to @samp{.}.
+@end defvr
+
+@node SPV Detail dateTimeFormat Element
+@subsubsection The @code{dateTimeFormat} Element
+
+@example
+dateTimeFormat
+ :baseFormat[dt_base_format]=(date | time | dateTime)
+ :separatorChars?
+ :mdyOrder=(dayMonthYear | monthDayYear | yearMonthDay)?
+ :showYear=bool?
+ :yearAbbreviation=bool?
+ :showQuarter=bool?
+ :quarterPrefix?
+ :quarterSuffix?
+ :showMonth=bool?
+ :monthFormat=(long | short | number | paddedNumber)?
+ :showWeek=bool?
+ :weekPadding=bool?
+ :weekSuffix?
+ :showDayOfWeek=bool?
+ :dayOfWeekAbbreviation=bool?
+ :dayPadding=bool?
+ :dayOfMonthPadding=bool?
+ :hourPadding=bool?
+ :minutePadding=bool?
+ :secondPadding=bool?
+ :showDay=bool?
+ :showHour=bool?
+ :showMinute=bool?
+ :showSecond=bool?
+ :showMillis=bool?
+ :dayType=(month | year)?
+ :hourFormat=(AMPM | AS_24 | AS_12)?
+=> affix*
+@end example
+
+This element appears only in schema version 2.5 and earlier
+(@pxref{SPV Detail visualization Element}).
+
+Data to be formatted in date formats is stored as strings in legacy
+data, in the format @code{yyyy-mm-ddTHH:MM:SS.SSS} and must be parsed
+and reformatted by the reader.
+
+The following attribute is required.
+
+@defvr {Attribute} baseFormat
+Specifies whether a date and time are both to be displayed, or just
+one of them.
+@end defvr
+
+Many of the attributes' meanings are obvious. The following seem to
+be worth documenting.
+
+@defvr {Attribute} separatorChars
+Exactly four characters. In order, these are used for: decimal point,
+grouping, date separator, time separator. Always @samp{.,-:}.
+@end defvr
+
+@defvr {Attribute} mdyOrder
+Within a date, the order of the days, months, and years.
+@code{dayMonthYear} is the only observed value, but one would expect
+that @code{monthDayYear} and @code{yearMonthDay} to be reasonable as
+well.
+@end defvr
+
+@defvr {Attribute} showYear
+@defvrx {Attribute} yearAbbreviation
+Whether to include the year and, if so, whether the year should be
+shown abbreviated, that is, with only 2 digits. Each is @code{true}
+or @code{false}; only values of @code{true} and @code{false},
+respectively, have been observed.
+@end defvr
+
+@defvr {Attribute} showMonth
+@defvrx {Attribute} monthFormat
+Whether to include the month (@code{true} or @code{false}) and, if so,
+how to format it. @code{monthFormat} is one of the following:
+
+@table @code
+@item long
+The full name of the month, e.g.@: in an English locale,
+@code{September}.
+
+@item short
+The abbreviated name of the month, e.g.@: in an English locale,
+@code{Sep}.
+
+@item number
+The number representing the month, e.g.@: 9 for September.
+
+@item paddedNumber
+A two-digit number representing the month, e.g.@: 09 for September.
+@end table
+
+Only values of @code{true} and @code{short}, respectively, have been
+observed.
+@end defvr
+
+@defvr {Attribute} dayType
+This attribute is always @code{month} in the corpus, specifying that
+the day of the month is to be displayed; a value of @code{year} is
+supposed to indicate that the day of the year, where 1 is January 1,
+is to be displayed instead.
+@end defvr
+
+@defvr {Attribute} hourFormat
+@code{hourFormat}, if present, is one of:
+
+@table @code
+@item AMPM
+The time is displayed with an @code{am} or @code{pm} suffix, e.g.@:
+@code{10:15pm}.
+
+@item AS_24
+The time is displayed in a 24-hour format, e.g.@: @code{22:15}.
+
+This is the only value observed in the corpus.
+
+@item AS_12
+The time is displayed in a 12-hour format, without distinguishing
+morning or evening, e.g.@: @code{10;15}.
+@end table
+
+@code{hourFormat} is sometimes present for @code{elapsedTime} formats,
+which is confusing since a time duration does not have a concept of AM
+or PM. This might indicate a bug in the code that generated the XML
+in the corpus, or it might indicate that @code{elapsedTime} is
+sometimes used to format a time of day.
+@end defvr
+
+For a @code{baseFormat} of @code{date}, PSPP chooses a print format
+type based on the following rules:
+
+@enumerate
+@item
+If @code{showQuarter} is true: @code{QYR}.
+
+@item
+Otherwise, if @code{showWeek} is true: @code{WKYR}.
+
+@item
+Otherwise, if @code{mdyOrder} is @code{dayMonthYear}:
+
+@enumerate a
+@item
+If @code{monthFormat} is @code{number} or @code{paddedNumber}: @code{EDATE}.
+
+@item
+Otherwise: @code{DATE}.
+@end enumerate
+
+@item
+Otherwise, if @code{mdyOrder} is @code{yearMonthDay}: @code{SDATE}.
+
+@item
+Otherwise, @code{ADATE}.
+@end enumerate
+
+For a @code{baseFormat} of @code{dateTime}, PSPP uses @code{YMDHMS} if
+@code{mdyOrder} is @code{yearMonthDay} and @code{DATETIME} otherwise.
+For a @code{baseFormat} of @code{time}, PSPP uses @code{DTIME} if
+@code{showDay} is true, otherwise @code{TIME} if @code{showHour} is
+true, otherwise @code{MTIME}.
+
+For a @code{baseFormat} of @code{date}, the chosen width is the
+minimum for the format type, adding 2 if @code{yearAbbreviation} is
+false or omitted. For other base formats, the chosen width is the
+minimum for its type, plus 3 if @code{showSecond} is true, plus 4 more
+if @code{showMillis} is also true. Decimals are 0 by default, or 3
+if @code{showMillis} is true.
+
+@node SPV Detail elapsedTimeFormat Element
+@subsubsection The @code{elapsedTimeFormat} Element
+
+@example
+elapsedTimeFormat
+ :baseFormat[dt_base_format]=(date | time | dateTime)
+ :dayPadding=bool?
+ :hourPadding=bool?
+ :minutePadding=bool?
+ :secondPadding=bool?
+ :showYear=bool?
+ :showDay=bool?
+ :showHour=bool?
+ :showMinute=bool?
+ :showSecond=bool?
+ :showMillis=bool?
+=> affix*
+@end example
+
+This element specifies the way to display a time duration.
+
+Data to be formatted in elapsed time formats is stored as strings in
+legacy data, in the format @code{H:MM:SS.SSS}, with additional hour
+digits as needed for long durations, and must be parsed and
+reformatted by the reader.
+
+The following attribute is required.
+
+@defvr {Attribute} baseFormat
+Specifies whether a day and a time are both to be displayed, or just
+one of them.
+@end defvr
+
+The remaining attributes specify exactly how to display the elapsed
+time.
+
+For @code{baseFormat} of @code{time}, PSPP converts this element to
+print format type @code{DTIME}; otherwise, if @code{showHour} is true,
+to @code{TIME}; otherwise, to @code{MTIME}. The chosen width is the
+minimum for the chosen type, adding 3 if @code{showSecond} is true,
+adding 4 more if @code{showMillis} is also true. Decimals are 0 by
+default, or 3 if @code{showMillis} is true.
+
+@node SPV Detail format Element
+@subsubsection The @code{format} Element
+
+@example
+format
+ :baseFormat[f_base_format]=(date | time | dateTime | elapsedTime)?
+ :errorCharacter?
+ :separatorChars?
+ :mdyOrder=(dayMonthYear | monthDayYear | yearMonthDay)?
+ :showYear=bool?
+ :showQuarter=bool?
+ :quarterPrefix?
+ :quarterSuffix?
+ :yearAbbreviation=bool?
+ :showMonth=bool?
+ :monthFormat=(long | short | number | paddedNumber)?
+ :dayPadding=bool?
+ :dayOfMonthPadding=bool?
+ :showWeek=bool?
+ :weekPadding=bool?
+ :weekSuffix?
+ :showDayOfWeek=bool?
+ :dayOfWeekAbbreviation=bool?
+ :hourPadding=bool?
+ :minutePadding=bool?
+ :secondPadding=bool?
+ :showDay=bool?
+ :showHour=bool?
+ :showMinute=bool?
+ :showSecond=bool?
+ :showMillis=bool?
+ :dayType=(month | year)?
+ :hourFormat=(AMPM | AS_24 | AS_12)?
+ :minimumIntegerDigits=int?
+ :maximumFractionDigits=int?
+ :minimumFractionDigits=int?
+ :useGrouping=bool?
+ :scientific=(onlyForSmall | whenNeeded | true | false)?
+ :small=real?
+ :prefix?
+ :suffix?
+ :tryStringsAsNumbers=bool?
+ :negativesOutside=bool?
+=> relabel* affix*
+@end example
+
+This element is the union of all of the more-specific format elements.
+It is interpreted in the same way as one of those format elements,
+using @code{baseFormat} to determine which kind of format to use.
+
+There are a few attributes not present in the more specific formats:
+
+@defvr {Attribute} tryStringsAsNumbers
+When this is @code{true}, it is supposed to indicate that string
+values should be parsed as numbers and then displayed according to
+numeric formatting rules. However, in the corpus it is always
+@code{false}.
+@end defvr
+
+@defvr {Attribute} negativesOutside
+If true, the negative sign should be shown before the prefix; if
+false, it should be shown after.
+@end defvr
+
+@node SPV Detail affix Element
+@subsubsection The @code{affix} Element
+
+@example
+affix
+ :definesReference=int
+ :position=(subscript | superscript)
+ :suffix=bool
+ :value
+=> EMPTY
+@end example
+
+This defines a suffix (or, theoretically, a prefix) for a formatted
+value. It is used to insert a reference to a footnote. It has the
+following attributes:
+
+@defvr {Attribute} definesReference
+This specifies the footnote number as a natural number: 1 for the
+first footnote, 2 for the second, and so on.
+@end defvr
+
+@defvr {Attribute} position
+Position for the footnote label. Always @code{superscript}.
+@end defvr
+
+@defvr {Attribute} suffix
+Whether the affix is a suffix (@code{true}) or a prefix
+(@code{false}). Always @code{true}.
+@end defvr
+
+@defvr {Attribute} value
+The text of the suffix or prefix. Typically a letter, e.g.@: @code{a}
+for footnote 1, @code{b} for footnote 2, @enddots{} The corpus
+contains other values: @code{*}, @code{**}, and a few that begin with
+at least one comma: @code{,b}, @code{,c}, @code{,,b}, and @code{,,c}.
+@end defvr
+
+@node SPV Detail interval Element
+@subsection The @code{interval} Element
+
+@example
+interval :style=ref style => labeling footnotes?
+
+labeling
+ :style=ref style?
+ :variable=ref (sourceVariable | derivedVariable)
+=> (formatting | format | footnotes)*
+
+formatting :variable=ref (sourceVariable | derivedVariable) => formatMapping*
+
+formatMapping :from=int => format?
+
+footnotes
+ :superscript=bool?
+ :variable=ref (sourceVariable | derivedVariable)
+=> footnoteMapping*
+
+footnoteMapping :definesReference=int :from=int :to => EMPTY
+@end example
+
+The @code{interval} element and its descendants determine the basic
+formatting and labeling for the table's cells. These basic styles are
+overridden by more specific styles set using @code{setCellProperties}
+(@pxref{SPV Detail setCellProperties Element}).
+
+The @code{style} attribute of @code{interval} itself may be ignored.
+
+The @code{labeling} element may have a single @code{formatting} child.
+If present, its @code{variable} attribute refers to a variable whose
+values are format specifiers as numbers, e.g. value 0x050802 for F8.2.
+However, the numbers are not actually interpreted that way. Instead,
+each number actually present in the variable's data is mapped by a
+@code{formatMapping} child of @code{formatting} to a @code{format}
+that specifies how to display it.
+
+The @code{labeling} element may also have a @code{footnotes} child
+element. The @code{variable} attribute of this element refers to a
+variable whose values are comma-delimited strings that list the
+1-based indexes of footnote references. (Cells without any footnote
+references are numeric 0 instead of strings.)
+
+Each @code{footnoteMapping} child of the @code{footnotes} element
+defines the footnote marker to be its @code{to} attribute text for the
+footnote whose 1-based index is given in its @code{definesReference}
+attribute.
+
+@node SPV Detail style Element
+@subsection The @code{style} Element
+
+@example
+style
+ :color=color?
+ :color2=color?
+ :labelAngle=real?
+ :border-bottom=(solid | thick | thin | double | none)?
+ :border-top=(solid | thick | thin | double | none)?
+ :border-left=(solid | thick | thin | double | none)?
+ :border-right=(solid | thick | thin | double | none)?
+ :border-bottom-color?
+ :border-top-color?
+ :border-left-color?
+ :border-right-color?
+ :font-family?
+ :font-size?
+ :font-weight=(regular | bold)?
+ :font-style=(regular | italic)?
+ :font-underline=(none | underline)?
+ :margin-bottom=dimension?
+ :margin-left=dimension?
+ :margin-right=dimension?
+ :margin-top=dimension?
+ :textAlignment=(left | right | center | decimal | mixed)?
+ :labelLocationHorizontal=(positive | negative | center)?
+ :labelLocationVertical=(positive | negative | center)?
+ :decimal-offset=dimension?
+ :size?
+ :width?
+ :visible=bool?
+=> EMPTY
+@end example
+
+A @code{style} element has an effect only when it is referenced by
+another element to set some aspect of the table's style. Most of the
+attributes are self-explanatory. The rest are described below.
+
+@defvr {Attribute} {color}
+In some cases, the text color; in others, the background color.
+@end defvr
+
+@defvr {Attribute} {color2}
+Not used.
+@end defvr
+
+@defvr {Attribute} {labelAngle}
+Normally 0. The value -90 causes inner column or outer row labels to
+be rotated vertically.
+@end defvr
+
+@defvr {Attribute} {labelLocationHorizontal}
+Not used.
+@end defvr
+
+@defvr {Attribute} {labelLocationVertical}
+The value @code{positive} corresponds to vertically aligning text to
+the top of a cell, @code{negative} to the bottom, @code{center} to the
+middle.
+@end defvr
+
+@node SPV Detail labelFrame Element
+@subsection The @code{labelFrame} Element
+
+@example
+labelFrame :style=ref style => location+ label? paragraph?
+
+paragraph :hangingIndent=dimension? => EMPTY
+@end example
+
+A @code{labelFrame} element specifies content and style for some
+aspect of a table. Only @code{labelFrame} elements that have a
+@code{label} child are important. The @code{purpose} attribute in the
+@code{label} determines what the @code{labelFrame} affects:
+
+@table @code
+@item title
+The table's title and its style.
+
+@item subTitle
+The table's caption and its style.
+
+@item footnote
+The table's footnotes and the style for the footer area.
+
+@item layer
+The style for the layer area.
+
+@item subSubTitle
+Ignored.
+@end table
+
+The @code{style} attribute references the style to use for the area.
+
+The @code{label}, if present, specifies the text to put into the title
+or caption or footnotes. For footnotes, the label has two @code{text}
+children for every footnote, each of which has a @code{usesReference}
+attribute identifying the 1-based index of a footnote. The first,
+third, fifth, @dots{} @code{text} child specifies the content for a
+footnote; the second, fourth, sixth, @dots{} child specifies the
+marker. Content tends to end in a new-line, which the reader may wish
+to trim; similarly, markers tend to end in @samp{.}.
+
+The @code{paragraph}, if present, may be ignored, since it is always
+empty.
+
+@node SPV Detail Legacy Properties
+@subsection Legacy Properties
+
+The detail XML format has features for styling most of the aspects of
+a table. It also inherits defaults for many aspects from structure
+XML, which has the following @code{tableProperties} element:
+
+@example
+tableProperties
+ :name?
+=> generalProperties footnoteProperties cellFormatProperties borderProperties printingProperties
+
+generalProperties
+ :hideEmptyRows=bool?
+ :maximumColumnWidth=dimension?
+ :maximumRowWidth=dimension?
+ :minimumColumnWidth=dimension?
+ :minimumRowWidth=dimension?
+ :rowDimensionLabels=(inCorner | nested)?
+=> EMPTY
+
+footnoteProperties
+ :markerPosition=(superscript | subscript)?
+ :numberFormat=(alphabetic | numeric)?
+=> EMPTY
+
+cellFormatProperties => cell_style+
+
+any[cell_style]
+ :alternatingColor=color?
+ :alternatingTextColor=color?
+=> style
+
+style
+ :color=color?
+ :color2=color?
+ :font-family?
+ :font-size?
+ :font-style=(regular | italic)?
+ :font-weight=(regular | bold)?
+ :font-underline=(none | underline)?
+ :labelLocationVertical=(positive | negative | center)?
+ :margin-bottom=dimension?
+ :margin-left=dimension?
+ :margin-right=dimension?
+ :margin-top=dimension?
+ :textAlignment=(left | right | center | decimal | mixed)?
+ :decimal-offset=dimension?
+=> EMPTY
+
+borderProperties => border_style+
+
+any[border_style]
+ :borderStyleType=(none | solid | dashed | thick | thin | double)?
+ :color=color?
+=> EMPTY
+
+printingProperties
+ :printAllLayers=bool?
+ :rescaleLongTableToFitPage=bool?
+ :rescaleWideTableToFitPage=bool?
+ :windowOrphanLines=int?
+ :continuationText?
+ :continuationTextAtBottom=bool?
+ :continuationTextAtTop=bool?
+ :printEachLayerOnSeparatePage=bool?
+=> EMPTY
+@end example
+
+The @code{name} attribute appears only in standalone @file{.stt} files
+(@pxref{SPSS TableLook STT Format}).