Some progress on format documentation.
[pspp] / spv-file-format.texi
index ee99c24051c9eddff1b14ceb1220956e45e3131f..ce094484da3fe059cfb6c3e60f889c14d4cc56b6 100644 (file)
@@ -143,25 +143,25 @@ times.
 @end iftex
 
 @menu
-* SPV heading Element::
-* SPV label Element::
-* SPV container Element::
-* SPV text Element (Inside @code{container})::
-* SPV html Element::
-* SPV table Element::
-* SPV tableStructure Element::
-* SPV dataPath Element::
-* SPV pageSetup Element::
-* SPV pageHeader and pageFooter Elements::
-* SPV pageParagraph Element::
-* SPV @code{text} Element (Inside @code{pageParagraph})::
+* SPV Structure heading Element::
+* SPV Structure label Element::
+* SPV Structure container Element::
+* SPV Structure text Element (Inside @code{container})::
+* SPV Structure html Element::
+* SPV Structure table Element::
+* SPV Structure tableStructure Element::
+* SPV Structure dataPath Element::
+* SPV Structure pageSetup Element::
+* SPV Structure pageHeader and pageFooter Elements::
+* SPV Structure pageParagraph Element::
+* SPV Structure @code{text} Element (Inside @code{pageParagraph})::
 @end menu
 
-@node SPV heading Element
+@node SPV Structure heading Element
 @subsection The @code{heading} Element
 
 Parent: Document root or @code{heading} @*
-Contents: [@code{pageSetup}] @code{label} (@code{container} @math{|} @code{heading})*
+Contents: @code{pageSetup}? @code{label} (@code{container} @math{|} @code{heading})*
 
 The root of a structure member is a @code{heading}, which represents a
 section of output beginning with a title (the @code{label}) and
@@ -234,7 +234,7 @@ The output language, e.g.@: @code{en}, @code{it}, @code{es},
 @code{de}, @code{pt-BR}.
 @end defvr
 
-@node SPV label Element
+@node SPV Structure label Element
 @subsection The @code{label} Element
 
 Parent: @code{heading} or @code{container} @*
@@ -255,11 +255,11 @@ no text.
 
 This element has no attributes.
 
-@node SPV container Element
+@node SPV Structure container Element
 @subsection The @code{container} Element
 
 Parent: @code{heading} @*
-Contents: @code{label} [@code{table} @math{|} @code{text}]
+Contents: @code{label} (@code{table} @math{|} @code{text})?
 
 A @code{container} serves to label a @code{table} or a @code{text}
 item.
@@ -282,7 +282,7 @@ The width of the container in the form @code{@var{n}px}, e.g.@:
 @code{1097px}.
 @end defvr
 
-@node SPV text Element (Inside @code{container})
+@node SPV Structure text Element (Inside @code{container})
 @subsection The @code{text} Element (Inside @code{container})
 
 Parent: @code{container} @*
@@ -308,7 +308,7 @@ of where @code{commandName} is present but set to the empty string.
 As on the @code{heading} element.
 @end defvr
 
-@node SPV html Element
+@node SPV Structure html Element
 @subsection The @code{html} Element
 
 Parent: @code{text} @*
@@ -327,7 +327,7 @@ This element has the following attributes.
 This always contains @code{en} in the corpus.
 @end defvr
 
-@node SPV table Element
+@node SPV Structure table Element
 @subsection The @code{table} Element
 
 Parent: @code{container} @*
@@ -361,7 +361,7 @@ As on the @code{heading} element.  In the corpus, this is only present
 for version 21 and up and always includes all 8 digits.
 @end defvr
 
-@node SPV tableStructure Element
+@node SPV Structure tableStructure Element
 @subsection The @code{tableStructure} Element
 
 Parent: @code{table} @*
@@ -369,7 +369,7 @@ Contents: @code{dataPath}
 
 This element has no attributes.
 
-@node SPV dataPath Element
+@node SPV Structure dataPath Element
 @subsection The @code{dataPath} Element
 
 Parent: @code{tableStructure} @*
