---
title: "Office 2003 XML (WordprocessingML 2003, SpreadsheetML 2003)"
url: https://recursiveai.org/onedocument/docs/xml-2003/
description: "Both formats are read-only. A file opens as a Document or a Workbook by conversion: the reader turns the 2003 file into an in-memory OOXML package (DOCX…"
version: "1.0.0"
source: https://github.com/recursive-ai-oss/onedocument-csharp/blob/a85720e075c783fc596641d8586ee126cae088c5/docs/xml-2003.md
---

# Office 2003 XML (WordprocessingML 2003, SpreadsheetML 2003)

Both formats are read-only. A file opens as a `Document` or a `Workbook` by **conversion**: the reader turns the 2003 file into an in-memory
OOXML package (DOCX or XLSX) on the markup layer and the hub wraps that package like any other. What the hub then holds saves as DOCX or XLSX,
extracts as text and converts as any OOXML file does. `Document.ImportLoss` and `Workbook.ImportLoss` list what did not map (null for a file
that was opened natively). Writing the 2003 formats is not supported.

```csharp
using Document doc = Document.Open("old.xml");       // sniffed: Word 2003 XML
using Workbook wb = Workbook.Open("old.xml");        // sniffed: Excel 2003 XML
Office.Convert("old.xml", "new.docx");               // or .xlsx
LossReport? lost = doc.ImportLoss;
```

The static entry points are `WordMl2003.ToPackage/Open` (`RecursiveAI.OneDocument.Documents.Xml2003`) and `SpreadsheetMl2003.ToPackage/Open`
(`RecursiveAI.OneDocument.Spreadsheets.Xml2003`); they take an `IByteSource`, an `OpenContext` and an optional `ILossSink`.

## Identification

By content, never the extension (`FormatSniffer`): the `mso-application` processing instruction (`Word.Document`, `Excel.Sheet`) or the root
namespace (`http://schemas.microsoft.com/office/word/2003/wordml`, `urn:schemas-microsoft-com:office:spreadsheet`), ahead of generic XML. The
files are `.xml` (Word's "Word 2003 XML Document", Excel's "XML Spreadsheet 2003") and sometimes `.doc` or `.xls` by name.

## Reading rules

- The file is parsed once with the markup tokenizer (no `System.Xml`). DTDs and entity declarations are refused; nesting, attribute counts and
  part size obey `OfficeLimits`. Not well-formed XML is `xml.*`; a root that is not the format's is `wml2003.not-wordml` or
  `sml2003.not-spreadsheet`. Everything else is repaired and reported (`defects.md`); the reader raises nothing but `OfficeException`.
- Order in the output follows the ECMA-376 schema sequences, not the order in the 2003 file: property lists (paragraph, run, table, row, cell,
  section, style, list level) are read into a set and written in schema order. A property that appears twice keeps its last occurrence.
- Hyperlink targets become external relationships. Nothing is fetched, linked pictures are not followed, and data in `w:binData` is decoded
  but never executed.
- Names carry hyphens in 2003 (`w:first-line`, `w:h-ansi`, `w:line-rule`) and camel case in 2006. Attribute and element names convert by that
  rule, with `w:fareast` → `eastAsia`. Hyphenated enumeration values (`dash-long`, `next-page`, `at-least`) convert the same way.
  Fractional measures (LibreOffice writes `4320.5401`) round to whole numbers; empty attributes are left out.

## Word

| 2003 | Becomes |
|---|---|
| `o:DocumentProperties` | `docProps/core.xml` (title, subject, author, keywords, description, last author, revision, created, saved, category) and `docProps/app.xml` (company, manager, pages, words, characters, lines, paragraphs, characters with spaces, total time) |
| `o:CustomDocumentProperties` | `docProps/custom.xml` (`dt:dt` string, boolean, integer, float) |
| `w:fonts/w:defaultFonts` | `w:docDefaults/w:rPrDefault/w:rFonts` |
| `w:styles/w:style` | `word/styles.xml`; `wx:uiName` is a hint and ignored (`w:name` is kept); latent styles are dropped |
| `w:lists` (`w:listDef`, `w:list`) | `word/numbering.xml` (`w:abstractNum`, `w:num`, level overrides); `w:nfc` codes map to number formats; `w:listPr` in a paragraph becomes `w:numPr` |
| `w:docPr` | `word/settings.xml`: zoom, track revisions, default tab stop, character spacing control; even-page headers set `w:evenAndOddHeaders` |
| `wx:sect`, `wx:sub-section` | read through; a section's `w:sectPr` goes on the last paragraph before it, the last section's closes the body |
| `w:hdr`, `w:ftr` (in `w:sectPr`) | `word/headerN.xml`, `word/footerN.xml` with `odd` → default, `even`, `first` |
| `w:p`, `w:r`, `w:t`, `w:tab`, `w:br`, `w:sym`, … | the same elements; a run nested in a run (LibreOffice inside a hyperlink) becomes a sibling |
| `w:tbl` | tables with grid, `w:hmerge` → `w:gridSpan`, `w:vmerge` → `w:vMerge`; a missing grid is made from the widest row; a cell always ends with a paragraph |
| `w:fldSimple`, `w:fldChar` | unchanged |
| `w:hlink` | `w:hyperlink` (`w:dest` → relationship, `w:bookmark` → `w:anchor`) |
| `aml:annotation` bookmark start/end | `w:bookmarkStart/End` |
| `aml:annotation` `Word.Comment*` | `word/comments.xml`, `w:commentRangeStart/End`, `w:commentReference` |
| `aml:annotation` `Word.Insertion`, `Word.Deletion` | `w:ins`, `w:del` (text becomes `w:delText`) with author and date |
| `w:footnote`, `w:endnote` (inline in a run) | `word/footnotes.xml`, `word/endnotes.xml` with separators, and the reference |
| `w:pict` with `v:imagedata` and `w:binData` | a DrawingML inline picture (`word/media/imageN.*`; the type is taken from the bytes, the size from the VML `style`) |
| `w:pict` with `v:textbox` | a VML text box with converted content |
| `w:smartTag`, `w:customXml`, `w:sdt` | removed, text kept |

