Skip to content

Commit 43edf8c

Browse files
committed
table: add alt text options
Add `title` and `description` parameters to the Table object to allow alternative text to be specified.
1 parent 02e3b0b commit 43edf8c

File tree

7 files changed

+259
-1
lines changed

7 files changed

+259
-1
lines changed

lib/Excel/Writer/XLSX.pm

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6354,6 +6354,8 @@ The last parameter in C<add_table()> should be a hash ref containing the paramet
63546354
total_row
63556355
columns
63566356
name
6357+
description
6358+
title
63576359
63586360
The table parameters are detailed below. There are no required parameters and the hash ref isn't required if no options are specified.
63596361
@@ -6615,6 +6617,27 @@ Formatting can also be applied to columns, to the column data using C<format> an
66156617
Standard Excel::Writer::XLSX format objects can be used. However, they should be limited to numerical formats for the columns and simple formatting like text wrap for the headers. Overriding other table formatting may produce inconsistent results.
66166618
66176619
6620+
=head2 description
6621+
6622+
The C<description> parameter can be used to set the alt text description for
6623+
the table. This is useful for accessibility purposes and for users of screen
6624+
readers:
6625+
6626+
$worksheet->add_table( 'B3:F7', {
6627+
description => 'Table with the sales data for Spain'
6628+
} );
6629+
6630+
=head2 title
6631+
6632+
The C<title> parameter can be used to set the alt text title for the table.
6633+
This is useful for accessibility purposes and for users of screen readers. It
6634+
can be used in conjunction with the C<description> parameter:
6635+
6636+
$worksheet->add_table( 'B3:F7', {
6637+
title => 'Sales data table',
6638+
description => 'Table with the sales data for Spain'
6639+
} );
6640+
66186641
66196642
=head1 FORMULAS AND FUNCTIONS IN EXCEL
66206643