@@ -380,7 +380,7 @@ e.g.@: @code{0000000001437_lightTableData.bin}.
 
 This element has no attributes.
 
-@node SPV pageSetup Element
+@node SPV Structure pageSetup Element
 @subsection The @code{pageSetup} Element
 
 Parent: @code{heading} @*
@@ -419,7 +419,7 @@ Always @code{0deg}.
 Always @code{12pt}.
 @end defvr
 
-@node SPV pageHeader and pageFooter Elements
+@node SPV Structure pageHeader and pageFooter Elements
 @subsection The @code{pageHeader} and @code{pageFooter} Elements
 
 Parent: @code{pageSetup} @*
@@ -427,7 +427,7 @@ Contents: @code{pageParagraph}*
 
 This element has no attributes.
 
-@node SPV pageParagraph Element
+@node SPV Structure pageParagraph Element
 @subsection The @code{pageParagraph} Element
 
 Parent: @code{pageHeader} or @code{pageFooter} @*
@@ -437,11 +437,11 @@ Text to go at the top or bottom of a page, respectively.
 
 This element has no attributes.
 
-@node SPV @code{text} Element (Inside @code{pageParagraph})
+@node SPV Structure @code{text} Element (Inside @code{pageParagraph})
 @subsection The @code{text} Element (Inside @code{pageParagraph})
 
-Parent: @code{pageParagraph} @*
-Contents: [CDATA]
+Parent: @code{pageParagraph}
+Contents: CDATA?
 
 This @code{text} element is nested inside a @code{pageParagraph}.  There
 is a different @code{text} element that is nested inside a
@@ -1092,8 +1092,9 @@ The Style, if present, changes the style for this individual Value.
 Whereas the light binary format represents everything about a given
 pivot table, the legacy binary format conceptually consists of a
 number of named sources, each of which consists of a number of named
-series, each of which is a 1-dimensional array of numbers or strings
-or a mix.  Thus, the legacy binary member format is quite simple.
+variables, each of which is a 1-dimensional array of numbers or
+strings or a mix.  Thus, the legacy binary member format is quite
+simple.
 
 This section uses the same context-free grammar notation as in the
 previous section, with the following additions:
@@ -1140,18 +1141,19 @@ The following sections go into more detail.
 @cartouche
 @format
 Metadata @result{}
-    int[@t{per-series}] int[@t{n-series}] int[@t{offset}]
+    int[@t{n-data}] int[@t{n-variables}] int[@t{offset}]
     vAF(byte*32[@t{source-name}])
     vB0(byte*64[@t{source-name}] int[@t{x}])
 @end format
 @end cartouche
 
-A data source consists of @code{n-series} series of data, with
-@code{per-series} data values per series.
+A data source has @code{n-variables} variables, each with
+@code{n-data} data values.
 
 @code{source-name} is a 32- or 64-byte string padded on the right with
-zero bytes.  The names that appear in the corpus are very generic,
-usually @code{tableData} or @code{source0}.
+zero bytes.  The names that appear in the corpus are very generic:
+usually @code{tableData} for pivot table data or @code{source0} for
+chart data.
 
 A given Metadata's @code{offset} is the offset, in bytes, from the
 beginning of the member to the start of the corresponding Data.  This
@@ -1166,26 +1168,25 @@ The meaning of @code{x} in version 0xb0 is unknown.
 
 @cartouche
 @format
-Data @result{} NumericData StringData?
-NumericData @result{} NumericSeries*[@t{n-series}]
-NumericSeries @result{} byte*288[@t{series-name}] double*[@t{per-series}]
+Data @result{} NumericData*[@t{n-variables}] StringData?
+NumericData @result{} byte*288[@t{variable-name}] double*[@t{n-data}]
 @end format
 @end cartouche
 
 Data follow the Metadata in the legacy binary format, with sources in
-the same order.  Each NumericSeries begins with a @code{series-name}
+the same order.  Each NumericSeries begins with a @code{variable-name}
 that generally indicates its role in the pivot table, e.g.@: ``cell'',
 ``cellFormat'', ``dimension0categories'', ``dimension0group0'',
