SPSS Viewer File Format
***********************

SPSS Viewer or .spv files, here called SPV files, are written by SPSS 16 and later to represent the contents of its output editor. This chapter documents the format, based on examination of a corpus of about 500 files from a variety of sources.  This description is detailed enough to read SPV files, but probably not enough to write them.

SPSS 15 and earlier versions use a completely different output format based on the Microsoft Compound Document Format.  This format is not documented here.

An SPV file is a Zip archive that can be read with zipinfo and unzip and similar programs.  The final member in the Zip archive is a file named META-INF/MANIFEST.MF.  This structure makes SPV files resemble Java ``JAR'' files (and ODF files), but whereas a JAR manifest contains a sequence of colon-delimited key/value pairs, an SPV manifest contains the string allowPivoting=true, without a new-line.  (This string may be the best way to identify an SPV file; it is invariant across the corpus.)

The rest of the members in an SPV file's Zip archive fall into two categories: structure and detail members.  Structure member names begin with outputViewerNNNNNNNNNN, where each N is a decimal digit, and end with .xml, and often include the string _heading in between.  Each of these members represents some kind of output item (a table, a heading, a block of text, etc.) or a group of them.  The member whose output goes at the beginning of the document is numbered 0, the next member in the output is numbered 1, and so on.

Structure members contain XML.  This XML is sometimes self-contained, but it often references detail members in the Zip archive, which are named as follows:

PREFIX_table.xml and PREFIX_tableData.bin
PREFIX_lightTableData.bin
     The structure of a table plus its data.  Older SPV files pair a PREFIX_table.xml file that describes the table's structure with a binary PREFIX_tableData.bin file that gives its data.  Newer SPV files (the majority of those in the corpus) instead include a single PREFIX_lightTableData.bin file that incorporates both into a single binary format.

PREFIX_warning.xml and PREFIX_warningData.bin
PREFIX_lightWarningData.bin
     Same format used for tables, with a different name.

PREFIX_notes.xml and PREFIX_notesData.bin
PREFIX_lightNotesData.bin
     Same format used for tables, with a different name.

PREFIX_chartData.bin and PREFIX_chart.xml
     The structure of a chart plus its data.  Charts do not have a ``light'' format.

PREFIX_pmml.scf
PREFIX_stats.scf

PREFIX_model.xml
     Not yet investigated.  The corpus contains few examples.

The PREFIX in the names of the detail members is typically an 11-digit decimal number that increases for each item, tending to skip values.  Older SPV files use different naming conventions.  Structure member refer to detail members by name, and so their exact names do not matter to readers as long as they are unique.

Structure Member Format
=======================

Structure members' XML files claim conformance with a collection of XML Schemas.  These schemas are distributed, under a nonfree license, with SPSS binaries.  Fortunately, the schemas are not necessary to understand the structure members.  To a degree, the schemas can even be deceptive because they document elements and attributes that are not in the corpus and do not document elements and attributes that are commonly found there.

Structure members use a different XML namespace for each schema, but these namespaces are not entirely consistent.  In some SPV files, for example, the viewer-tree schema is associated with namespace http://xml.spss.com/spss/viewer-tree and in others with http://xml.spss.com/spss/viewer/viewer-tree (note the additional viewer/).  Under either name, the schema URIs are not resolvable to obtain the schemas themselves.

One may ignore all of the above in interpreting a structure member. The actual XML has a simple and straightforward form that does not require a reader to take schemas or namespaces into account.

The elements found in structure members are documented below.  For each element, we note the possible parent elements and the element's contents.  The contents are specified as pseudo-regular expressions with the following conventions:

text
     XML text content.

CDATA
     XML CDATA content.

element
     The named element.

(...)
     Grouping multiple elements.

[X]
     An optional X.

A | B
     A choice between A and B.

X*
     Zero or more X.

For a diagram illustrating the hierarchy of elements within an SPV structure member, please refer to a PDF version of the manual.

The heading Element
-------------------

Parent: Document root or heading

Contents: pageSetup? label (container | heading)*

The root of a structure member is a heading, which represents a section of output beginning with a title (the label) and ordinarily followed by content containers or further nested (sub)-sections of output.

The document root heading, only, may also contain a pageSetup element.

The following attributes have been observed on both document root and nested heading elements.

 -- Optional: creator-version
     The version of the software that created this SPV file.  A string of the form xxyyzzww represents software version xx.yy.zz.ww, e.g. 21000001 is version 21.0.0.1.  Trailing pairs of zeros are sometimes omitted, so that 21, 210000, and 21000000 are all version 21.0.0.0 (and the corpus contains all three of those forms).

The following attributes have been observed on document root heading elements only:

 -- Optional: creator
     The directory in the file system of the software that created this SPV file.

 -- Optional: creation-date-time
     The date and time at which the SPV file was written, in a locale-specific format, e.g. Friday, May 16, 2014 6:47:37 PM PDT or lunedì 17 marzo 2014 3.15.48 CET or even Friday, December 5, 2014 5:00:19 o'clock PM EST.

 -- Optional: lockReader
     Whether a reader should be allowed to edit the output.  The possible values are true and false, but the corpus only contains false.

 -- Optional: schemaLocation
     This is actually an XML Namespace attribute.  A reader may ignore it.

The following attributes have been observed only on nested heading elements:

 -- Required: commandName
     The locale-invariant name of the command that produced the output, e.g. Frequencies, T-Test, Non Par Corr.

 -- Optional: visibility
     To what degree the output represented by the element is visible.  The only observed value is collapsed.

 -- Optional: locale
     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. en-US, en-GB, el-GR, sr-Cryl-RS.

 -- Optional: olang
     The output language, e.g. en, it, es, de, pt-BR.

The label Element
-----------------

Parent: heading or container

Contents: text

Every heading and container holds a label as its first child.  The root heading in a structure member always contains the string ``Output''.  Otherwise, the text in label describes what it labels, often by naming the statistical procedure that was executed, e.g. ``Frequencies'' or ``T-Test''.  Labels are often very generic, especially within a container, e.g. ``Title'' or ``Warnings'' or ``Notes''.  Label text is localized according to the output language, e.g. in Italian a frequency table procedure is labeled ``Frequenze''.

The corpus contains one example of an empty label, one that contains no text.

This element has no attributes.

The container Element
---------------------

Parent: heading

Contents: label (table | text)?

A container serves to label a table or a text item.

