Technical Article

XLSX Font Family Classification in Delphi: What Does Zero Mean?

The spreadsheet looks the same after saving, but a font's XLSX metadata can still change. HotXLS stores the requested typeface name and its family classification as distinct values: zero means the family is unspecified and is written without a family element, while a positive classification is retained

A font name asks the spreadsheet application for a particular face; the family value describes its broad design category. In TXLSXFont.Family, 1 through 5 identify Roman, Swiss, Modern, Script and Decorative respectively. The number does not install that face or change the name stored beside it. A workbook can therefore request a named font even when it leaves the family category unspecified, and the application opening the file remains responsible for finding or substituting the requested face

Where is the font classification stored?

The route from a cell to its font is indirect. An XLSX file is a ZIP package, and the worksheet cell refers to a style whose font information lives in shared records in xl/styles.xml. Follow that reference when a report looks different on another machine: reading the text displayed in the cell tells us little about the stored font definition. A font record may include a name with no family child, or it may have a positive classification alongside that name. Both are meaningful metadata choices. Neither embeds a font program in the workbook or proves the requested face is installed on the computer opening it. When the face is unavailable, the spreadsheet application chooses a substitute, and the chosen substitute can affect the appearance even though the workbook metadata remains unchanged

<font>
  <name val="Example Sans"/>
  <family val="2"/>
</font>

The fragment names Example Sans and gives it the Swiss classification. It is one font record within a larger style table, not a complete workbook. If no category has been specified, HotXLS writes that font without a family child; the name can still be present and can still identify the requested typeface

Set the classification when you actually know it

The first Delphi routine creates a workbook, adds one custom font and assigns it to a cell. The index returned from the font collection is adjusted when the example assigns the cell's FontIndex, so the two properties should be read with their respective indexing conventions in mind

uses
  SysUtils, lxHandleX;

procedure SaveFontExample(const FileName: string);
var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  FontIndex: Integer;
  Font: TXLSXFont;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Report');
    Sheet.Cells[1, 1].Value := 'Quarterly report';

    FontIndex := Book.Fonts.Add('Arial', 11, False, False);
    Font := Book.Fonts[FontIndex];
    Font.Family := 2;
    Sheet.Cells[1, 1].FontIndex := FontIndex + 1;

    Book.SaveAs(FileName);
  finally
    Book.Free;
  end;
end;

The 2 assigned in the example means Swiss. It is the classification of the font record, not a request for a second font. We created and saved a workbook containing Arial with family 2, reopened it with HotXLS, and read back both values. The corresponding font definition is stored in xl/styles.xml. If you examine the package directly, retain the surrounding font and style tables when you make a smaller example: a font entry on its own does not tell you which worksheet cells refer to it. Two cells can share a font record while using different fills or number formats, so a visual change elsewhere in the style does not by itself establish that the family value changed. Repeating the exercise with zero gives an unspecified family. HotXLS omits the family element in that output, while keeping the font name. For an unfamiliar positive value, retain the number in the diagnostic record rather than assigning it one of the five familiar labels by guesswork

Zero, an absent element, and a byte-for-byte comparison

An explicit zero and an absent element deserve a closer look during a round trip. If an input font says <family val="0"/>, HotXLS reads its family value as zero and writes the output without that child element. The semantic result remains unspecified, but the XML spelling changes. A byte-for-byte archival or signature workflow therefore has a different requirement from an application that only needs to preserve the font's meaning. A positive value gives another useful case: family val="3" identifies Modern and should remain 3 after reading, saving and reopening. Other positive values are passed through too. Preserve an unfamiliar number until the source application or specification gives you enough context to interpret it; treating every unknown category as one of the common five would discard information

A round-trip check that catches the two cases

To exercise the two cases, you can create font records with the same name and assign family 0 to one and family 2 to the other. Save and reopen the workbook, follow each cell's style to its font, and read the values back. In the saved xl/styles.xml, the zero case has no family child while the positive case carries its value. That answers a metadata question; a rendered face depends on the fonts installed in the environment that opens the file. For a substitution investigation, use a machine where the requested face is absent and record the face the spreadsheet application chooses. Different viewers or operating systems can make different choices. In the Delphi routine below, zero denotes the default cell font, so the code checks the index before converting it to a font-collection index

procedure InspectSavedFont(const FileName: string);
var
  Book: TXLSXWorkbook;
  FontIndex: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open(FileName) <> 1 then
      raise Exception.Create('Cannot open workbook');
    if Book.Sheets.Count = 0 then
      raise Exception.Create('Workbook has no sheets');
    FontIndex := Book.Sheets[1].Cells[1, 1].FontIndex;
    if (FontIndex <= 0) or (FontIndex > Book.Fonts.Count) then
      raise Exception.Create('Cell has no custom font');
    Writeln('Name: ', Book.Fonts[FontIndex - 1].Name);
    Writeln('Family: ', Book.Fonts[FontIndex - 1].Family);
  finally
    Book.Free;
  end;
end;

For the workbook created by SaveFontExample, the reopened family should be 2. With 0 assigned instead, the value is unspecified and the saved font record has no family element. Read the workbook and its style table together to see both parts of the result. The second routine checks that the workbook contains a worksheet and that the cell points to a custom font before it reads the collection. If the cell uses the default font, its index is zero; subtracting one without that check would address the wrong collection position. Collection indexes belong to the workbook being read; a number recorded from one file may identify a different definition in another

What about font indices and other styles?

An index is useful only in the context of the workbook that owns it. Style records can be reorganized during a save, so follow the reopened cell to its resolved font instead of treating an index from the original package as the font's permanent identity. Check the name and family, then the rest of the style: fill, border, alignment, number format and protection can affect the report too. If the metadata is intact but the appearance changes on another computer, look for the requested face in that environment and determine how the spreadsheet application substitutes it. We prefer that sequence—cell style, font record, target environment—before changing the family value, because it separates the stored metadata from the machine's choice of an available font

Choosing a value for new files

Keep a category supplied by an existing template when it is known. For a new font with no known family, zero is the honest choice; guessing would add a classification the source never supplied. An application that owns a controlled font catalog can record categories there and apply them consistently. When several font records share a name, the first matching name in the collection need not be the one used by your cell. For related formatting work, the cell styles and rich text guide covers cell-level styles, and XLSX round-trip preservation discusses other package features. The workbook and font routines used above belong to the HotXLS Delphi Component