-followed by the numeric data, one double per element in the series.  A
-double with the maximum negative double @code{-DBL_MAX} represents the
-system-missing value SYSMIS.
+followed by the numeric data, one double per datum.  A double with the
+maximum negative double @code{-DBL_MAX} represents the system-missing
+value SYSMIS.
 
 @cartouche
 @format
 StringData @result{} i1 string[@t{source-name}] Pairs Labels
 
-Pairs @result{} int[@t{n-string-series}] PairSeries*[@t{n-string-series}]
-PairSeries @result{} string[@t{pair-series-name}] int[@t{n-pairs}] Pair*[@t{n-pairs}]
+Pairs @result{} int[@t{n-string-vars}] PairSeries*[@t{n-string-vars}]
+PairVar @result{} string[@t{pair-var-name}] int[@t{n-pairs}] Pair*[@t{n-pairs}]
 Pair @result{} int[@t{i}] int[@t{j}]
 
 Labels @result{} int[@t{n-labels}] Label*[@t{n-labels}]
@@ -1195,23 +1196,23 @@ Label @result{} int[@t{frequency}] int[@t{s}]
 
 A source may include a mix of numeric and string data values.  When a
 source includes any string data, the data values that are strings are
-set to SYSMIS in the NumericSeries, and StringData follows the
+set to SYSMIS in the NumericData, and StringData follows the
 NumericData.  A source that contains no string data omits the
 StringData.  To reliably determine whether a source includes
 StringData, the reader should check whether the offset following the
-NumericData is the offset of the next series, as indicated by its
+NumericData is the offset of the next source, as indicated by its
 Metadata (or the end of the member, in the case of the last source).
 
 StringData repeats the name of the source (from Metadata).
 
-The string data overlays the numeric data.  @code{n-string-series} is
-the number of series within the source that include string data.  More
-precisely, it is the 1-based index of the last series in the source
+The string data overlays the numeric data.  @code{n-string-vars} is
+the number of variables in the source that include string data.  More
+precisely, it is the 1-based index of the last variable in the source
 that includes any string data; thus, it would be 4 if there are 5
-series and only the fourth one includes string data.
+variables and only the fourth one includes string data.
 
-Each PairSeries consists a sequence of 0 or more Pair nonterminals,
-each of which maps from a 0-based index within series @code{i} to a
+Each PairVar consists a sequence of 0 or more Pair nonterminals, each
+of which maps from a 0-based index within variable @code{i} to a
 0-based label index @code{j}, e.g.@: pair @code{i} = 2, @code{j} = 3,
 means that the third data value (with value SYSMIS) is to be replaced
 by the string of the fourth Label.
@@ -1225,3 +1226,824 @@ label is the string @code{s}.  Each label also includes a
 @section Legacy Detail Member XML Format
 
 This format is still under investigation.
+
+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.
+
+The important elements of the detail XML format are:
+
+@itemize @bullet
+@item
+Variables.  Variables in detail XML roughly correspond to the
+dimensions in a light detail member.  There is one variable for each
+dimension, plus one variable for each level of labeling along an axis.
+
+The bulk of variables are defined with @code{sourceVariable} elements.
+The data for these variables comes from the associated
+@code{tableData.bin} member.  Some variables are defined, with
+@code{derivedVariable} elements, as a constant or in terms of a
+mapping function from a source variable.
+
+@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.
+@end itemize
+
+All elements have an optional @code{id} attribute.  In practice many
+elements are assigned @code{id} attributes that are never referenced.
+
+@menu
+* SPV Detail visualization Element::
+* SPV Detail userSource Element::
+* SPV Detail sourceVariable Element::
+* SPV Detail derivedVariable Element::
+* SPV Detail extension Element::
+* SPV Detail graph Element::
+* SPV Detail location Element::
+* SPV Detail coordinates Element::
+* SPV Detail faceting Element::
+* SPV Detail facetLayout Element::
+@end menu
+
+@node SPV Detail visualization Element
+@subsection The @code{visualization} Element
+
+@format
+Parent: Document root
+Contents:
+     extension?
+     userSource
+     (sourceVariable @math{|} derivedVariable)@math{+}
+     graph
+     labelFrame@math{+}
+     container?
+     style@math{+}
+     layerController?
+@end format
+
+This element has the following attributes.
+
+@defvr {Required} 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 {Required} date
+The date on the which the file was created, as a string of the form
+@code{YYYY-MM-DD}.
+@end defvr
+
+@defvr {Required} 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 {Required} name
+The title of the pivot table, localized to the output language.
+@end defvr
+
+@defvr {Required} style
+The @code{id} of a @code{style} element (@pxref{SPV Detail style
+element}).  This is the base style for the entire pivot table.  In
+every example in the corpus, the value is @code{visualizationStyle}
+and the corresponding @code{style} element has no attributes other
+than @code{id}.
+@end defvr
+
+@defvr {Required} type
+A floating-point number.  The meaning is unknown.
+@end defvr
+
+@defvr {Required} 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
+
+@node SPV Detail userSource Element
+@subsection The @code{userSource} Element
+
+Parent: @code{visualization} @*
+Contents:
+
+This element has the following attributes.
+
+@defvr {Optional} missing
+Always @code{listwise}.
+@end defvr
+
+@node SPV Detail sourceVariable Element
+@subsection The @code{sourceVariable} Element
+
+Parent: @code{visualization} @*
+Contents: @code{extension}* (@code{format} @math{|} @code{stringFormat})?
+
+This element defines a variable whose values can be used elsewhere in
+the visualization.  It ties this element's @code{id} to a variable
+from the @file{tableData.bin} member that corresponds to this
+@file{.xml}.
+
+This element has the following attributes.
+
+@defvr {Required} categorical
+Always set to @code{true}.
+@end defvr
+
+@defvr {Required} 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 {Required} sourceName
+The name of a variable within the source, the @code{variable-name} in
+the corresponding @file{tableData.bin} member (@pxref{SPV Legacy
+Member Data}).
+@end defvr
+
+@defvr {Optional} dependsOn
+The @code{variable-name} of a variable linked to this one, so that a
+viewer can work with them together.  For a group variable, this is the
+name of the corresponding categorical variable.
+@end defvr
+
+@defvr {Optional} label
+The variable label, if any
+@end defvr
+
+@defvr {Optional} 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
+
+@node SPV Detail derivedVariable Element
+@subsection The @code{derivedVariable} Element
+
+Parent: @code{visualization} @*
+Contents: @code{extension}* (@code{format} @math{|} @code{stringFormat} @code{valueMapEntry}*)
+
+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 {Required} categorical
+Always set to @code{true}.
+@end defvr
+
+@defvr {Required} 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(@var{number})
+@itemx constant(@var{variable})
+A constant.  The meaning when a variable is 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 {Optional} dependsOn
+The @code{variable-name} of a variable linked to this one, so that a
+viewer can work with them together.  For a group variable, this is the
+name of the corresponding categorical variable.
+@end defvr
+
+@menu
+* SPV Detail valueMapEntry Element::
+@end menu
+
+@node SPV Detail valueMapEntry Element
+@subsubsection The @code{valueMapEntry} Element
+
+Parent: @code{derivedVariable} @*
+Contents: empty
+
+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.
+
+@code{valueMapEntry} has the following attributes.
+
+@defvr {Required} from
+A source value, or multiple source values separated by semicolons,
+e.g.@: @code{0} or @code{13;14;15;16}.
+@end defvr
+
+@defvr {Required} to
+The target value.
+@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{visualization} Parent Element
+
+With @code{visualization} as its parent element, @code{extension} has
+the following attributes.
+
+@defvr {Optional} numRows
+An integer that presumably defines the number of rows in the displayed
+pivot table.
+@end defvr
+
+@defvr {Optional} showGridline
+Always set to @code{false} in the corpus.
+@end defvr
+
+@defvr {Optional} minWidthSet
+@defvrx {Optional} maxWidthSet
+Always set to @code{true} in the corpus.
+@end defvr
+
+@subsubheading @code{container} Parent Element
+
+With @code{container} as its parent element, @code{extension} has the
+following attributes.
+
+@defvr {Required} combinedFootnotes
+Always set to @code{true} in the corpus.
+@end defvr
+
+@subsubheading @code{sourceVariable} and @code{derivedVariable} Parent Element
+
+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
+
+@defvr {Required} from
+An integer or a name like ``dimension0''.
+@end defvr
+
+@defvr {Required} helpId
+An identifier.
+@end defvr
+
+@node SPV Detail graph Element
+@subsection The @code{graph} Element
+
+Parent: @code{visualization} @*
+Contents: @code{location}@math{+} @code{coordinates} @code{faceting} @code{facetLayout} @code{interval}
+
+@code{graph} has the following attributes.
+
+@defvr {Required} cellStyle
+@defvrx {Required} 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
+
+Parent: @code{graph} @*
+Contents: empty
+
+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{heigth} 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 {Required} part
+One of @code{height}, @code{width}, @code{top}, @code{bottom}, or
+@code{left}.  Presumably @code{right} is acceptable as well but the
+corpus contains no examples.
+@end defvr
+
+@defvr {Required} 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 {Optional} 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 is the ID of 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 coordinates Element
+@subsection The @code{coordinates} Element
+
+Parent: @code{graph} @*
+Contents: empty
+
+This element is always present and always empty, with no attributes
+(except @code{id}).
+
+@node SPV Detail faceting Element
+@subsection The @code{faceting} Element
+
+Parent: @code{graph} @*
+Contents: @code{cross} @code{layer}*
+
+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.
+
+@code{faceting} has no attributes (other than @code{id}).
+
+@subsubheading The @code{cross} Element
+
+Parent: @code{faceting} @*
+Contents: @code{nest} @code{nest}
+
+The @code{cross} element describes the row and column structure of the
+table.  It has exactly two @code{nest} children, the first of which
+describes the table's rows and the second the table's columns.
+
+@code{cross} has no attributes (other than @code{id}).
+
+@subsubheading The @code{nest} Element
+
+Parent: @code{cross} @*
+Contents: @code{variableReference}@math{+}
+
+A given @code{nest} usually consists of one or more dimensions, each
+of which is represented by @code{variableReference} child elements.
+Minimally, a dimension has two @code{variableReference} children, one
+for the categories, one for the data, e.g.:
+
+@example
+<nest>
+  <variableReference ref="dimension0categories"/>
+  <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+@noindent
+Groups of categories introduce additional variable references, e.g.@:
+
+@example
+<nest>
+  <variableReference ref="dimension0categories"/>
+  <variableReference ref="dimension0group0"/>
+  <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+@noindent
+Grouping can be hierarchical, e.g.@:
+
+@example
+<nest>
+  <variableReference ref="dimension0categories"/>
+  <variableReference ref="dimension0group1"/>
+  <variableReference ref="dimension0group0"/>
+  <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+@noindent
+XXX what are group maps?
+
+@example
+<nest id="nest_1973">
+  <variableReference ref="dimension1categories"/>
+  <variableReference ref="dimension1group1map"/>
+  <variableReference ref="dimension1group0map"/>
+  <variableReference ref="dimension1"/>
+</nest>
+<nest>
+  <variableReference ref="dimension0categories"/>
+  <variableReference ref="dimension0group0map"/>
+  <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+@noindent
+A @code{nest} can contain multiple dimensions:
+
+@example
+<nest>
+  <variableReference ref="dimension1categories"/>
+  <variableReference ref="dimension1group0"/>
+  <variableReference ref="dimension1"/>
+  <variableReference ref="dimension0categories"/>
+  <variableReference ref="dimension0"/>
+</nest>
+@end example
+
+One @code{nest} within a given @code{cross} 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}.
+
+@code{nest} has no attributes (other than @code{id}).
+
+@subsubheading The @code{variableReference} Element
+
+Parent: @code{nest} @*
+Contents: empty
+
+@code{variableReference} has one attribute.
+
+@defvr {Required} ref
+The @code{id} of a @code{sourceVariable} or @code{derivedVariable}
+element.
+@end defvr
+
+@subsubheading The @code{layer} Element
+
+Parent: @code{faceting} @*
+Contents: empty
+
+Each layer is represented by a pair of @code{layer} elements.  The
+first of this pair is for a category variable, the second for the data
+variable, 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 {Required} variable
+The @code{id} of a @code{sourceVariable} or @code{derivedVariable}
+element.
+@end defvr
+
+@defvr {Required} 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 {Optional} 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 {Optional} method
+When present, this is always @code{nest}.
+@end defvr
+
+@node SPV Detail facetLayout Element
+@subsection The @code{facetLayout} Element
+
+Parent: @code{graph} @*
+Contents: @code{tableLayout} @code{facetLevel}@math{+} @code{setCellProperties}*
+
+@subsubheading The @code{tableLayout} Element
+
+Parent: @code{facetLayout} @*
+Contents: empty
+
+@defvr {Required} verticalTitlesInCorner
+Always set to @code{true}.
+@end defvr
+
+@defvr {Optional} style
+The @code{id} of a @code{style} element.
+@end defvr
+
+@defvr {Optional} fitCells
+Always set to @code{ticks}.
+@end defvr
+
+@subsubheading The @code{facetLevel} Element
+
+Parent: @code{facetLayout}
+Contents: @code{axis}
+
+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 {Required} 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 {Required} gap
+Always observed as @code{0pt}.
+@end defvr
+
+@subsubheading The @code{setCellProperties} Element
+
+Parent: @code{facetLayout} @*
+Contents: @code{setMetaData} @code{setStyle}* @code{setFormat}@math{+} @code{union}?
+
+This element sets style properties of cells designated by the
+@code{target} attribute of its child elements.
+
+@defvr {Optional} applyToConverse
+If present, always @code{true}.  This appears to invert the meaning of
+the @code{target} of sub-elements: the selected cells are the ones
+@emph{not} designated by @code{target}.
+@end defvr
+
+@subsubheading The @code{setMetaData} Element
+
+Parent: @code{setCellProperties} @*
+Contents: empty
+
+It's really not clear what visible effect this element has, if any.
+
+@defvr {Required} target
+The @code{id} of an element whose metadata is to be set.  In the
+corpus, this is always @code{graph}, the @code{id} used for the
+@code{graph} element.
+@end defvr
+
+@defvr {Required} key
+@defvrx {Required} value
+A key-value pair to set for the target.
+
+In the corpus, @code{key} is @code{cellPropId} or, rarely,
+@code{diagProps}, and @code{value} is always the @code{id} of the
+parent @code{setCellProperties}.
+@end defvr
+
+@subsubheading The @code{setStyle} Element
+
+Parent: @code{setCellProperties} @*
+Contents: empty
+
+This element associates a style with the target.
+
+@defvr {Required} target
+The @code{id} of an element whose style is to be set.  In the corpus,
+this is always the @code{id} of an @code{interval}, @code{labeling},
+or, rarely, @code{graph} element.
+@end defvr
+
+@defvr {Required} style
+The @code{id} of a @code{style} element that identifies the style to
+set on the target.
+@end defvr
+
+@subsubheading The @code{setFormat} Element
+
+@format
+Parent: @code{setCellProperties}
+Contents:
+    @code{format}
+  @math{|} @code{numberFormat}
+  @math{|} @code{stringFormat}@math{+}
+  @math{|} @code{dateTimeFormat}
+@end format
+
+This element sets the format of the target, ``format'' in this case
+meaning an 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}).  In version 2.5
+and earlier, @code{setFormat} contains one of a number of child
+elements that correspond to the different varieties of print formats.
+In version 2.7 and later, @code{setFormat} instead always contains a
+@code{format} element.
+
+@subsubheading The @code{format} Element
+
+Parent: @code{sourceVariable}, @code{derivedVariable}, @code{formatMapping}, @code{labeling}, @code{formatMapping}, @code{setFormat} @*
+Contents: (@code{affix}@math{+} @math{|} @code{relabel})?
+
+This element determines a format, equivalent to an SPSS print format.
+The following attribute determines the high-level kind of formatting
+in use:
+
+@defvr {Optional} baseFormat
+One of @code{date}, @code{time}, @code{dateTime}, or
+@code{elapsedTime}.  When this attribute is omitted, this element is a
+numeric or string format.
+@end defvr
+
+@noindent
+Whether, in the corpus, other attributes are always present (``yes''),
+never present (``no''), or sometimes present (``opt'') depends on
+@code{baseFormat}:
+
+@multitable {maximumFractionDigits} {@code{dateTime}} {@code{elapsedTime}} {number} {string}
+@headitem Attribute @tab @code{dateTime} @tab @code{elapsedTime} @tab number @tab string
+@item errorCharacter        @tab yes @tab yes @tab yes @tab opt
+@item separatorChars        @tab yes @tab  no @tab  no @tab no
+@item @w{ }
+@item mdyOrder              @tab yes @tab  no @tab  no @tab no
+@item @w{ }
+@item showYear              @tab yes @tab  no @tab  no @tab no
+@item yearAbbreviation      @tab yes @tab  no @tab  no @tab no
+@item @w{ }
+@item showMonth             @tab yes @tab  no @tab  no @tab no
+@item monthFormat           @tab yes @tab  no @tab  no @tab no
+@item @w{ }
+@item showDay               @tab yes @tab opt @tab  no @tab no
+@item dayPadding            @tab yes @tab opt @tab  no @tab no
+@item dayOfMonthPadding     @tab yes @tab  no @tab  no @tab no
+@item dayType               @tab yes @tab  no @tab  no @tab no
+@item @w{ }
+@item showHour              @tab yes @tab opt @tab  no @tab no
+@item hourFormat            @tab yes @tab opt @tab  no @tab no
+@item hourPadding           @tab yes @tab yes @tab  no @tab no
+@item @w{ }
+@item showMinute            @tab yes @tab yes @tab  no @tab no
+@item minutePadding         @tab yes @tab yes @tab  no @tab no
+@item @w{ }
+@item showSecond            @tab yes @tab yes @tab  no @tab no
+@item secondPadding         @tab  no @tab yes @tab  no @tab no
+@item @w{ }
+@item showMillis            @tab  no @tab yes @tab  no @tab no
+@item @w{ }
+@item minimumIntegerDigits  @tab  no @tab  no @tab yes @tab no
+@item maximumFractionDigits @tab  no @tab yes @tab yes @tab no
+@item minimumFractionDigits @tab  no @tab yes @tab yes @tab no
+@item useGrouping           @tab  no @tab opt @tab  no @tab no
+@item @w{ }
+@item tryStringsAsNumbers   @tab  no @tab  no @tab  no @tab no
+@item @w{ }
+@item scientific            @tab  no @tab  no @tab yes @tab no
+@item small                 @tab  no @tab  no @tab opt @tab no
+@item @w{ }
+@item suffix                @tab  no @tab  no @tab opt @tab no
+@end multitable
+
+Each attribute is described below.
+
+@defvr {Attribute} errorCharacter
+A character that replaces the formatted value when it cannot otherwise
+be represented in the given format.  Always @samp{*}.
+@end defvr
+
+@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} dayPadding
+@defvrx {Attribute} dayOfMonthPadding
+@defvrx {Attribute} hourPadding
+@defvrx {Attribute} minutePadding
+@defvrx {Attribute} secondPadding
+These attributes presumably control whether each field in the output
+is padded with spaces to its maximum width, but the details are not
+understood.  The only observed value for any of these attributes is
+@code{true}.
+@end defvr
+
+@defvr {Attribute} showDay
+@defvrx {Attribute} showHour
+@defvrx {Attribute} showMinute
+@defvrx {Attribute} showSecond
+@defvrx {Attribute} showMillis
+These attributes presumably control whether each field is displayed
+in the output, but the details are not understood.  The only
+observed value for any of these attributes is @code{true}.
+@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