This element has the following attributes.

 -- Required: visibility
     Either visible or hidden, this indicates whether the container's content is displayed.

 -- Optional: text-align
     Presumably indicates the alignment of text within the container.  The only observed value is left.  Observed with nested table and text elements.

 -- Optional: width
     The width of the container in the form Npx, e.g. 1097px.

The text Element (Inside container)
-----------------------------------

Parent: container

Contents: html

This text element is nested inside a container.  There is a different text element that is nested inside a pageParagraph.

This element has the following attributes.

 -- Required: type
     One of title, log, or text.

 -- Optional: commandName
     As on the heading element.  For output not specific to a command, this is simply log.  The corpus contains one example of where commandName is present but set to the empty string.

 -- Optional: creator-version
     As on the heading element.

The html Element
----------------

Parent: text

Contents: CDATA

The CDATA contains an HTML document.  In some cases, the document starts with <html> and ends with </html; in others the html element is implied.  Generally the HTML includes a head element with a CSS stylesheet.  The HTML body often begins with <BR>.  The actual content ranges from trivial to simple: just discarding the CSS and tags yields readable results.

This element has the following attributes.

 -- Required: lang
     This always contains en in the corpus.

The table Element
-----------------

Parent: container

Contents: tableStructure

This element has the following attributes.

 -- Required: commandName
     As on the heading element.

 -- Required: type
     One of table, note, or warning.

 -- Required: subType
     The locale-invariant name for the particular kind of output that this table represents in the procedure.  This can be the same as commandName e.g. Frequencies, or different, e.g. Case Processing Summary.  Generic subtypes Notes and Warnings are often used.

 -- Required: tableId
     A number that uniquely identifies the table within the SPV file, typically a large negative number such as -4147135649387905023.

 -- Optional: creator-version
     As on the heading element.  In the corpus, this is only present for version 21 and up and always includes all 8 digits.

The tableStructure Element
--------------------------

Parent: table

Contents: dataPath

This element has no attributes.

The dataPath Element
--------------------

Parent: tableStructure

Contents: text

Contains the name of the Zip member that holds the table details, e.g. 0000000001437_lightTableData.bin.

This element has no attributes.

The pageSetup Element
---------------------

Parent: heading

Contents: pageHeader pageFooter

This element has the following attributes.

 -- Required: initial-page-number
     Always 1.

 -- Optional: chart-size
     Always as-is or a localization (!) of it (e.g. dimensione attuale, Wie vorgegeben).

 -- Optional: margin-left
 -- Optional: margin-right
 -- Optional: margin-top
 -- Optional: margin-bottom
     Margin sizes in the form SIZEin, e.g. 0.25in.

 -- Optional: paper-height
 -- Optional: paper-width
     Paper sizes in the form SIZEin, e.g. 8.5in by 11in for letter paper or 8.267in by 11.692in for A4 paper.

 -- Optional: reference-orientation
     Always 0deg.

 -- Optional: space-after
     Always 12pt.

The pageHeader and pageFooter Elements
--------------------------------------

Parent: pageSetup

Contents: pageParagraph*

This element has no attributes.

The pageParagraph Element
-------------------------

Parent: pageHeader or pageFooter

Contents: text

Text to go at the top or bottom of a page, respectively.

This element has no attributes.

The text Element (Inside pageParagraph)
---------------------------------------

Parent: pageParagraph Contents: CDATA?

This text element is nested inside a pageParagraph.  There is a different text element that is nested inside a container.

The element is either empty, or contains CDATA that holds almost-XHTML text: in the corpus, either an html or p element.  It is almost-XHTML because the html element designates the default namespace as http://xml.spss.com/spss/viewer/viewer-tree instead of an XHTML namespace, and because the CDATA can contain substitution variables: &[Page] for the page number and &[PageTitle] for the page title.

Typical contents (indented for clarity):

     <html xmlns="http://xml.spss.com/spss/viewer/viewer-tree">
         <head></head>
         <body>
             <p style="text-align:right; margin-top: 0">Page &[Page]</p>
         </body>
     </html>

This element has the following attributes.

 -- Required: type
     Always text.

Light Detail Member Format
==========================

This section describes the format of ``light'' detail .bin members.  These members have a binary format which we describe here in terms of a context-free grammar using the following conventions:

NonTerminal => ...
     Nonterminals have CamelCaps names, and => indicates a production.  The right-hand side of a production is often broken across multiple lines.  Break points are chosen for aesthetics only and have no semantic significance.

00, 01, ..., ff.
     Bytes with fixed values are written in hexadecimal:

i0, i1, ..., i9, i10, i11, ...
     32-bit integers with fixed values are written in decimal, prefixed by i.

byte
     An arbitrary byte.

int
     An arbitrary 32-bit integer.

double
     An arbitrary 64-bit IEEE floating-point number.

string
     A 32-bit integer followed by the specified number of bytes of character data.  (The encoding is indicated by the Formats nonterminal.)

X?
     X is optional, e.g. 00? is an optional zero byte.

X*N
     X is repeated N times, e.g. byte*10 for ten arbitrary bytes.

X[NAME]
     Gives X the specified NAME.  Names are used in textual explanations.  They are also used, also bracketed, to indicate counts, e.g. int[n] byte*[n] for a 32-bit integer followed by the specified number of arbitrary bytes.

A | B
     Either A or B.

(X)
     Parentheses are used for grouping to make precedence clear, especially in the presence of |, e.g. in 00 (01 | 02 | 03) 00.

count(X)
     A 32-bit integer that indicates the number of bytes in X, followed by X itself.

v1(X)
     In a version 1 .bin member, X; in version 3, nothing. (The .bin header indicates the version.)

v3(X)
     In a version 3 .bin member, X; in version 1, nothing.

All integer and floating-point values in this format use little-endian byte order.

A ``light'' detail member .bin consists of a number of sections concatenated together, terminated by a byte 01:

     LightMember => Header Title Caption Footnotes Fonts Formats Dimensions Data 01

The following sections go into more detail.

Header
------

An SPV file begins with an 39-byte header:

     Header =>
         01 00
         (i1 | i3)[version]
         01 (00 | 01) byte*21 00 00
         int[table-id] byte*4

version is a version number that affects the interpretation of some of the other data in the member.  We will refer to ``version 1'' and ``version 3'' later on and use v1(...) and v3(...) for version-specific formatting (as described previously).

table-id is a binary version of the tableId attribute in the structure member that refers to the detail member.  For example, if tableId is -4154297861994971133, then table-id would be 0xdca00003.

