Skip to content

xlsx: 3Stars, 3Triangles and 5Boxes are written into the base iconSet attribute, which the schema does not allow #403

Description

@t-ujiie-g

Three of the twenty icon-set names icon_set_steps accepts produce a workbook that fails Open XML schema validation, and Excel offers to repair it: 3Stars, 3Triangles, 5Boxes.

Those three were added in Excel 2010 and exist only in the x14 extension schema. ST_IconSetType in the base SpreadsheetML schema (ECMA-376 Part 1 §18.18.42) has seventeen values and none of them:

3Arrows, 3ArrowsGray, 3Flags, 3Signs, 3Symbols, 3Symbols2, 3TrafficLights1, 3TrafficLights2, 4Arrows, 4ArrowsGray, 4Rating, 4RedToBlack, 4TrafficLights, 5Arrows, 5ArrowsGray, 5Quarters, 5Rating

build_icon_set_rule writes whatever name it is given straight into the base attribute (xlsx/conditional_format.mbt:773):

sb.write_view(
  "<iconSet iconSet=\"\{escape_xml_attr(opt.icon_style)}\" showValue=\"\{show_value}\"",
)

and icon_set_steps (xlsx/conditional_format.mbt:468) admits all three:

"3Arrows" || "3Stars" || "3Triangles" => Some(["0", "33", "67"])
…
"5Arrows" | "5ArrowsGray" | "5Boxes" | "5Quarters" | "5Rating" => Some([…])

Reproduction

let wb = @xlsx.Workbook::new()
let sheet = wb.new_sheet("S")
sheet.set_cell_value("A1", @xlsx.CellValue::Number(1.0))
sheet.set_cell_value("A2", @xlsx.CellValue::Number(2.0))
sheet.set_cell_value("A3", @xlsx.CellValue::Number(3.0))
let opt = @xlsx.ConditionalFormatOptions::new("icon_set")
opt.set_icon_style("5Boxes")
wb.set_conditional_format("S", "A1:A3", [opt])

Validated with the Open XML SDK (OpenXmlValidator, FileFormatVersions.Office2013):

Sch_AttributeValueDataTypeDetailed /x:worksheet[1]/x:conditionalFormatting[1]/x:cfRule[1]/x:iconSet[1]
  The attribute 'iconSet' has invalid value '5Boxes'. The Enumeration constraint failed.

One workbook per accepted name, all twenty:

ok  3Arrows      ok  3Symbols        ok  4Arrows        ok  5Arrows
ok  3ArrowsGray  ok  3Symbols2       ok  4ArrowsGray    ok  5ArrowsGray
ok  3Flags       ok  3TrafficLights1 ok  4Rating        FAIL 5Boxes
ok  3Signs       ok  3TrafficLights2 ok  4RedToBlack    ok  5Quarters
FAIL 3Stars      FAIL 3Triangles     ok  4TrafficLights ok  5Rating

What Excel writes for these three

A base rule holding a fallback icon set from the legal seventeen, plus the real one in the x14 extension, joined by a GUID id:

<!-- sheetData … then, in the worksheet -->
<conditionalFormatting sqref="A1:A3">
  <cfRule type="iconSet" priority="1">
    <extLst>
      <ext xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
           uri="{B025F937-C7B1-47D3-B67F-A62EFF666E3E}">
        <x14:id>{4EC6E01C-…}</x14:id>
      </ext>
    </extLst>
    <iconSet iconSet="3TrafficLights1">…</iconSet>   <!-- the fallback -->
  </cfRule>
</conditionalFormatting>
…
<extLst>
  <ext uri="{78C0D931-6437-407d-A8EE-F0AAD7539E65}" xmlns:x14="…/2009/9/main">
    <x14:conditionalFormattings>
      <x14:conditionalFormatting xmlns:xm="…/excel/2006/main">
        <x14:cfRule type="iconSet" priority="1" id="{4EC6E01C-…}">
          <x14:iconSet iconSet="5Boxes">…</x14:iconSet>
        </x14:cfRule>
        <xm:sqref>A1:A3</xm:sqref>
      </x14:conditionalFormatting>
    </x14:conditionalFormattings>
  </ext>
</extLst>

Suggested fix

The machinery already exists — write.mbt:2157 writes exactly this x14:conditionalFormattings block for advanced data bars. Routing the three 2010-only icon sets through the same path, with a same-arity fallback in the base rule (3TrafficLights1 for the three-icon sets, 5Rating for 5Boxes), makes them valid and keeps them rendering in Excel 2010+.

If that is more than it is worth, rejecting the three from icon_set_steps with an XlsxError would at least turn a silently corrupt workbook into an error a caller can act on. Today they are accepted and the damage is only visible when a user opens the file.

Environment: bobzhang/mbtexcel@0.1.9, macOS, native target. Found by running the Open XML SDK validator over every icon set our schema exposes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions