@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 Structure heading Element
@defvr {Optional} @code{creation-date-time}
The date and time at which the SPV file was written, in a
-locale-specific format, e.g. @code{Friday, May 16, 2014 6:47:37 PM
+locale-specific format, e.g.@: @code{Friday, May 16, 2014 6:47:37 PM
PDT} or @code{lunedì 17 marzo 2014 3.15.48 CET} or even @code{Friday,
December 5, 2014 5:00:19 o'clock PM EST}.
@end defvr
@node SPV Structure @code{text} Element (Inside @code{pageParagraph})
@subsection The @code{text} Element (Inside @code{pageParagraph})
-Parent: @code{pageParagraph} @*
+Parent: @code{pageParagraph}
Contents: CDATA?
This @code{text} element is nested inside a @code{pageParagraph}. There
and have no semantic significance.
@item 00, 01, @dots{}, ff.
-Bytes with fixed values are written in hexadecimal:
+A bytes with a fixed value, written as a pair of hexadecimal digits.
@item i0, i1, @dots{}, i9, i10, i11, @dots{}
-32-bit integers with fixed values are written in decimal, prefixed by
+@itemx b0, b1, @dots{}, b9, b10, b11, @dots{}
+A 32-bit integer in little-endian or big-endian byte order,
+respectively, with a fixed value, written in decimal, prefixed by
@samp{i}.
@item byte
-An arbitrary byte.
+A byte.
+
+@item bool
+A byte with value 0 or 1.
+
+@item int16
+@itemx be16
+A 16-bit integer in little-endian or big-endian byte order,
+respectively.
@item int
-An arbitrary 32-bit integer.
+@itemx be32
+A 32-bit integer in little-endian or big-endian byte order,
+respectively.
+
+@item int64
+@itemx be64
+A 64-bit integer in little-endian or big-endian byte order,
+respectively.
@item double
-An arbitrary 64-bit IEEE floating-point number.
+A 64-bit IEEE floating-point number.
+
+@item float
+A 32-bit IEEE floating-point number.
@item string
-A 32-bit integer followed by the specified number of bytes of
-character data. (The encoding is indicated by the Formats
-nonterminal.)
+@itemx bestring
+A 32-bit integer, in little-endian or big-endian byte order,
+respectively, followed by the specified number of bytes of character
+data. (The encoding is indicated by the Formats nonterminal.)
@item @var{x}?
@var{x} is optional, e.g.@: 00? is an optional zero byte.
In a version 3 @file{.bin} member, @var{x}; in version 1, nothing.
@end table
-All integer and floating-point values in this format use little-endian
-byte order.
+Little-endian byte order is far more common in this format, but a few
+pieces of the format use big-endian byte order.
A ``light'' detail member @file{.bin} consists of a number of sections
concatenated together, terminated by a byte 01:
@cartouche
@format
-LightMember @result{} Header Title Caption Footnotes Fonts Formats Dimensions Data 01
+LightMember @result{}
+ Header Title
+ Caption Footnotes
+ Fonts Borders PrintSettings TableSettings Formats
+ Dimensions Data
+ 01
@end format
@end cartouche
@menu
* SPV Light Member Header::
* SPV Light Member Title::
-* PSV Light Member Caption::
+* SPV Light Member Caption::
* SPV Light Member Footnotes::
* SPV Light Member Fonts::
+* SPV Light Member Borders::
+* SPV Light Member Print Settings::
+* SPV Light Member Table Settings::
* SPV Light Member Formats::
* SPV Light Member Dimensions::
* SPV Light Member Categories::
@node SPV Light Member Header
@subsection Header
-An SPV file begins with an 39-byte header:
+An SPV light member begins with a 39-byte header:
@cartouche
@format
Header @result{}
01 00
(i1 @math{|} i3)[@t{version}]
- 01 (00 @math{|} 01) byte*21 00 00
- int[@t{table-id}] byte*4
+ 01 bool*4 int
+ int[@t{min-column-width}] int[@t{max-column-width}]
+ int[@t{min-row-width}] int[@t{max-row-width}]
+ int64[@t{table-id}]
@end format
@end cartouche
@code{table-id} is a binary version of the @code{tableId} attribute in
the structure member that refers to the detail member. For example,
-if @code{tableId} is @code{-4154297861994971133}, then @code{table-id}
-would be 0xdca00003.
+if @code{tableId} is @code{-4122591256483201023}, then @code{table-id}
+would be 0xc6c99d183b300001.
+
+@code{min-column-width} is the minimum width that a column will be
+assigned automatically. @code{max-column-width} is the maximum width
+that a column will be assigned to accommodate a long column label.
+@code{min-row-width} and @code{max-row-width} are a similar range for
+the width of row labels. All of these measurements are in 1/96 inch
+units.
The meaning of the other variable parts of the header is not known.
Title @result{}
Value[@t{title1}] 01?
Value[@t{c}] 01? 31
- Value[@t{title2}] 01? 00? 58
+ Value[@t{title2}] 01?
@end format
@end cartouche
well formatted. For example, for a frequency table, @code{title1} and
@code{title2} name the variable and @code{c} is simply ``Frequencies''.
-@node PSV Light Member Caption
+@node SPV Light Member Caption
@subsection Caption
@cartouche
@format
-Caption @result{} 58 @math{|} 31 Value[@t{caption}]
+Caption @result{} Caption1 Caption2
+Caption1 @result{} 31 Value @math{|} 58
+Caption2 @result{} 31 Value @math{|} 58
@end format
@end cartouche
-The @code{caption}, if presented, is shown below the table.
+The Caption, if present, is shown below the table. Caption2 is
+normally present. Caption1 is only rarely nonempty; it might reflect
+user editing of the caption.
@node SPV Light Member Footnotes
@subsection Footnotes
@format
Fonts @result{} 00 Font*8
Font @result{}
- byte[@t{index}] 31 string[@t{typeface}] 00 00
- (10 @math{|} 20 @math{|} 40 @math{|} 50 @math{|} 70 @math{|} 80)[@t{f1}] 41
- (i0 @math{|} i1 @math{|} i2)[@t{f2}] 00
- (i0 @math{|} i2 @math{|} i64173)[@t{f3}]
- (i0 @math{|} i1 @math{|} i2 @math{|} i3)[@t{f4}]
- string[@t{fgcolor}] string[@t{bgcolor}] i0 i0 00
- v3(int[@t{f5}] int[@t{f6}] int[@t{f7}] int[@t{f8}]))
+ byte[@t{index}] 31
+ string[@t{typeface}] float[@t{size}] int[@t{style}] bool[@t{underline}]
+ int[@t{halign}] int[@t{valign}]
+ string[@t{fgcolor}] string[@t{bgcolor}]
+ byte[@t{alternate}] string[@t{altfg}] string[@t{altbg}]
+ v3(int[@t{left-margin}] int[@t{right-margin}] int[@t{top-margin}] int[@t{bottom-margin}])
@end format
@end cartouche
Each Font represents the font style for a different element, in the
-following order: title, caption, footnote, row labels, column labels,
-corner labels, data, and layers.
+following order: title, caption, footer, corner, column
+labels, row labels, data, and layers.
@code{index} is the 1-based index of the Font, i.e. 1 for the first
Font, through 8 for the final Font.
is @code{SansSerif} in over 99% of instances and @code{Times New
Roman} in the rest.
+@code{size} is the size of the font, in points. The most common size
+in the corpus is 12 points.
+
+@code{style} is a bit mask. Bit 0 (with value 1) is set for bold, bit
+1 (with value 2) is set for italic.
+
+@code{underline} is 1 if the font is underlined, 0 otherwise.
+
+@code{halign} specifies horizontal alignment: 0 for center, 2 for
+left, 4 for right, 61453 for decimal, 64173 for mixed. Mixed
+alignment varies according to type: string data is left-justified,
+numbers and most other formats are right-justified.
+
+@code{valign} specifies vertical alignment: 0 for center, 1 for top, 3
+for bottom.
+
@code{fgcolor} and @code{bgcolor} are the foreground color and
background color, respectively. In the corpus, these are always
@code{#000000} and @code{#ffffff}, respectively.
-The meaning of the remaining data is unknown. It seems likely to
-include font sizes, horizontal and vertical alignment, attributes such
-as bold or italic, and margins.
-
-The table below lists the values observed in the corpus. When a cell
-contains a single value, then 99@math{+}% of the corpus contains that value.
-When a cell contains a pair of values, then the first value is seen in
-about two-thirds of the corpus and the second value in about the
-remaining one-third. In fonts that include multiple pairs, values are
-correlated, that is, for font 3, f5 = 24, f6 = 24, f7 = 2 appears
-about two-thirds of the time, as does the combination of f4 = 0, f6 =
-10 for font 7.
-
-@multitable {font} {40} {f2} {64173} {0/1} {24/11} {10/11} {2/3} {f8}
-@headitem font @tab f1 @tab f2 @tab f3 @tab f4 @tab f5 @tab f6 @tab f7 @tab f8
-@item 1 @tab 40 @tab 1 @tab 0 @tab 0 @tab 8 @tab 10/11 @tab 1 @tab 8
-@item 2 @tab 40 @tab 0 @tab 2 @tab 1 @tab 8 @tab 10/11 @tab 1 @tab 1
-@item 3 @tab 40 @tab 0 @tab 2 @tab 1 @tab 24/11 @tab 24/ 8 @tab 2/3 @tab 4
-@item 4 @tab 40 @tab 0 @tab 2 @tab 3 @tab 8 @tab 10/11 @tab 1 @tab 1
-@item 5 @tab 40 @tab 0 @tab 0 @tab 1 @tab 8 @tab 10/11 @tab 1 @tab 4
-@item 6 @tab 40 @tab 0 @tab 2 @tab 1 @tab 8 @tab 10/11 @tab 1 @tab 4
-@item 7 @tab 40 @tab 0 @tab 64173 @tab 0/1 @tab 8 @tab 10/11 @tab 1 @tab 1
-@item 8 @tab 40 @tab 0 @tab 2 @tab 3 @tab 8 @tab 10/11 @tab 1 @tab 4
-@end multitable
+@code{alternate} is 01 if rows should alternate colors, 00 if all rows
+should be the same color. When @code{alternate} is 01, @code{altfg}
+and @code{altbg} specify the colors for the alternate rows.
+
+@code{left-margin}, @code{right-margin}, @code{top-margin}, and
+@code{bottom-margin} are measured in multiples of 1/96 inch.
+
+@node SPV Light Member Borders
+@subsection Borders
+
+@cartouche
+@format
+Borders @result{}
+ b1[@t{endian}]
+ be32[@t{n-borders}] Border*[@t{n-borders}]
+ bool[@t{show-grid-lines}]
+ 00 00 00
+
+Border @result{}
+ be32[@t{border-type}]
+ be32[@t{stroke-type}]
+ be32[@t{color}]
+@end format
+@end cartouche
+
+The Borders reflect how borders between regions are drawn.
+
+The fixed value of @code{endian} can be used to validate the
+endianness.
+
+@code{show-grid-lines} is 1 to draw grid lines, otherwise 0.
+
+Each Border describes one kind of border. @code{n-borders} seems to
+always be 19. Each @code{border-type} appears once (although in an
+unpredictable order) and correspond to the following borders:
+
+@table @asis
+@item 0
+Title.
+@item 1@dots{}4
+Left, top, right, and bottom outer frame.
+@item 5@dots{}8
+Left, top, right, and bottom inner frame.
+@item 9, 10
+Left and top of data area.
+@item 11, 12
+Horizontal and vertical dimension rows.
+@item 13, 14
+Horizontal and vertical dimension columns.
+@item 15, 16
+Horizontal and vertical category rows.
+@item 17, 18
+Horizontal and vertical category columns.
+@end table
+
+@code{stroke-type} describes how a border is drawn, as one of:
+
+@table @asis
+@item 0
+No line.
+@item 1
+Solid line.
+@item 2
+Dashed line.
+@item 3
+Thick line.
+@item 4
+Thin line.
+@item 5
+Double line.
+@end table
+
+@code{color} is an RGB color. Bits 24--31 are alpha, bits 16--23 are
+red, 8--15 are green, 0--7 are blue. An alpha of 255 indicates an
+opaque color, therefore opaque black is 0xff000000.
+
+@node SPV Light Member Print Settings
+@subsection Print Settings
+
+@cartouche
+@format
+PrintSettings @result{}
+ b1[@t{endian}]
+ bool[@t{all-layers}]
+ bool[@t{paginate-layers}]
+ bool[@t{fit-width}]
+ bool[@t{fit-length}]
+ bool[@t{top-continuation}]
+ bool[@t{bottom-continuation}]
+ be32[@t{n-orphan-lines}]
+ bestring[@t{continuation-string}]
+@end format
+@end cartouche
+
+The PrintSettings reflect settings for printing. The fixed value of
+@code{endian} can be used to validate the endianness.
+
+@code{all-layers} is 1 to print all layers, 0 to print only the
+visible layers.
+
+@code{paginate-layers} is 1 to print each layer at the start of a new
+page, 0 otherwise. (This setting is honored only @code{all-layers} is
+1, since otherwise only one layer is printed.)
+
+@code{fit-width} and @code{fit-length} control whether the table is
+shrunk to fit within a page's width or length, respectively.
+
+@code{n-orphan-lines} is the minimum number of rows or columns to put
+in one part of a table that is broken across pages.
+
+If @code{top-continuation} is 1, then @code{continuation-string} is
+printed at the top of a page when a table is broken across pages for
+printing; similarly for @code{bottom-continuation} and the bottom of a
+page. Usually, @code{continuation-string} is empty.
+
+@node SPV Light Member Table Settings
+@subsection Table Settings
+
+@cartouche
+@format
+TableSettings @result{}
+ be32[@t{endian}]
+ be32
+ be32[@t{current-layer}]
+ bool[@t{omit-empty}]
+ bool[@t{show-row-labels-in-corner}]
+ bool[@t{show-alphabetic-markers}]
+ bool[@t{footnote-marker-position}]
+ v3(
+ byte
+ be32[@t{n}] byte*[@t{n}]
+ bestring[@t{notes}]
+ bestring[@t{table-look}]
+ 00...
+ )
+@end format
+@end cartouche
+
+The TableSettings reflect display settings. The fixed value of
+@code{endian} can be used to validate the endianness.
+
+@code{current-layer} is the displayed layer.
+
+If @code{omit-empty} is 1, empty rows or columns (ones with nothing in
+any cell) are hidden; otherwise, they are shown.
+
+If @code{show-row-labels-in-corner} is 1, then row labels are shown in
+the upper left corner; otherwise, they are shown nested.
+
+If @code{show-alphabetic-markers} is 1, markers are shown as letters
+(e.g. @samp{a}, @samp{b}, @samp{c}, @dots{}); otherwise, they are
+shown as numbers starting from 1.
+
+When @code{footnote-marker-position} is 1, footnote markers are shown
+as superscripts, otherwise as subscripts.
+
+@code{notes} is a text string that contains user-specified notes. It
+is displayed when the user hovers the cursor over the table, like
+``alt text'' on a webpage. It is not printed. It is usually empty.
+
+@code{table-look} is the name of a SPSS ``TableLook'' table style,
+such as ``Default'' or ``Academic''; it is often empty.
+
+TableSettings ends with an arbitrary number of null bytes.
@node SPV Light Member Formats
@subsection Formats
@cartouche
@format
Formats @result{}
- int[@t{n1}] byte*[@t{n1}]
- int[@t{n2}] byte*[@t{n2}]
- int[@t{n3}] byte*[@t{n3}]
- int[@t{n4}] int*[@t{n4}]
+ int[@t{nwidths}] int*[@t{nwidths}]
string[@t{encoding}]
- (i0 @math{|} i-1) (00 @math{|} 01) 00 (00 @math{|} 01)
- int
+ int (00 @math{|} 01) 00 (00 @math{|} 01)
+ int[@t{epoch}]
byte[@t{decimal}] byte[@t{grouping}]
- int[@t{n-ccs}] string*[@t{n-ccs}]
+ CustomCurrency
v1(i0)
v3(count(count(X5) count(X6)))
+CustomCurrency @result{} int[@t{n-ccs}] string*[@t{n-ccs}]
+
X5 @result{} byte*33 int[@t{n}] int*[@t{n}]
X6 @result{}
01 00 (03 @math{|} 04) 00 00 00
string[@t{command}] string[@t{subcommand}]
string[@t{language}] string[@t{charset}] string[@t{locale}]
- (00 @math{|} 01) 00 (00 @math{|} 01) (00 @math{|} 01)
- int
+ (00 @math{|} 01) 00 bool bool
+ int[@t{epoch}]
byte[@t{decimal}] byte[@t{grouping}]
- byte*8 01
- (string[@t{dataset}] string[@t{datafile}] i0 int i0)?
- int[@t{n-ccs}] string*[@t{n-ccs}]
- 2e (00 @math{|} 01) (i2000000 i0)?
+ double[@t{small}] 01
+ (string[@t{dataset}] string[@t{datafile}] i0 int[@t{date}] i0)?
+ CustomCurrency
+ byte[@t{missing}] bool (i2000000 i0)?
@end format
@end cartouche
-In every example in the corpus, @code{n1} is 240. The meaning of the
-bytes that follow it is unknown.
-
-In every example in the corpus, @code{n2} is 18 and the bytes that
-follow it are @code{00 00 00 01 00 00 00 00 00 00 00 00 00 02 00 00 00
-00}. The meaning of these bytes is unknown.
-
-In every example in the corpus for version 1, @code{n3} is 16 and the
-bytes that follow it are @code{00 00 00 01 00 00 00 01 00 00 00 00 01
-01 01 01}. In version 3, observed @code{n3} varies from 117 to 150,
-and its bytes include a 1-byte count at offset 0x34. When the count
-is nonzero, a text string of that length at offset 0x35 is the name of
-a ``TableLook'', e.g. ``Default'' or ``Academic''.
-
-Observed values of @code{n4} vary from 0 to 17. Out of 7,060 examples
-in the corpus, it is nonzero only 36 times.
+If @code{nwidths} is nonzero, then the accompanying integers are
+column widths as manually adjusted by the user. (Row heights are
+computed automatically based on the widths.)
@code{encoding} is a character encoding, usually a Windows code page
such as @code{en_US.windows-1252} or @code{it_IT.windows-1252}. The
rest of the character strings in the member use this encoding. The
encoding string is itself encoded in US-ASCII.
+@code{epoch} is the year that starts the epoch. A 2-digit year is
+interpreted as belonging to the 100 years beginning at the epoch. The
+default epoch year is 69 years prior to the current year; thus, in
+2017 this field by default contains 1948. In the corpus, @code{epoch}
+ranges from 1943 to 1948, plus some contain -1.
+
@code{decimal} is the decimal point character. The observed values
are @samp{.} and @samp{,}.
@samp{'} (apostrophe), @samp{ } (space), and zero (presumably
indicating that digits should not be grouped).
+@code{dataset} is the name of the dataset analyzed to produce the
+output, e.g.@: @code{DataSet1}, and @code{datafile} the name of the
+file it was read from, e.g.@: @file{C:\Users\foo\bar.sav}. The latter
+is sometimes the empty string.
+
+@code{date} is a date, as seconds since the epoch, i.e.@: since
+January 1, 1970. Pivot tables within an SPV files often have dates a
+few minutes apart, so this is probably a creation date for the tables
+rather than for the file.
+
+Sometimes @code{dataset}, @code{datafile}, and @code{date} are present
+and other times they are absent. The reader can distinguish by
+assuming that they are present and then checking whether the
+presumptive @code{dataset} contains a null byte (a valid string never
+will).
+
@code{n-ccs} is observed as either 0 or 5. When it is 5, the
following strings are CCA through CCE format strings. @xref{Custom
Currency Formats,,, pspp, PSPP}. Most commonly these are all
ValueMod @result{}
31 i0 (i0 @math{|} i1 string[@t{subscript}])
v1(00 (i1 @math{|} i2) 00 00 int 00 00)
- v3(count(FormatString Style ValueModUnknown))
- @math{|} 31 i1 int[@t{footnote-number}] Format
- @math{|} 31 i2 (00 @math{|} 01 @math{|} 02) 00 (i1 @math{|} i2 @math{|} i3) Format
- @math{|} 31 i3 00 00 01 00 i2 Format
+ v3(count(FormatString
+ (31 Style | 58)
+ (31 Style2 | 58)))
+ @math{|} 31 int[@t{n-refs}] int16*[@t{n-refs}] Format
@math{|} 58
-Style @result{} 58 @math{|} 31 01? 00? 00? 00? 01 string[@t{fgcolor}] string[@t{bgcolor}] string[@t{typeface}] byte
+
Format @result{} 00 00 count(FormatString Style 58)
-FormatString @result{} count((i0 (58 @math{|} 31 string))?)
-ValueModUnknown @result{} 58 @math{|} 31 i0 i0 i0 i0 01 00 (01 @math{|} 02 @math{|} 08) 00 08 00 0a 00)
+FormatString @result{} count((count((i0 58)?) (58 @math{|} 31 string))?)
+
+Style @result{}
+ bool[@t{bold}] bool[@t{italic}] bool[@t{underline}] bool[@t{show}]
+ string[@t{fgcolor}] string[@t{bgcolor}]
+ string[@t{typeface}] byte[@t{size}]
+
+Style2 @result{}
+ int[@t{halign}] int[@t{valign}] double[@t{offset}]
+ int16[@t{left-margin}] int16[@t{right-margin}]
+ int16[@t{top-margin}] int16[@t{bottom-margin}]
@end format
@end cartouche
-The @code{footnote-number}, if present, specifies a footnote that the
-Value references. The footnote's marker is shown appended to the main
-text of the Value, as a superscript.
+A ValueMod that begins with ``31 i0'' specifies a string to append to
+the main text of the Value, as a subscript. The subscript text is a
+brief indicator, e.g.@: @samp{a} or @samp{a,b}, with its meaning
+indicated by the table caption. In this usage, subscripts are similar
+to footnotes. One apparent difference is that a Value can only
+reference one footnote but a subscript can list more than one letter.
-The @code{subscript}, if present, specifies a string to append to the
-main text of the Value, as a subscript. The subscript text is a brief
-indicator, e.g.@: @samp{a} or @samp{a,b}, with its meaning indicated
-by the table caption. In this usage, subscripts are similar to
-footnotes; one apparent difference is that a Value can only reference
-one footnote but a subscript can list more than one letter.
+A ValueMod that begins with 31 followed by a nonzero ``int'' specifies
+a footnote or footnotes that the Value references. Footnote markers
+are shown appended to the main text of the Value, as superscripts.
The Format, if present, is a format string for substitutions using the
syntax explained previously. It appears to be an English-language
version of the localized format string in the Value in which the
Format is nested.
-The Style, if present, changes the style for this individual Value.
+Style and Style2, if present, change the style for this individual
+Value. @code{bold}, @code{italic}, and @code{underline} control the
+particular style. @code{fgcolor} and @code{bgcolor} are strings, such
+as @code{#ffffff}. The @code{size} is a font size in units of 1/96
+inch.
+
+@code{halign} is 0 for center, 2 for left, 4 for right, 6 for decimal,
+0xffffffad for mixed. For decimal alignment, @code{offset} is the
+decimal point's offset from the right side of the cell, in units of
+1/72 inch.
+
+@code{valign} specifies vertical alignment: 0 for center, 1 for top, 3
+for bottom.
+
+@code{left-margin}, @code{right-margin}, @code{top-margin}, and
+@code{bottom-margin} are in units of 1/72 inch.
@node SPV Legacy Detail Member Binary Format
@section Legacy Detail Member Binary Format
This format is still under investigation.
-All elements have an optional @code{id} attribute.
+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
@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
@node SPV Detail userSource Element
@subsection The @code{userSource} Element
-@format
Parent: @code{visualization} @*
Contents:
-@end format
This element has the following attributes.
@node SPV Detail sourceVariable Element
@subsection The @code{sourceVariable} Element
-@format
Parent: @code{visualization} @*
Contents: @code{extension}* (@code{format} @math{|} @code{stringFormat})?
-@end format
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{.bin} member that corresponds to this @file{.xml}.
+from the @file{tableData.bin} member that corresponds to this
+@file{.xml}.
This element has the following attributes.
@defvr {Required} source
Always set to @code{tableData}, the @code{source-name} in the
-corresponding @file{.bin} member (@pxref{SPV Legacy Member Metadata}).
+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{.bin} member (@pxref{SPV Legacy Member Data}).
+the corresponding @file{tableData.bin} member (@pxref{SPV Legacy
+Member Data}).
@end defvr
@defvr {Optional} dependsOn
@node SPV Detail derivedVariable Element
@subsection The @code{derivedVariable} Element
-@format
Parent: @code{visualization} @*
Contents: @code{extension}* (@code{format} @math{|} @code{stringFormat} @code{valueMapEntry}*)
-@end format
Like @code{sourceVariable}, this element defines a variable whose
values can be used elsewhere in the visualization. Instead of being
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
-@format
Parent: @code{derivedVariable} @*
Contents: empty
-@end format
A @code{valueMapEntry} element defines a mapping from one or more
values of a source expression to a target value. (In the corpus, the
@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{axis} Element
+
+Parent: @code{facetLevel} @*
+Contents: @code{label}? @code{majorTicks}
+
+@defvr {Attribute} style
+The @code{id} of a @code{style} element.
+@end defvr
+
+@subsubheading The @code{label} Element
+
+Parent: @code{axis} or @code{labelFrame} @*
+Contents: @code{text}@math{+} @math{|} @code{descriptionGroup}
+
+This element represents a label on some aspect of the table. For example,
+the table's title is a @code{label}.
+
+The contents of the label can be one or more @code{text} elements or a
+@code{descriptionGroup}.
+
+@defvr {Attribute} style
+@defvrx {Optional} textFrameStyle
+Each of these is the @code{id} of 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 {Optional} purpose
+The kind of entity being labeled, one of @code{title},
+@code{subTitle}, @code{layer}, or @code{footnote}.
+@end defvr
+
+@subsubheading The @code{descriptionGroup} Element
+
+Parent: @code{label} @*
+Contents: (@code{description} @math{|} @code{text})@math{+}
+
+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
+
+@subsubheading The @code{description} Element
+
+Parent: @code{descriptionGroup} @*
+Contents: empty
+
+A @code{description} is like a macro that expands to some property of
+the target of its parent @code{descriptionGroup}.
+
+@defvr {Attribute} name
+The name of the property. Only @code{variable} and @code{value}
+appear in the corpus.
+@end defvr
+
+@subsubheading The @code{majorTicks} Element
+
+Parent: @code{axis} @*
+Contents: @code{gridline}?
+
+@defvr {Attribute} labelAngle
+@defvrx {Attribute} length
+Both always defined to @code{0}.
+@end defvr
+
+@defvr {Attribute} style
+@defvrx {Attribute} tickFrameStyle
+Each of these is the @code{id} of 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
+
+@subsubheading The @code{gridline} Element
+
+Parent: @code{majorTicks} @*
+Contents: empty
+
+Represents ``gridlines,'' which for a table represents the lines
+between the rows or columns of a table (XXX?).
+
+@defvr {Attribute} style
+The style for the gridline.
+@end defvr
+
+@defvr {Attribute} zOrder
+Observed as a number between 28 and 31. Does not seem to be
+important.
+@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, as further restricted
+by the optional @code{union} element if present. The @code{target}
+values often used, e.g.@: @code{graph} or @code{labeling}, actually
+affect every cell, so the @code{union} element is a useful
+restriction.
+
+@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}. 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
+
+@subsubheading The @code{setMetaData} Element
+
+Parent: @code{setCellProperties} @*
+Contents: empty
+
+This element is not known to have any visible effect.
+
+@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 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.
+
+XXX reinvestigate the above claim about versions: it appears to be
+incorrect.
+
+The @code{setFormat} element itself has the following attributes.
+
+@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{majorTicks} or
+@code{labeling} element.
+@end defvr
+
+@defvr {Optional} reset
+If this is @code{true}, this format overrides the target's previous
+format. If it is @code{false}, the adds to the previous format. In
+the corpus this is always @code{true}. The default behavior is
+unknown.
+@end defvr
+
+@menu
+* SPV Detail format Element::
+* SPV Detail numberFormat Element::
+* SPV Detail stringFormat Element::
+* SPV Detail dateTimeFormat Element::
+* SPV Detail affix Element::
+* SPV Detail relabel Element::
+* SPV Detail union Element::
+@end menu
+
+@node SPV Detail format Element
+@subsubsection The @code{format} Element
+
+Parent: @code{sourceVariable}, @code{derivedVariable}, @code{formatMapping}, @code{labeling}, @code{formatMapping}, @code{setFormat} @*
+Contents: (@code{affix}@math{+} @math{|} @code{relabel}@math{+})?
+
+This element appears only in schema version 2.7 (@pxref{SPV Detail
+visualization Element}).
+
+This element determines a format, equivalent to an SPSS print format.
+
+@subsubheading Attributes for All Formats
+
+These attributes apply to all kinds of formats. The most important of
+these attributes determines the high-level kind of formatting in use:
+
+@defvr {Optional} baseFormat
+Either @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 @w{ }
+@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 yes @tab no
+@item scientific @tab no @tab no @tab yes @tab no
+@item small @tab no @tab no @tab opt @tab no
+@item suffix @tab no @tab no @tab opt @tab no
+@item @w{ }
+@item tryStringsAsNumbers @tab no @tab no @tab no @tab yes
+@item @w{ }
+@end multitable
+
+@defvr {Attribute} errorCharacter
+A character that replaces the formatted value when it cannot otherwise
+be represented in the given format. Always @samp{*}.
+@end defvr
+
+@subsubheading Date and Time Attributes
+
+These attributes are used with @code{dateTime} and @code{elapsedTime}
+formats or both.
+
+@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
+
+@subsubheading Numeric Attributes
+
+These attributes are used for formats when @code{baseFormat} is
+@code{number}. Attributes @code{maximumFractionDigits}, and
+@code{minimumFractionDigits}, and @code{useGrouping} are also used
+when @code{baseFormat} is @code{elapsedTime}.
+
+@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} maximumFractionDigits
+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. It would make sense for the grouping character to come from
+the @code{separatorChars} attribute, but that attribute is only
+present when @code{baseFormat} is @code{dateTime} or
+@code{elapsedTime}, in the corpus at least. Perhaps that is because
+this attribute has only been observed as @code{false}.
+@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 {Optional} 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 {Optional} prefix
+@defvrx {Optional} suffix
+Specifies a prefix or a suffix to apply to the formatted number. Only
+@code{suffix} has been observed, with value @samp{%}.
+@end defvr
+
+@subsubheading String Attributes
+
+These attributes are used for formats when @code{baseFormat} is
+@code{string}.
+
+@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
+
+@node SPV Detail numberFormat Element
+@subsubsection The @code{numberFormat} Element
+
+Parent: @code{setFormat} @*
+Contents: @code{affix}@math{+}
+
+This element appears only in schema version 2.5 and earlier
+(@pxref{SPV Detail visualization Element}). Possibly this element
+could also contain @code{relabel} elements in a more diverse corpus.
+
+This element has the following attributes.
+
+@defvr {Attribute} maximumFractionDigits
+@defvrx {Attribute} minimumFractionDigits
+@defvrx {Attribute} minimumIntegerDigits
+@defvrx {Optional} scientific
+@defvrx {Optional} small
+@defvrx {Optional} suffix
+@defvrx {Optional} useGroupging
+The syntax and meaning of these attributes is the same as on the
+@code{format} element for a numeric format. @pxref{SPV Detail format
+element}.
+@end defvr
+
+@node SPV Detail stringFormat Element
+@subsubsection The @code{stringFormat} Element
+
+Parent: @code{setFormat} @*
+Contents: (@code{affix}@math{+} @math{|} @code{relabel}@math{+})?
+
+This element appears only in schema version 2.5 and earlier
+(@pxref{SPV Detail visualization Element}).
+
+This element has no attributes.
+
+@node SPV Detail dateTimeFormat Element
+@subsubsection The @code{dateTimeFormat} Element
+
+Parent: @code{setFormat} @*
+Contents: empty
+
+This element appears only in schema version 2.5 and earlier
+(@pxref{SPV Detail visualization Element}). Possibly this element
+could also contain @code{affix} and @code{relabel} elements in a more
+diverse corpus.
+
+The following attribute is required.
+
+@defvr {Attribute} baseFormat
+Either @code{dateTime} or @code{time}.
+@end defvr
+
+When @code{baseFormat} is @code{dateTime}, the following attributes
+are available.
+
+@defvr {Attribute} dayOfMonthPadding
+@defvrx {Attribute} dayPadding
+@defvrx {Attribute} dayType
+@defvrx {Attribute} hourFormat
+@defvrx {Attribute} hourPadding
+@defvrx {Attribute} mdyOrder
+@defvrx {Attribute} minutePadding
+@defvrx {Attribute} monthFormat
+@defvrx {Attribute} separatorChars
+@defvrx {Attribute} showDay
+@defvrx {Attribute} showHour
+@defvrx {Attribute} showMinute
+@defvrx {Attribute} showMonth
+@defvrx {Attribute} showSecond
+@defvrx {Attribute} showYear
+@defvrx {Attribute} yearAbbreviation
+The syntax and meaning of these attributes is the same as on the
+@code{format} element when that element's @code{baseFormat} is
+@code{dateTime}. @pxref{SPV Detail format Element}.
+@end defvr
+
+When @code{baseFormat} is @code{time}, the following attributes are
+available.
+
+@defvr {Attribute} hourFormat
+@defvrx {Attribute} hourPadding
+@defvrx {Attribute} minutePadding
+@defvrx {Attribute} monthFormat
+@defvrx {Attribute} separatorChars
+@defvrx {Attribute} showDay
+@defvrx {Attribute} showHour
+@defvrx {Attribute} showMinute
+@defvrx {Attribute} showMonth
+@defvrx {Attribute} showSecond
+@defvrx {Attribute} showYear
+@defvrx {Attribute} yearAbbreviation
+The syntax and meaning of these attributes is the same as on the
+@code{format} element when that element's @code{baseFormat} is
+@code{elapsedTime}. @pxref{SPV Detail format Element}.
+@end defvr
+
+@node SPV Detail affix Element
+@subsubsection The @code{affix} Element
+
+Parent: @code{format} or @code{numberFormat} or @code{stringFormat} @*
+Contents: empty
+
+Possibly this element could have @code{dateTimeFormat} as a parent in
+a more diverse corpus.
+
+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 relabel Element
+@subsubsection The @code{relabel} Element
+
+Parent: @code{format} or @code{stringFormat} @*
+Contents: empty
+
+Possibly this element could have @code{numberFormat} or
+@code{dateTimeFormat} as a parent in a more diverse corpus.
+
+This 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 union Element
+@subsubsection The @code{union} Element
+
+Parent: @code{setCellProperties} @*
+Contents: @code{intersect}@math{+}
+
+This element represents a set of cells, computed as the union of the
+sets represented by each of its children.
+
+@subsubheading The @code{intersect} Element
+
+Parent: @code{union} @*
+Contents: @code{where}@math{+} @math{|} @code{intersectWhere}?
+
+This element represents a set of cells, computed as the intersection
+of the sets represented by each of its children.
+
+Of the two possible children, in the corpus @code{where} is far more
+common, appearing thousands of times, whereas @code{intersectWhere}
+only appears 4 times.
+
+Most @code{intersect} elements have two or more children.
+
+@subsubheading The @code{where} Element
+
+Parent: @code{intersect} @*
+Contents: empty
+
+This element represents the set of cells in which the value of a
+specified variable falls within a specified set.
+
+@defvr {Attribute} variable
+The @code{id} of a variable, e.g.@: @code{dimension0categories} or
+@code{dimension0group0map}.
+@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
+
+@subsubheading The @code{intersectWhere}
+
+Parent: @code{intersect} @*
+Contents: empty
+
+The meaning of this element is unknown.
+
+@defvr {Attribute} variable
+@defvrx {Attribute} variable2
+The meaning of these attributes is unknown. In the four examples in
+the corpus they always take the values @code{dimension2categories} and
+@code{dimension0categories}, respectively.
+@end defvr