The meaning of the other variable parts of the header is not known.

Title
-----

     Title =>
         Value[title1] 01?
         Value[c] 01? 31
         Value[title2] 01? 00? 58

The Title, which follows the Header, specifies the pivot table's title twice, as title1 and title2.  In the corpus, they are always the same.

Whereas the Value in title1 and in title2 are appropriate for presentation, and localized to the user's language, c is in English, sometimes less specific, and sometimes less well formatted.  For example, for a frequency table, title1 and title2 name the variable and c is simply ``Frequencies''.

Caption
-------

     Caption => 58 | 31 Value[caption]

The caption, if presented, is shown below the table.

Footnotes
---------

     Footnotes => int[n] Footnote*[n]
     Footnote => Value[text] (58 | 31 Value[marker]) byte*4

Each footnote has text and an optional customer marker (such as *).

Fonts
-----

     Fonts => 00 Font*8
     Font =>
         byte[index] 31 string[typeface] 00 00
         (10 | 20 | 40 | 50 | 70 | 80)[f1] 41
         (i0 | i1 | i2)[f2] 00
         (i0 | i2 | i64173)[f3]
         (i0 | i1 | i2 | i3)[f4]
         string[fgcolor] string[bgcolor] i0 i0 00
         v3(int[f5] int[f6] int[f7] int[f8]))

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.

index is the 1-based index of the Font, i.e. 1 for the first Font, through 8 for the final Font.

typeface is the string name of the font.  In the corpus, this is SansSerif in over 99% of instances and Times New Roman in the rest.

fgcolor and bgcolor are the foreground color and background color, respectively.  In the corpus, these are always #000000 and #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+% 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.

font   f1   f2   f3   f4   f5   f6   f7   f8
1   40   1       0     0   8   10/11     1   8
2   40   0       2     1   8   10/11     1   1
3   40   0       2   1   24/11   24/ 8   2/3   4
4   40   0       2     3   8   10/11     1   1
5   40   0       0     1   8   10/11     1   4
6   40   0       2     1   8   10/11     1   4
7   40   0   64173   0/1   8   10/11     1   1
8   40   0       2     3   8   10/11     1    4

Formats
-------

     Formats =>
         int[n1] byte*[n1]
         int[n2] byte*[n2]
         int[n3] byte*[n3]
         int[n4] int*[n4]
         string[encoding]
         (i0 | i-1) (00 | 01) 00 (00 | 01)
         int
         byte[decimal] byte[grouping]
         int[n-ccs] string*[n-ccs]
         v1(i0)
         v3(count(count(X5) count(X6)))

     X5 => byte*33 int[n] int*[n]
     X6 =>
         01 00 (03 | 04) 00 00 00
         string[command] string[subcommand]
         string[language] string[charset] string[locale]
         (00 | 01) 00 (00 | 01) (00 | 01)
         int
         byte[decimal] byte[grouping]
         byte*8 01
         (string[dataset] string[datafile] i0 int i0)?
         int[n-ccs] string*[n-ccs]
         2e (00 | 01) (i2000000 i0)?

In every example in the corpus, n1 is 240.  The meaning of the bytes that follow it is unknown.

In every example in the corpus, n2 is 18 and the bytes that follow it are 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, n3 is 16 and the bytes that follow it are 00 00 00 01 00 00 00 01 00 00 00 00 01 01 01 01.  In version 3, observed 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 n4 vary from 0 to 17.  Out of 7,060 examples in the corpus, it is nonzero only 36 times.

encoding is a character encoding, usually a Windows code page such as en_US.windows-1252 or 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.

decimal is the decimal point character.  The observed values are . and ,.

grouping is the grouping character.  Usually, it is , if decimal is ., and vice versa.  Other observed values are ' (apostrophe),   (space), and zero (presumably indicating that digits should not be grouped).

n-ccs is observed as either 0 or 5.  When it is 5, the following strings are CCA through CCE format strings.  See Custom Currency Formats (PSPP).  Most commonly these are all -,,, but other strings occur.

Dimensions
----------

A pivot table presents multidimensional data.  A Dimension identifies the categories associated with each dimension.

     Dimensions => int[n-dims] Dimension*[n-dims]
     Dimension => Value[name] DimUnknown int[n-categories] Category*[n-categories]
     DimUnknown =>
         byte[d1]
         (00 | 01 | 02)[d2]
         (i0 | i2)[d3]
         (00 | 01)[d4]
         (00 | 01)[d5]
         01
         int[d6]

name is the name of the dimension, e.g. Variables, Statistics, or a variable name.

d1 is usually 0 but many other values have been observed.

d3 is 2 over 99% of the time.

d5 is 0 over 99% of the time.

d6 is either -1 or the 0-based index of the dimension, e.g. 0 for the first dimension, 1 for the second, and so on.  The latter is the case 98% of the time in the corpus.

Categories
----------

Categories are arranged in a tree.  Only the leaf nodes in the tree are really categories; the others just serve as grouping constructs.

     Category => Value[name] (Leaf | Group)
     Leaf => 00 00 00 i2 int[index] i0
     Group =>
         (00 | 01)[merge] 00 01 (i0 | i2)[data]
         i-1 int[n-subcategories] Category*[n-subcategories]

name is the name of the category (or group).

A Leaf represents a leaf category.  The Leaf's index is a nonnegative integer less than n-categories in the Dimension in which the Category is nested (directly or indirectly).

A Group represents a Group of nested categories.  Usually a Group contains at least one Category, so that n-subcategories is positive, but a few Groups with n-subcategories 0 has been observed.

If a Group's merge is 00, the most common value, then the group is really a distinct group that should be represented as such in the visual representation and user interface.  If merge is 01, the categories in this group should be shown and treated as if they were direct children of the group's containing group (or if it has no parent group, then direct children of the dimension), and this group's name is irrelevant and should not be displayed.  (Merged groups can be nested!)

A Group's data appears to be i2 when all of the categories within a group are leaf categories that directly represent data values for a variable (e.g. in a frequency table or crosstabulation, a group of values in a variable being tabulated) and i0 otherwise.

Data
----

The final part of an SPV light member contains the actual data.

     Data =>
         int[layers] int[rows] int[columns] int*[n-dimensions]
         int[n-data] Datum*[n-data]
     Datum => int64[index] v3(00?) Value

The values of layers, rows, and columns each specifies the number of dimensions displayed in layers, rows, and columns, respectively.  Any of them may be zero.  Their values sum to n-dimensions from Dimensions (see SPV Light Member Dimensions).

The n-dimensions integers are a permutation of the 0-based dimension numbers.  The first layers integers specify each of the dimensions represented by layers, the next rows integers specify the dimensions represented by rows, and the final columns integers specify the dimensions represented by columns. When there is more than one dimension of a given kind, the inner dimensions are given first.

The format of a Datum varies slightly from version 1 to version 3: in version 1 it allows for an extra optional 00 byte.

A Datum consists of an index and a Value.  Suppose there are d dimensions and dimension i, 0 \le i < d, has n_i categories.  Consider the datum at coordinates x_i, 0 \le i < d, and note that 0 \le x_i < n_i.  Then the index is calculated by the following algorithm:

     let index = 0
     for each i from 0 to d - 1:
         index = (n_i \times index) + x_i

For example, suppose there are 3 dimensions with 3, 4, and 5 categories, respectively.  The datum at coordinates (1, 2, 3) has index 5 \times (4 \times (3 \times 0 + 1) + 2) + 3 = 33.

Value
-----

Value is used throughout the SPV light member format.  It boils down to a number or a string.

     Value => 00? 00? 00? 00? RawValue
     RawValue =>
         01 ValueMod int[format] double[x]
       | 02 ValueMod int[format] double[x]
         string[varname] string[vallab] (01 | 02 | 03)
       | 03 string[local] ValueMod string[id] string[c] (00 | 01)[type]
       | 04 ValueMod int[format] string[vallab] string[varname]
         (01 | 02 | 03) string[s]
       | 05 ValueMod string[varname] string[varlabel] (01 | 02 | 03)
       | ValueMod string[format] int[n-args] Argument*[n-args]
     Argument =>
         i0 Value
       | int[x] i0 Value*[x+1]      /* x > 0 */

There are several possible encodings, which one can distinguish by the first nonzero byte in the encoding.

01
     The numeric value x, intended to be presented to the user formatted according to format, which is in the format described for system files.  See System File Output Formats, for details. Most commonly, format has width 40 (the maximum).

     An x with the maximum negative double value -DBL_MAX represents the system-missing value SYSMIS.  (HIGHEST and LOWEST have not been observed.)  See System File Format, for more about these special values.

02
     Similar to 01, with the additional information that x is a value of variable varname and has value label vallab. Both varname and vallab can be the empty string, the latter very commonly.

     The meaning of the final byte is unknown.  Possibly it is connected to whether the value or the label should be displayed.

03
     A text string, in two forms: c is in English, and sometimes abbreviated or obscure, and local is localized to the user's locale.  In an English-language locale, the two strings are often the same, and in the cases where they differ, local is more appropriate for a user interface, e.g. c of ``Not a PxP table for MCN...'' versus local of ``Computed only for a PxP table, where P must be greater than 1.''

     c and local are always either both empty or both nonempty.

     id is a brief identifying string whose form seems to resemble a programming language identifier, e.g. cumulative_percent or factor_14.  It is not unique.

     type is 00 for text taken from user input, such as syntax fragment, expressions, file names, data set names, and 01 for fixed text strings such as names of procedures or statistics.  In the former case, id is always the empty string; in the latter case, id is still sometimes empty.

04
     The string value s, intended to be presented to the user formatted according to format.  The format for a string is not too interesting, and the corpus contains many clearly invalid formats like A16.39 or A255.127 or A134.1, so readers should probably ignore the format entirely.

     s is a value of variable varname and has value label vallab.  varname is never empty but vallab is commonly empty.

     The meaning of the final byte is unknown.

05
     Variable varname, which is rarely observed as empty in the corpus, with variable label varlabel, which is often empty.

     The meaning of the final byte is unknown.

31 or 58
     (These bytes begin a ValueMod.)  A format string, analogous to printf, followed by one or more Arguments, each of which has one or more values.  The format string uses the following syntax:

     \%
     \:
     \[
     \]
          Each of these expands to the character following \\, to escape characters that have special meaning in format strings.  These are effective inside and outside the [...]  syntax forms described below.

     \n
          Expands to a new-line, inside or outside the [...] forms described below.

     ^I
          Expands to a formatted version of argument I, which must have only a single value.  For example, ^1 expands to the first argument's value.

     [:A:]I
          Expands A for each of the values in I.  A should contain one or more ^J conversions, which are drawn from the values for argument I in order.  Some examples from the corpus:

          [:^1:]1
               All of the values for the first argument, concatenated.

          [:^1\n:]1
               Expands to the values for the first argument, each followed by a new-line.

          [:^1 = ^2:]2
               Expands to X = Y where X is the second argument's first value and Y is its second value.  (This would be used only if the argument has two values.  If there were more values, the second and third values would be directly concatenated, which would look funny.)

     [A:B:]I
          This extends the previous form so that the first values are expanded using A and later values are expanded using B.  For an unknown reason, within A the ^J conversions are instead written as %J.  Some examples from the corpus:

          [%1:*^1:]1
               Expands to all of the values for the first argument, separated by *.

          [%1 = %2:, ^1 = ^2:]1
               Given appropriate values for the first argument, expands to X = 1, Y = 2, Z = 3.

          [%1:, ^1:]1
               Given appropriate values, expands to 1, 2, 3.

     The format string is localized to the user's locale.

ValueMod
--------

A ValueMod can specify special modifications to a Value.

     ValueMod =>
         31 i0 (i0 | i1 string[subscript])
         v1(00 (i1 | i2) 00 00 int 00 00)
         v3(count(FormatString Style ValueModUnknown))
       | 31 i1 int[footnote-number] Format
       | 31 i2 (00 | 01 | 02) 00 (i1 | i2 | i3) Format
       | 31 i3 00 00 01 00 i2 Format
       | 58
     Style => 58 | 31 01? 00? 00? 00? 01 string[fgcolor] string[bgcolor] string[typeface] byte
     Format => 00 00 count(FormatString Style 58)
     FormatString => count((i0 (58 | 31 string))?)
     ValueModUnknown => 58 | 31 i0 i0 i0 i0 01 00 (01 | 02 | 08) 00 08 00 0a 00)

The 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.

The 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. a or 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 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.

Legacy Detail Member Binary Format
==================================

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 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:

vAF(X)
     In a version 0xaf legacy member, X; in other versions, nothing. (The legacy member header indicates the version; see below.)

vB0(X)
     In a version 0xb0 legacy member, X; in other versions, nothing.

A legacy detail member .bin has the following overall format:

     LegacyBinary =>
         00 byte[version] int16[n-sources] int[member-size]
         Metadata*[n-sources] Data*[n-sources]

version is a version number that affects the interpretation of some of the other data in the member.  Versions 0xaf and 0xb0 are known.  We will refer to ``version 0xaf'' and ``version 0xb0'' members later on.

A legacy member consists of n-sources data sources, each of which has Metadata and Data.

member-size is the size of the legacy binary member, in bytes.

The following sections go into more detail.

Metadata
--------

     Metadata =>
         int[n-data] int[n-variables] int[offset]
         vAF(byte*32[source-name])
         vB0(byte*64[source-name] int[x])

A data source has n-variables variables, each with n-data data values.

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 tableData for pivot table data or source0 for chart data.

A given Metadata's offset is the offset, in bytes, from the beginning of the member to the start of the corresponding Data.  This allows programs to skip to the beginning of the data for a particular source; it is also important to determine whether a source includes any string data (see SPV Legacy Member Data).

The meaning of x in version 0xb0 is unknown.

Data
----

     Data => NumericData*[n-variables] StringData?
     NumericData => byte*288[variable-name] double*[n-data]

Data follow the Metadata in the legacy binary format, with sources in the same order.  Each NumericSeries begins with a 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 datum.  A double with the maximum negative double -DBL_MAX represents the system-missing value SYSMIS.

     StringData => i1 string[source-name] Pairs Labels

     Pairs => int[n-string-vars] PairSeries*[n-string-vars]
     PairVar => string[pair-var-name] int[n-pairs] Pair*[n-pairs]
     Pair => int[i] int[j]

     Labels => int[n-labels] Label*[n-labels]
     Label => int[frequency] int[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 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 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.  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 variables and only the fourth one includes string data.

Each PairVar consists a sequence of 0 or more Pair nonterminals, each of which maps from a 0-based index within variable i to a 0-based label index j, e.g. pair i = 2, j = 3, means that the third data value (with value SYSMIS) is to be replaced by the string of the fourth Label.

The labels themselves follow the pairs.  The valuable part of each label is the string s.  Each label also includes a frequency that reports the number of pairs that reference it (although this is not useful).

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:

  * 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 sourceVariable elements. The data for these variables comes from the associated tableData.bin member.  Some variables are defined, with derivedVariable elements, as a constant or in terms of a mapping function from a source variable.

  * Assignment of variables to axes.  A variable can appear as columns, or rows, or layers.  The faceting element and its sub-elements describe this assignment.

All elements have an optional id attribute.  In practice many elements are assigned id attributes that are never referenced.

The visualization Element
-------------------------

     Parent: Document root
     Contents:
          extension?
          userSource
          (sourceVariable | derivedVariable)+
          graph
          labelFrame+
          container?
          style+
          layerController?

This element has the following attributes.

 -- Required: creator
     The version of the software that created this SPV file, as a string of the form xxyyzz, which represents software version xx.yy.zz, e.g. 160001 is version 16.0.1.  The corpus includes major versions 16 through 19.

 -- Required: date
     The date on the which the file was created, as a string of the form YYYY-MM-DD.

 -- 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. en-US, en-GB, el-GR, sr-Cryl-RS.

 -- Required: name
     The title of the pivot table, localized to the output language.

 -- Required: style
     The id of a style element (see SPV Detail style element).  This is the base style for the entire pivot table.  In every example in the corpus, the value is visualizationStyle and the corresponding style element has no attributes other than id.

 -- Required: type
     A floating-point number.  The meaning is unknown.

 -- Required: version
     The visualization schema version number.  In the corpus, the value is one of 2.4, 2.5, 2.7, and 2.8.

The userSource Element
----------------------

Parent: visualization

Contents:

This element has the following attributes.

 -- Optional: missing
     Always listwise.

The sourceVariable Element
--------------------------

Parent: visualization

Contents: extension* (format | stringFormat)?

This element defines a variable whose values can be used elsewhere in the visualization.  It ties this element's id to a variable from the tableData.bin member that corresponds to this .xml.

This element has the following attributes.

 -- Required: categorical
     Always set to true.

 -- Required: source
     Always set to tableData, the source-name in the corresponding tableData.bin member (see SPV Legacy Member Metadata).

 -- Required: sourceName
     The name of a variable within the source, the variable-name in the corresponding tableData.bin member (see SPV Legacy Member Data).

 -- Optional: dependsOn
     The 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.

 -- Optional: label
     The variable label, if any

 -- Optional: labelVariable
     The 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.

The derivedVariable Element
---------------------------

Parent: visualization

Contents: extension* (format | stringFormat valueMapEntry*)

Like 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.

 -- Required: categorical
     Always set to true.

 -- 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. (VAR1 + VAR2) / 2.  In practice, the corpus contains only the following forms of expressions:

     constant(NUMBER)
     constant(VARIABLE)
          A constant.  The meaning when a variable is named is unknown. Sometimes the ``variable name'' has spaces in it.

     map(VARIABLE)
          Transforms the values in the named VARIABLE using the valueMapEntrys contained within the element.

 -- Optional: dependsOn
     The 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.

The valueMapEntry Element
.........................

Parent: derivedVariable

Contents: empty

A 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 valueMapEntry.  If multiple source values map to the same target value, they can be combined or separate.

valueMapEntry has the following attributes.

 -- Required: from
     A source value, or multiple source values separated by semicolons, e.g. 0 or 13;14;15;16.

 -- Required: to
     The target value.

The 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.

visualization Parent Element
............................

With visualization as its parent element, extension has the following attributes.

 -- Optional: numRows
     An integer that presumably defines the number of rows in the displayed pivot table.

 -- Optional: showGridline
     Always set to false in the corpus.

 -- Optional: minWidthSet
 -- Optional: maxWidthSet
     Always set to true in the corpus.

container Parent Element
........................

With container as its parent element, extension has the following attributes.

 -- Required: combinedFootnotes
     Always set to true in the corpus.

sourceVariable and derivedVariable Parent Element
.................................................

With sourceVariable or derivedVariable as its parent element, extension has the following attributes.  A given parent element often contains several extension elements that specify the meaning of the source data's variables or sources, e.g.

     <extension from="0" helpId="corrected_model"/>
     <extension from="3" helpId="error"/>
     <extension from="4" helpId="total_9"/>
     <extension from="5" helpId="corrected_total"/>

 -- Required: from
     An integer or a name like ``dimension0''.

 -- Required: helpId
     An identifier.

The graph Element
-----------------

Parent: visualization

Contents: location+ coordinates faceting facetLayout interval

graph has the following attributes.

 -- Required: cellStyle
 -- Required: style
     Each of these is the id of a style element (see SPV Detail style element).  The former is the default style for individual cells, the latter for the entire table.

The location Element
--------------------

Parent: 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 height, width, left, and top.  Some examples in the corpus add a fifth for part bottom, even though it is not clear how all of top, bottom, and heigth can be honored at the same time.  In any case, location seems to have little importance in representing tables; a reader can safely ignore it.

 -- Required: part
     One of height, width, top, bottom, or left.  Presumably right is acceptable as well but the corpus contains no examples.

 -- Required: method
     How the location is determined:

     sizeToContent
          Based on the natural size of the table.  Observed only for parts height and width.

     attach
          Based on the location specified in target.  Observed only for parts top and bottom.

     fixed
          Using the value in value.  Observed only for parts top, bottom, and left.

     same
          Same as the specified target.  Observed only for part left.

 -- Optional: min
     Minimum size.  Only observed with value 100pt.  Only observed for part width.

 -- Dependent: target
     Required when method is attach or same, not observed otherwise.  This is the ID of an element to attach to. Observed with the ID of title, footnote, graph, and other elements.

 -- Dependent: value
     Required when method is fixed, not observed otherwise. Observed values are 0%, 0px, 1px, and 3px on parts top and left, and 100% on part bottom.

The coordinates Element
-----------------------

Parent: graph

Contents: empty

This element is always present and always empty, with no attributes (except id).

The faceting Element
--------------------

Parent: graph

Contents: cross layer*

The faceting element describes the row, column, and layer structure of the table.  Its cross child determines the row and column structure, and each layer child (if any) represents a layer.

faceting has no attributes (other than id).

The cross Element
.................

Parent: faceting

Contents: nest nest

The cross element describes the row and column structure of the table.  It has exactly two nest children, the first of which describes the table's rows and the second the table's columns.

cross has no attributes (other than id).

The nest Element
................

Parent: cross

Contents: variableReference+

A given nest usually consists of one or more dimensions, each of which is represented by variableReference child elements. Minimally, a dimension has two variableReference children, one for the categories, one for the data, e.g.:

     <nest>
       <variableReference ref="dimension0categories"/>
       <variableReference ref="dimension0"/>
     </nest>

Groups of categories introduce additional variable references, e.g.

     <nest>
       <variableReference ref="dimension0categories"/>
       <variableReference ref="dimension0group0"/>
       <variableReference ref="dimension0"/>
     </nest>

Grouping can be hierarchical, e.g.

     <nest>
       <variableReference ref="dimension0categories"/>
       <variableReference ref="dimension0group1"/>
       <variableReference ref="dimension0group0"/>
       <variableReference ref="dimension0"/>
     </nest>

XXX what are group maps?

     <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>

A nest can contain multiple dimensions:

     <nest>
       <variableReference ref="dimension1categories"/>
       <variableReference ref="dimension1group0"/>
       <variableReference ref="dimension1"/>
       <variableReference ref="dimension0categories"/>
       <variableReference ref="dimension0"/>
     </nest>

One nest within a given cross may have no dimensions, in which case it still has one variableReference child, which references a derivedVariable whose value attribute is constant(0).  In the corpus, such a derivedVariable has row or column, respectively, as its id.

nest has no attributes (other than id).

The variableReference Element
.............................

Parent: nest

Contents: empty

variableReference has one attribute.

 -- Required: ref
     The id of a sourceVariable or derivedVariable element.

The layer Element
.................

Parent: faceting

Contents: empty

Each layer is represented by a pair of layer elements.  The first of this pair is for a category variable, the second for the data variable, e.g.:

     <layer value="0" variable="dimension0categories" visible="true"/>
     <layer value="dimension0" variable="dimension0" visible="false"/>

layer has the following attributes.

 -- Required: variable
     The id of a sourceVariable or derivedVariable element.

 -- Required: value
     The value to select.  For a category variable, this is always 0; for a data variable, it is the same as the variable attribute.

 -- Optional: visible
     Whether the layer is visible.  Generally, category layers are visible and data layers are not, but sometimes this attribute is omitted.

 -- Optional: method
     When present, this is always nest.

The facetLayout Element
-----------------------

Parent: graph

Contents: tableLayout facetLevel+ setCellProperties*

The tableLayout Element
.......................

Parent: facetLayout

Contents: empty

 -- Required: verticalTitlesInCorner
     Always set to true.

 -- Optional: style
     The id of a style element.

 -- Optional: fitCells
     Always set to ticks.

The facetLevel Element
......................

Parent: facetLayout

Contents: axis

Each facetLevel describes a variableReference or layer, and a table has one facetLevel element for each such element.  For example, an SPV detail member that contains four variableReference elements and two layer elements will contain six facetLevel elements.

In the corpus, 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 level attribute, described below.  Second, in the corpus, a facetLevel always has an id that is the same as the id of the element it describes with _facetLevel appended.  One should not formally rely on this, of course, but it is usefully indicative.

 -- Required: level
     A 1-based index into the variableReference and layer elements, e.g. a facetLayout with a level of 1 describes the first variableReference in the SPV detail member, and in a member with four variableReference elements, a facetLayout with a level of 5 describes the first layer in the member.

 -- Required: gap
     Always observed as 0pt.

The axis Element
................

Parent: facetLevel

Contents: label? majorTicks

 -- Attribute: style
     The id of a style element.

The label Element
.................

Parent: axis or labelFrame

Contents: text+ | descriptionGroup

This element represents a label on some aspect of the table.  For example, the table's title is a label.

The contents of the label can be one or more text elements or a descriptionGroup.

 -- Attribute: style
 -- Optional: textFrameStyle
     Each of these is the id of a style element. style is the style of the label text, textFrameStyle the style for the frame around the label.

 -- Optional: purpose
     The kind of entity being labeled, one of title, subTitle, layer, or footnote.

The descriptionGroup Element
............................

Parent: label

Contents: (description | text)+

A descriptionGroup concatenates one or more elements to form a label.  Each element can be a text element, which contains literal text, or a description element that substitutes a value or a variable name.

 -- Attribute: target
     The id of an element being described.  In the corpus, this is always faceting.

 -- Attribute: separator
     A string to separate the description of multiple groups, if the target has more than one.  In the corpus, this is always a new-line.

Typical contents for a descriptionGroup are a value by itself:

     <description name="value"/>

or a variable and its value, separated by a colon:

     <description name="variable"/><text>:</text><description name="value"/>

The description Element
.......................

Parent: descriptionGroup

Contents: empty

A description is like a macro that expands to some property of the target of its parent descriptionGroup.

 -- Attribute: name
     The name of the property.  Only variable and value appear in the corpus.

The majorTicks Element
......................

Parent: axis

Contents: gridline?

 -- Attribute: labelAngle
 -- Attribute: length
     Both always defined to 0.

 -- Attribute: style
 -- Attribute: tickFrameStyle
     Each of these is the id of a style element. style is the style of the tick labels, tickFrameStyle the style for the frames around the labels.

The gridline Element
....................

Parent: majorTicks

Contents: empty

Represents ``gridlines,'' which for a table represents the lines between the rows or columns of a table (XXX?).

 -- Attribute: style
     The style for the gridline.

 -- Attribute: zOrder
     Observed as a number between 28 and 31.  Does not seem to be important.

The setCellProperties Element
.............................

Parent: facetLayout

Contents: setMetaData setStyle* setFormat+ union?

This element sets style properties of cells designated by the target attribute of its child elements, as further restricted by the optional union element if present.  The target values often used, e.g. graph or labeling, actually affect every cell, so the union element is a useful restriction.

 -- Optional: applyToConverse
     If present, always true.  This appears to invert the meaning of the target of sub-elements: the selected cells are the ones not designated by target.  This is confusing, given the additional restrictions of union, but in the corpus applyToConverse is never present along with union.

The setMetaData Element
.......................

Parent: setCellProperties

Contents: empty

This element is not known to have any visible effect.

 -- Required: target
     The id of an element whose metadata is to be set.  In the corpus, this is always graph, the id used for the graph element.

 -- Required: key
 -- Required: value
     A key-value pair to set for the target.

     In the corpus, key is cellPropId or, rarely, diagProps, and value is always the id of the parent setCellProperties.

The setStyle Element
....................

Parent: setCellProperties

Contents: empty

This element associates a style with the target.

 -- Required: target
     The id of an element whose style is to be set.  In the corpus, this is always the id of an interval, labeling, or, rarely, graph element.

 -- Required: style
     The id of a style element that identifies the style to set on the target.

The setFormat Element
.....................

     Parent: setCellProperties
     Contents:
         format
       | numberFormat
       | stringFormat+
       | dateTimeFormat

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 visualization element's version attribute (see SPV Detail visualization Element).  In version 2.5 and earlier, setFormat contains one of a number of child elements that correspond to the different varieties of print formats. In version 2.7 and later, setFormat instead always contains a format element.

XXX reinvestigate the above claim about versions: it appears to be incorrect.

The setFormat element itself has the following attributes.

 -- Required: target
     The id of an element whose style is to be set.  In the corpus, this is always the id of an majorTicks or labeling element.

 -- Optional: reset
     If this is true, this format overrides the target's previous format.  If it is false, the adds to the previous format.  In the corpus this is always true.  The default behavior is unknown.

The format Element
..................

Parent: sourceVariable, derivedVariable, formatMapping, labeling, formatMapping, setFormat

Contents: (affix+ | relabel+)?

This element appears only in schema version 2.7 (see SPV Detail visualization Element).

This element determines a format, equivalent to an SPSS print format.

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:

 -- Optional: baseFormat
     Either dateTime or elapsedTime.  When this attribute is omitted, this element is a numeric or string format.

Whether, in the corpus, other attributes are always present (``yes''), never present (``no''), or sometimes present (``opt'') depends on baseFormat:

Attribute   dateTime   elapsedTime   number   string
errorCharacter          yes   yes   yes   opt

separatorChars          yes    no    no   no

mdyOrder                yes    no    no   no

showYear                yes    no    no   no
yearAbbreviation        yes    no    no   no

showMonth               yes    no    no   no
monthFormat             yes    no    no   no

showDay                 yes   opt    no   no
dayPadding              yes   opt    no   no
dayOfMonthPadding       yes    no    no   no
dayType                 yes    no    no   no

showHour                yes   opt    no   no
hourFormat              yes   opt    no   no
hourPadding             yes   yes    no   no

showMinute              yes   yes    no   no
minutePadding           yes   yes    no   no

showSecond              yes   yes    no   no
secondPadding            no   yes    no   no

showMillis               no   yes    no   no

minimumIntegerDigits     no    no   yes   no
maximumFractionDigits    no   yes   yes   no
minimumFractionDigits    no   yes   yes   no
useGrouping              no   opt   yes   no
scientific               no    no   yes   no
small                    no    no   opt   no
suffix                   no    no   opt   no

tryStringsAsNumbers      no    no    no   yes

 -- Attribute: errorCharacter
     A character that replaces the formatted value when it cannot otherwise be represented in the given format.  Always *.

Date and Time Attributes
........................

These attributes are used with dateTime and elapsedTime formats or both.

 -- Attribute: separatorChars
     Exactly four characters.  In order, these are used for: decimal point, grouping, date separator, time separator.  Always .,-:.

 -- Attribute: mdyOrder
     Within a date, the order of the days, months, and years. dayMonthYear is the only observed value, but one would expect that monthDayYear and yearMonthDay to be reasonable as well.

 -- Attribute: showYear
 -- 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 true or false; only values of true and false, respectively, have been observed.

 -- Attribute: showMonth
 -- Attribute: monthFormat
     Whether to include the month (true or false) and, if so, how to format it.  monthFormat is one of the following:

     long
          The full name of the month, e.g. in an English locale, September.

     short
          The abbreviated name of the month, e.g. in an English locale, Sep.

     number
          The number representing the month, e.g. 9 for September.

     paddedNumber
          A two-digit number representing the month, e.g. 09 for September.

     Only values of true and short, respectively, have been observed.

 -- Attribute: dayPadding
 -- Attribute: dayOfMonthPadding
 -- Attribute: hourPadding
 -- Attribute: minutePadding
 -- 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 true.

 -- Attribute: showDay
 -- Attribute: showHour
 -- Attribute: showMinute
 -- Attribute: showSecond
 -- 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 true.

 -- Attribute: dayType
     This attribute is always month in the corpus, specifying that the day of the month is to be displayed; a value of year is supposed to indicate that the day of the year, where 1 is January 1, is to be displayed instead.

 -- Attribute: hourFormat
     hourFormat, if present, is one of:

     AMPM
          The time is displayed with an am or pm suffix, e.g. 10:15pm.

     AS_24
          The time is displayed in a 24-hour format, e.g. 22:15.

          This is the only value observed in the corpus.

     AS_12
          The time is displayed in a 12-hour format, without distinguishing morning or evening, e.g. 10;15.

     hourFormat is sometimes present for 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 elapsedTime is sometimes used to format a time of day.

Numeric Attributes
..................

These attributes are used for formats when baseFormat is number.  Attributes maximumFractionDigits, and minimumFractionDigits, and useGrouping are also used when baseFormat is elapsedTime.

 -- Attribute: minimumIntegerDigits
     Minimum number of digits to display before the decimal point.  Always observed as 0.

 -- Attribute: maximumFractionDigits
 -- 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.

 -- 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 separatorChars attribute, but that attribute is only present when baseFormat is dateTime or elapsedTime, in the corpus at least.  Perhaps that is because this attribute has only been observed as false.

 -- Attribute: scientific
     This attribute controls when and whether the number is formatted in scientific notation.  It takes the following values:

     onlyForSmall
          Use scientific notation only when the number's magnitude is smaller than the value of the small attribute.

     whenNeeded
          Use scientific notation when the number will not otherwise fit in the available space.

     true
          Always use scientific notation.  Not observed in the corpus.

     false
          Never use scientific notation.  A number that won't otherwise fit will be replaced by an error indication (see the errorCharacter attribute).  Not observed in the corpus.

 -- Optional: small
     Only present when the scientific attribute is onlyForSmall, this is a numeric magnitude below which the number will be formatted in scientific notation.  The values 0 and 0.0001 have been observed.  The value 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 scientific to false.

 -- Optional: prefix
 -- Optional: suffix
     Specifies a prefix or a suffix to apply to the formatted number.  Only suffix has been observed, with value %.

String Attributes
.................

These attributes are used for formats when baseFormat is string.

 -- Attribute: tryStringsAsNumbers
     When this is 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 false.

The numberFormat Element
........................

Parent: setFormat

Contents: affix+

This element appears only in schema version 2.5 and earlier (see SPV Detail visualization Element).  Possibly this element could also contain relabel elements in a more diverse corpus.

This element has the following attributes.

 -- Attribute: maximumFractionDigits
 -- Attribute: minimumFractionDigits
 -- Attribute: minimumIntegerDigits
 -- Optional: scientific
 -- Optional: small
 -- Optional: suffix
 -- Optional: useGroupging
     The syntax and meaning of these attributes is the same as on the format element for a numeric format.  see SPV Detail format element.

The stringFormat Element
........................

Parent: setFormat

Contents: (affix+ | relabel+)?

This element appears only in schema version 2.5 and earlier (see SPV Detail visualization Element).

This element has no attributes.

The dateTimeFormat Element
..........................

Parent: setFormat

Contents: empty

This element appears only in schema version 2.5 and earlier (see SPV Detail visualization Element).  Possibly this element could also contain affix and relabel elements in a more diverse corpus.

The following attribute is required.

 -- Attribute: baseFormat
     Either dateTime or time.

When baseFormat is dateTime, the following attributes are available.

 -- Attribute: dayOfMonthPadding
 -- Attribute: dayPadding
 -- Attribute: dayType
 -- Attribute: hourFormat
 -- Attribute: hourPadding
 -- Attribute: mdyOrder
 -- Attribute: minutePadding
 -- Attribute: monthFormat
 -- Attribute: separatorChars
 -- Attribute: showDay
 -- Attribute: showHour
 -- Attribute: showMinute
 -- Attribute: showMonth
 -- Attribute: showSecond
 -- Attribute: showYear
 -- Attribute: yearAbbreviation
     The syntax and meaning of these attributes is the same as on the format element when that element's baseFormat is dateTime.  see SPV Detail format Element.

When baseFormat is time, the following attributes are available.

 -- Attribute: hourFormat
 -- Attribute: hourPadding
 -- Attribute: minutePadding
 -- Attribute: monthFormat
 -- Attribute: separatorChars
 -- Attribute: showDay
 -- Attribute: showHour
 -- Attribute: showMinute
 -- Attribute: showMonth
 -- Attribute: showSecond
 -- Attribute: showYear
 -- Attribute: yearAbbreviation
     The syntax and meaning of these attributes is the same as on the format element when that element's baseFormat is elapsedTime.  see SPV Detail format Element.

The affix Element
.................

Parent: format or numberFormat or stringFormat

Contents: empty

Possibly this element could have 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:

 -- Attribute: definesReference
     This specifies the footnote number as a natural number: 1 for the first footnote, 2 for the second, and so on.

 -- Attribute: position
     Position for the footnote label.  Always superscript.

 -- Attribute: suffix
     Whether the affix is a suffix (true) or a prefix (false).  Always true.

 -- Attribute: value
     The text of the suffix or prefix.  Typically a letter, e.g. a for footnote 1, b for footnote 2, ...  The corpus contains other values: *, **, and a few that begin with at least one comma: ,b, ,c, ,,b, and ,,c.

The relabel Element
...................

Parent: format or stringFormat

Contents: empty

Possibly this element could have numberFormat or 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:

 -- Attribute: from
     The value to map.  In the corpus this is an integer or the system-missing value -1.797693134862316E300.

 -- Attribute: to
     The string to display in place of the value of from.  In the corpus this is a wide variety of value labels; the system-missing value is mapped to ..

The union Element
.................

Parent: setCellProperties

Contents: intersect+

This element represents a set of cells, computed as the union of the sets represented by each of its children.

The intersect Element
.....................

Parent: union

Contents: where+ | 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 where is far more common, appearing thousands of times, whereas intersectWhere only appears 4 times.

Most intersect elements have two or more children.

The where Element
.................

Parent: intersect

Contents: empty

This element represents the set of cells in which the value of a specified variable falls within a specified set.

 -- Attribute: variable
     The id of a variable, e.g. dimension0categories or dimension0group0map.

 -- Attribute: include
     A value, or multiple values separated by semicolons, e.g. 0 or 13;14;15;16.

The intersectWhere
..................

Parent: intersect

Contents: empty

The meaning of this element is unknown.

 -- Attribute: variable
 -- Attribute: variable2
     The meaning of these attributes is unknown.  In the four examples in the corpus they always take the values dimension2categories and dimension0categories, respectively.