Dropped, with `loss.*` codes: `loss.unmapped-markup.<element>` (any element without a counterpart, one line per element name),
`loss.shapes` (VML shapes with neither picture nor text), `loss.pictures`, `loss.ole-objects` (reduced to the preview picture),
`loss.smart-tags`, `loss.custom-xml`, `loss.formatting-revisions` (tracked formatting changes), `loss.comments` (a comment anchored between
paragraphs). Proofing marks and permission ranges are dropped silently: they describe the editing session, not the document.

## Excel

| 2003 | Becomes |
|---|---|
| `Worksheet`, `Table`, `Row`, `Cell` | sheets, rows, cells. `ss:Index` places an item (a backward index follows the previous item, `sml2003.bad-index`); `ss:Span` repeats a column or row; `ss:MergeAcross`/`MergeDown` merge |
| `Data` `ss:Type` | `Number`; `String` (inline string); `DateTime` (ISO 8601 → serial in the workbook's date system; a time alone on 1899-12-31 is a fraction of a day); `Boolean`; `Error` |
| `ss:Data` with HTML (`B`, `I`, `U`, `S`, `Sub`, `Sup`, `Font`) | rich inline string runs |
| `ss:Formula` (R1C1) | A1 text through the public formula parser and printer; the cached `Data` stays as the cached result; nothing is recalculated on open. `ss:ArrayRange` gives an array formula. Text the parser rejects is `sml2003.bad-formula` and the value stays as a constant |
| `Styles/Style` | cell formats; `ss:Parent` is resolved (a style with no parent inherits from `Default`); the number format names of the 2003 documentation (`Short Date`, `Percent`, `Currency` …) map to format codes |
| `Column`, `Row` attributes | widths (points → characters, below), heights, `ss:Hidden`, `ss:StyleID` (a cell without a style takes its row's, then its column's) |
| `Names`, `NamedRange`, `NamedCell` | defined names (workbook and sheet level); `Print_Area`, `Print_Titles`, `Criteria`, `Extract`, `_FilterDatabase` become the `_xlnm.` names |
| `Comment` | `xl/commentsN.xml` and a legacy drawing so the note shows |
| `ss:HRef` | a hyperlink (`#Sheet!A1` is internal) |
| `x:ConditionalFormatting` | `cellIs` and `expression` rules with a differential format from the CSS in `Format Style` |
| `x:DataValidation` | whole, decimal, list, date, time, text length and custom rules |
| `x:AutoFilter` | an auto filter range |
| `x:WorksheetOptions` | tab selection, gridlines and headings, right-to-left, zoom, frozen panes, protection, page margins, orientation, scale, paper size, centering, header and footer |
| `x:ExcelWorkbook` | date system (`Date1904`), active sheet, structure protection |
| `o:DocumentProperties` | core and app properties |

Deviations and choices:

- **Column widths.** 2003 stores points; XLSX stores characters of the default font's digit. The reader assumes a 7 pixel digit and 5 pixels of
  padding at 96 dpi: `(points × 96 / 72 − 5) / 7`, rounded to two places (48 points is 8.43 characters).
- **Duplicate style IDs.** The first definition wins (`sml2003.duplicate-style`). LibreOffice writes `Default` twice, the second time in full.
- **Named styles.** A named cell style (`ss:Name` other than `Default`) becomes a plain cell format; the name is reported as `loss.cell-style-names`.
- **Sheet names.** Characters `[]:*?/\` are removed, names are cut to 31 characters and made unique ignoring case (`sml2003.sheet-name`).
- **OpenFormula text.** LibreOffice's "Microsoft Excel 2003 XML" export writes `of:=[.B2]+[.B3]` in `ss:Formula`. That is not R1C1 and is not read here
  (OpenFormula belongs to the ODF reader); each such formula is a defect and its cached value is kept.
- **Not carried over**: manual page breaks (`loss.page-breaks`), sorting, pane details beyond the frozen split, printer settings.

## Checks and open questions

Checked on the build host: every file the sniffer calls Word or Excel 2003 XML among the committed fixtures and 87 Word and 4 Excel files written by
LibreOffice from its own corpus opens with typed defects only; their DOCX/XLSX conversions validate against the pinned ECMA-376 Transitional schemas
(1,157 of 1,158 parts; the one miss is `xml:space` on a spreadsheet `t` element, which the schema does not declare and Excel itself writes).

Unanswered by Office (to be answered on the oracle machine):

1. Does Word open the DOCX converted from `testdata/xml2003/word-features.xml` and `lo-word.xml` without a repair prompt, and does Word's own
   conversion of the 2003 file match (paragraph count, numbering labels, revisions, comment text, picture size)?
2. Does Excel open the XLSX converted from `excel-features.xml` without repair (comments with the legacy drawing, conditional formats, validation), and
   does Excel's own "Save as .xlsx" of the 2003 file give the same values, formats and formulas?
3. Which style wins when a style ID is defined twice, and does a cell without `ss:StyleID` take its row's or its column's style?
4. What column width does Excel give `ss:Width="64.008"` on a machine with the default font (the width formula above is an estimate)?

Regenerate the conversions with `tools/Xml2003Probe convert <dir> <out>`; `tools/xml2003/` holds the inputs LibreOffice converted for the fixtures.