lib/Excel/Writer/XLSX/Package/Table.pm

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ sub _assemble_xml_file {
7676
# Write the tableStyleInfo element.
7777
$self->_write_table_style_info();
7878

79+
# Write the extLst element for alt text/title.
80+
$self->_write_ext_lst();
7981

8082
# Close the table tag.
8183
$self->xml_end_tag( 'table' );
@@ -314,6 +316,66 @@ sub _write_totals_row_formula {
314316
}
315317

316318

319+
##############################################################################
320+
#
321+
# _write_ext_lst()
322+
#
323+
# Write the <extLst> element for the alt text/description.
324+
#
325+
sub _write_ext_lst {
326+
327+
my $self = shift;
328+
my $props = $self->{_properties};
329+
330+
if ( !$props->{_description} && !$props->{_title} ) {
331+
return;
332+
}
333+
334+
my $uri = '{504A1905-F514-4f6f-8877-14C23A59335A}';
335+
my $xmlns = 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main';
336+
337+
my @attributes = (
338+
'uri' => $uri,
339+
'xmlns:x14' => $xmlns,
340+
);
341+
342+
343+
$self->xml_start_tag( 'extLst' );
344+
$self->xml_start_tag( 'ext', @attributes );
345+
346+
# Write the x14:table element.
347+
$self->_write_x14_table();
348+
349+
$self->xml_end_tag( 'ext' );
350+
$self->xml_end_tag( 'extLst' );
351+
}
352+
353+
354+
##############################################################################
355+
#
356+
# _write_x14_table()
357+
#
358+
# Write the <x14:table> element.
359+
#
360+
sub _write_x14_table {
361+
362+
my $self = shift;
363+
my $props = $self->{_properties};
364+
365+
my @attributes = ();
366+
367+
if ( $props->{_title} ) {
368+
push @attributes, ( 'altText' => $props->{_title} );
369+
}
370+
371+
if ( $props->{_description} ) {
372+
push @attributes, ( 'altTextSummary' => $props->{_description} );
373+
}
374+
375+
$self->xml_empty_tag( 'x14:table', @attributes );
376+
}
377+
378+
317379
1;
318380

319381

lib/Excel/Writer/XLSX/Worksheet.pm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4964,6 +4964,8 @@ sub add_table {
49644964
name => 1,
49654965
style => 1,
49664966
total_row => 1,
4967+
description => 1,
4968+
title => 1,
49674969
);
49684970

49694971
# Check for valid input parameters.
@@ -4995,7 +4997,8 @@ sub add_table {
49954997
$table{_show_col_stripes} = $param->{banded_columns} ? 1 : 0;
49964998
$table{_header_row_count} = $param->{header_row} ? 1 : 0;
49974999
$table{_totals_row_shown} = $param->{total_row} ? 1 : 0;
4998-
5000+
$table{_description} = $param->{description};
5001+
$table{_title} = $param->{title};
49995002

50005003
# Set the table name.
50015004
if ( defined $param->{name} ) {

t/regression/table38.t

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
###############################################################################
2+
#
3+
# Tests the output of Excel::Writer::XLSX against Excel generated files.
4+
#
5+
# Copyright 2000-2025, John McNamara, jmcnamara@cpan.org
6+
#
7+
# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
8+
#
9+
10+
use lib 't/lib';
11+
use TestFunctions qw(_compare_xlsx_files _is_deep_diff);
12+
use strict;
13+
use warnings;
14+
15+
use Test::More tests => 1;
16+
17+
###############################################################################
18+
#
19+
# Tests setup.
20+
#
21+
my $filename = 'table38.xlsx';
22+
my $dir = 't/regression/';
23+
my $got_filename = $dir . "ewx_$filename";
24+
my $exp_filename = $dir . 'xlsx_files/' . $filename;
25+
26+
my $ignore_members = [];
27+
my $ignore_elements = {};
28+
29+
30+
###############################################################################
31+
#
32+
# Test the creation of a simple Excel::Writer::XLSX file with tables.
33+
#
34+
use Excel::Writer::XLSX;
35+
36+
my $workbook = Excel::Writer::XLSX->new( $got_filename );
37+
my $worksheet = $workbook->add_worksheet();
38+
39+
$worksheet->write(1, 0, 1);
40+
$worksheet->write(2, 0, 2);
41+
$worksheet->write(3, 0, 3);
42+
$worksheet->write(4, 0, 4);
43+
$worksheet->write(5, 0, 5);
44+
45+
$worksheet->write(1, 1, 10);
46+
$worksheet->write(2, 1, 15);
47+
$worksheet->write(3, 1, 20);
48+
$worksheet->write(4, 1, 10);
49+
$worksheet->write(5, 1, 15);
50+
51+
# Set the column width to match the target worksheet.
52+
$worksheet->set_column('A:B', 10.288);
53+
54+
# Add the table.
55+
$worksheet->add_table('A1:B6', { description => 'Alt text', title => 'Alt title' });
56+
57+
$workbook->close();
58+
59+
60+
###############################################################################
61+
#
62+
# Compare the generated and existing Excel files.
63+
#
64+
65+
my ( $got, $expected, $caption ) = _compare_xlsx_files(
66+
67+
$got_filename,
68+
$exp_filename,
69+
$ignore_members,
70+
$ignore_elements,
71+
);
72+
73+
_is_deep_diff( $got, $expected, $caption );
74+
75+
76+
###############################################################################
77+
#
78+
# Cleanup.
79+
#
80+
unlink $got_filename;
81+
82+
__END__
83+
84+
85+

t/regression/table39.t

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
###############################################################################
2+
#
3+
# Tests the output of Excel::Writer::XLSX against Excel generated files.
4+
#
5+
# Copyright 2000-2025, John McNamara, jmcnamara@cpan.org
6+
#
7+
# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
8+
#
9+
10+
use lib 't/lib';
11+
use TestFunctions qw(_compare_xlsx_files _is_deep_diff);
12+
use strict;
13+
use warnings;
14+
15+
use Test::More tests => 1;
16+
17+
###############################################################################
18+
#
19+
# Tests setup.
20+
#
21+
my $filename = 'table39.xlsx';
22+
my $dir = 't/regression/';
23+
my $got_filename = $dir . "ewx_$filename";
24+
my $exp_filename = $dir . 'xlsx_files/' . $filename;
25+
26+
my $ignore_members = [];
27+
my $ignore_elements = {};
28+
29+
30+
###############################################################################
31+
#
32+
# Test the creation of a simple Excel::Writer::XLSX file with tables.
33+
#
34+
use Excel::Writer::XLSX;
35+
36+
my $workbook = Excel::Writer::XLSX->new( $got_filename );
37+
my $worksheet = $workbook->add_worksheet();
38+
39+
$worksheet->write(1, 0, 1);
40+
$worksheet->write(2, 0, 2);
41+
$worksheet->write(3, 0, 3);
42+
$worksheet->write(4, 0, 4);
43+
$worksheet->write(5, 0, 5);
44+
45+
$worksheet->write(1, 1, 10);
46+
$worksheet->write(2, 1, 15);
47+
$worksheet->write(3, 1, 20);
48+
$worksheet->write(4, 1, 10);
49+
$worksheet->write(5, 1, 15);
50+
51+
# Set the column width to match the target worksheet.
52+
$worksheet->set_column('A:B', 10.288);
53+
54+
# Add the table.
55+
$worksheet->add_table('A1:B6', { description => 'Alt text' });
56+
57+
$workbook->close();
58+
59+
60+
###############################################################################
61+
#
62+
# Compare the generated and existing Excel files.
63+
#
64+
65+
my ( $got, $expected, $caption ) = _compare_xlsx_files(
66+
67+
$got_filename,
68+
$exp_filename,
69+
$ignore_members,
70+
$ignore_elements,
71+
);
72+
73+
_is_deep_diff( $got, $expected, $caption );
74+
75+
76+
###############################################################################
77+
#
78+
# Cleanup.
79+
#
80+
unlink $got_filename;
81+
82+
__END__
83+
84+
85+
6.71 KB
Binary file not shown.
6.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)