A C++ library for reading, writing, creating and modifying Microsoft Excel® (.xlsx) files.
C++
1,789
918 commits
updated Jun 15, 2026
OpenXLSX is a C++ library for reading, writing, creating and modifying Microsoft Excel® files, with the .xlsx format.
NOTE: With today's release v0.5.1, this repository is discontinued on github. It has been migrated to Codeberg, and will eventually be moved to @troldal's Codeberg.
Please do not open any more issues or pull requests on github, and instead submit your feature requests directly on Codeberg.
After creating an account on codeberg.org, you will be able to "own" and edit issues and comments previously created by you by linking your github account to codeberg via "Sign in with Github", direct link here.
This version, with updates from 2026-06-13, is the latest release.
Note: generally, for features awaiting implementation, refer to the open issues in the repository
BUILD_SHARED_LIBS functionality in Makefile.GNUMakefile.GNU, check for available dependencies and error out if any are missingFor the latest functionality updates, please refer to the development branch. Feel free to have a look. This way you don't have to wait until the main repository is updated.
0.5.1 - git tag will be updated in one of the next commitsOPENXLSX_MONOLITHIC_LIBRARY requires static, BUILD_SHARED_LIBS requires shared dependencies) and triggering (if enabled) automatic download from upstream if the required dependency is not availablevoid XLWorksheet::setDimension functions to set it, with auto-calculation of last cell, if desired. This addresses issue 361. Supported function overloads:void XLWorksheet::setDimension(XLCellReference topLeft, XLCellReference bottomRight, bool autoCalculateLastCell);
void XLWorksheet::setDimension(std::string topLeft, std::string bottomRight);
void XLWorksheet::setDimension(std::string dimension);
-DOPENXLSX_MONOLITHIC_LIBRARY=ON - this requires static dependencies and only works with miniz, fails with libzip (or rather: the libzip (sub-)dependencies will not be linked into the resulting bundled library)OpenXLSXFileSystemTools.hpp pathExists), nowide::stat is now used when nowide is in use. This should make calls to XLDocument::create and XLDocument::saveAs behave well with filenames containing unicode charactersOpenXLSXFileSystemTools fileSize to wrap call to stat with nowide compatibility - this is used in LibZip.hpp loadArchiveDataChange history is found in the detailed change log.
After a long period of inactivity, I have decided to resume development of OpenXLSX. The code has been cleaned up and a significant number of bugs have been fixed. The library has been tested on Windows, macOS and Linux, and should work on all platforms.
I would like to extend my sincere thanks to all the people who have contributed to the project, either by reporting bugs, suggesting features or by submitting pull requests. I would also like to thank all the people who have starred the project, and who have shown interest in the project.
In particular, I would like to thank Lars Uffmann (https://codeberg.org/lars_uffmann/) for his contributions to the project. Lars has spent significant time and effort in cleaning up the code, fixing bugs and implementing new features. Without his help, the project would not have been in the state it is today.
Many programming languages have the ability to modify Excel files, either natively or in the form of open source libraries. This includes Python, Java and C#. For C++, however, things are more scattered. While there are some libraries, they are generally less mature and have a smaller feature set than for other languages.
Because there are no open source library that fully fitted my needs, I decided to develop the OpenXLSX library.
The ambition is that OpenXLSX should be able to read, write, create and modify Excel files (data as well as formatting), and do so with as few dependencies as possible. Currently, OpenXLSX depends on the following 3rd party libraries:
-DOPENXLSX_ENABLE_LIBZIP=ONAs of version 0.5.0, these libraries are no longer included in the repository, and there are three ways to build OpenXLSX against them:
find_packagegitAlso, focus has been put on speed, not memory usage (although there are options for reducing the memory usage, at the cost of speed; more on that later).
OpenXLSX has been tested on the following platforms/compilers. Note that a '-' doesn't mean that OpenXLSX doesn't work; it just means that it hasn't been tested:
| GCC | Clang | MSVC | |
|---|---|---|---|
| Windows | MinGW | MinGW | + |
| Cygwin | - | - | N/A |
| MacOS | + | + | N/A |
| Linux | + | + | N/A |
The following compiler versions should be able to compile OpenXLSX without errors:
Clang 7 should be able to compile OpenXLSX, but apparently there is a bug in the implementation of std::variant, which causes compiler errors.
Visual Studio 2017 should also work, but hasn't been tested.
OpenXLSX uses CMake as the build system (or build system generator, to be exact) and git to pull in dependencies. Therefore, you must install CMake first, in order to build OpenXLSX. You can find (bad) installation instructions on www.cmake.org. If you wish the cmake to automatically fetch missing dependencies, you also need to install git.
Here is a summary to get a working configuration of cmake + git.
cmake & git on debian-based Linux distributionssudo apt update
sudo apt install build-essential cmake git
cmake & git on Windows 10/11 (for now only tested with MSYS Makefiles)Install MSYS2:
In a Powershell (run as Administrator): run winget install --id MSYS2.MSYS2 -e
→ After performing this step, the "MSYS2 MSYS shell" and the "MSYS2 MinGW 64-bit shell" should be accessible from the Start Menu
In MSYS2 MSYS shell: run pacman -Syu
The previous instruction might require a close & reopen of the MSYS2 MSYS shell
In MSYS2 MSYS shell: run pacman -Su
Install development toolchain:
In MSYS2 MinGW 64‑bit shell: run pacman -S --needed base-devel mingw-w64-x86_64-toolchain
Install cmake & git in MSYS2 environment:
pacman -S --needed mingw-w64-x86_64-cmake mingw-w64-x86_64-gitpacman -S --needed mingw-w64-x86_64-ninjaVerify installation:
In MSYS2 MinGW 64‑bit shell: verify versions of git, cmake, gcc, g++
git --version; cmake --version; gcc --version; g++ --version
In MSYS2 MinGW 64‑bit shell
git clone https://github.com/troldal/OpenXLSX <destination-folder>
cd <destination-folder>
mkdir build; cd build
Then build with MSYS Gnu make:
cmake .. -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel
Note: As of 2026-03-21, this configuration complains about miniz (if used) being incompatible with cmake versions >3.5; the following command sequence can be used to get rid of the warning:
cmake .. -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build . --parallel
or build with MinGW Gnu make (untested - should provide a working configuration that can be compiled from cmd/Powershell)
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel
or build with ninja (untested)
cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release
ninja
The OpenXLSX library is located in the OpenXLSX subdirectory to this repo. However, the root folder CMakeLists.txt establishes the library configuration and dependencies.
If you use CMake for your own project, you can add the OpenXLSX root folder as a subdirectory to your own project.
Alternatively, you can use CMake to generate make files or project files for a toolchain of your choice. Both methods are described in the following.
By far the easiest way to use OpenXLSX in your own project, is to use CMake yourself, and then add the OpenXLSX root folder as a subdirectory to the source tree of your own project. Several IDE's support CMake projects, most notably Visual Studio 2019, JetBrains CLion, and Qt Creator. If using Visual Studio, you have to specifically select 'CMake project' when creating a new project.
The main benefit of including the OpenXLSX library as a source subfolder, is that there is no need to locate the library and header files specifically; CMake will take care of that for you. Also, the library will be built using the same configuration (Debug, Release etc.) as your project. In particular, this a benefit on Windows, where is it not possible to use Release libraries in a Debug project (and vice versa) when STL objects are being passed through the library interface, as they are in OpenXLSX. When including the OpenXLSX source, this will not be a problem.
By using the add_subdirectory() command in the CMakeLists.txt file for your project, you can get access to the
headers and library files of OpenXLSX. OpenXLSX can generate either a shared library or a static library. By default
it will produce a static library, but you can change that by setting BUILD_SHARED_LIBS to ON. The library is
located in a namespace called OpenXLSX; hence the full name of the library is OpenXLSX::OpenXLSX.
Including OpenXLSX into your project would look like this inside your project's CMakeLists.txt:
# ============================================================================
# Configure OpenXLSX
# ============================================================================
set(OPENXLSX_CREATE_DOCS OFF)
set(OPENXLSX_BUILD_SAMPLES OFF)
set( BUILD_SHARED_LIBS OFF)
add_subdirectory( OpenXLSX )
Then you can use target_link_libraries and target_include_directories like so:
# Configure linkage for myapp
target_link_libraries(myapp PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(myapp PRIVATE ${OpenXLSX_INCLUDES})
For linking against a shared library, you should include the "rpath" into your final applications:
# Ensure configuration of install RPATH for myapp
set_target_properties(myapp PROPERTIES
INSTALL_RPATH_USE_LINK_PATH TRUE
)
The following snippet is a minimum CMakeLists.txt file for your own project, that includes OpenXLSX as a subdirectory. Note that the output location of the binaries are set to a common directory. On Linux and MacOS, this is not really required, but on Windows, this will make your life easier, as you would otherwise have to copy the OpenXLSX shared library file to the location of your executable in order to run.
cmake_minimum_required(VERSION 3.14)
project(myapp
VERSION 1.0.0
LANGUAGES CXX
)
# ============================================================================
# Example app configuration
# ============================================================================
add_executable(myapp myapp.cpp)
# ============================================================================
# Configure OpenXLSX
# ============================================================================
option(BUILD_SHARED_LIBS OFF "can be used to build shared library version of OpenXLSX")
set( OPENXLSX_CREATE_DOCS OFF)
set( OPENXLSX_BUILD_SAMPLES OFF)
add_subdirectory( OpenXLSX )
# Configure linkage for myapp
target_link_libraries(myapp PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(myapp PRIVATE ${OpenXLSX_INCLUDES})
# Ensure configuration of install RPATH for myapp
set_target_properties(myapp PROPERTIES
INSTALL_RPATH_USE_LINK_PATH TRUE
)
# Installation steps for myapp
install(TARGETS myapp
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT Runtime
)
Using the above, you should be able to compile and run the following code, which will generate a new Excel file named 'Spreadsheet.xlsx':
#include <OpenXLSX.hpp>
using namespace OpenXLSX;
int main() {
XLDocument doc;
doc.create("Spreadsheet.xlsx", XLForceOverwrite);
auto wks = doc.workbook().worksheet("Sheet1");
wks.cell("A1").value() = "Hello, OpenXLSX!";
doc.save();
return 0;
}
If you wish to produce the OpenXLSX binaries and include them in your project yourself, it can be done using CMake and a compiler toolchain of your choice.
From the command line, navigate the OpenXLSX subdirectory of the project root, and execute the following commands:
mkdir build
cd build
cmake ..
The last command will configure the project. This will configure the project using the default toolchain. If you
want to specify the toolchain, type cmake -G "<toolchain>" .. with <toolchain> being the toolchain you wish to
use, for example "Unix Makefiles", "Ninja", "Xcode", or "Visual Studio 16 2019". See the CMake documentation for
details.
Finally, you can build the library using the command:
cmake --build . --target OpenXLSX --config Release
You can change the --target and --config arguments to whatever you wish to use.
When built, you can install it using the following command (as superuser / sudo):
cmake --install .
This command will install the library and header files to the default location on your platform (usually /usr/local/ on Linux and MacOS, and C:\Program Files on Windows). You can set a different location using the --prefix argument.
Note that depending on the platform, it may not be possible to install both debug and release libraries. On Linux and MacOS, this is not a big issue, as release libraries can be used for both debug and release executables. Not so for Windows, where the configuration of the library must be the same as for the executable linking to it. For that reason, on Windows, it is much easier to just include the OpenXLSX source folder as a subdirectory to your CMake project; it will save you a lot of headaches.
g++With the most recent updates, the OpenXLSX CMake configuration will also configure (and install) a pkg-config file for libOpenXLSX (and libminiz), to simplify linking a program against OpenXLSX for systems on which pkg-config is available. Invoking pkg-config --cflags will yield the proper include flags, and pkg-config --static --libs will yield the linker instructions for the OpenXLSX library and its dependencies (pugixml and zip library).
The sequence of arguments to the compiler is important:
g++ `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp `pkg-config --static --libs OpenXLSX`
When linking against a shared library, the library runtime search path (rpath) should be included in the command. The OpenXLSX package config file provides the rpath setting via pkg-config --libs, so that the following, simplified line should work:
g++ `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp `pkg-config --libs OpenXLSX`
If this new feature does not work as intended, please try providing the rpath manually:
g++ -Wl,-rpath,/usr/local/lib `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp `pkg-config --libs OpenXLSX`
CAUTION: When attempting static linking while the shared library for OpenXLSX is also installed, the -lOpenXLSX flag returned from pkg-config --static --libs OpenXLSX will fail to link against the static library.
A manual fix like so should work (this is only an example, for libzip configuration, without nowide; see below):
g++ `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp -L/usr/local/lib -l:libOpenXLSX.a -L/usr/local/lib/OpenXLSX -l:libpugixml.a -l:libzip.a -lpugixml -lbz2 -llzma -lzstd -lssl -lcrypto -lz
Note that you will have to adjust the linker flags according to your configuration:
-l:libpugixml.a
-l:libminiz.a
-l:libzip.a (which requires -lbz2 -llzma -lzstd -lssl -lcrypto -lz)
-l:libnowide.a
However, the recommended solution for static linking is to not install the shared library (for now - might support different naming in the future).
cmakeBelow is a simple CMakeLists.txt template with all necessary steps to compile & link against an installed version of OpenXLSX.
Steps to test this (assuming OpenXLSX has been installed):
myappCMakeLists.txt template into myapp/myapp/srcDemo1.cpp into myapp/src/myapp/buildmyapp/buildcmake ..make all./myappCMakeLists.txt template:cmake_minimum_required(VERSION 3.14)
project(myapp
VERSION 1.0.0
LANGUAGES CXX
)
# ============================================================================
# Example app configuration
# ============================================================================
add_executable(myapp src/Demo1.cpp)
# Find dependency OpenXLSX
find_package(OpenXLSX CONFIG REQUIRED)
if(OpenXLSX_FOUND)
message( STATUS "FOUND OpenXLSX" )
get_target_property(OpenXLSX_INCLUDES OpenXLSX::OpenXLSX INTERFACE_INCLUDE_DIRECTORIES) # get OpenXLSX include directories
message( STATUS "OpenXLSX_INCLUDES is ${OpenXLSX_INCLUDES}" )
else()
message( FATAL_ERROR "MISSING DEPENDENCY OpenXLSX" )
endif()
# Configure linkage for myapp
target_link_libraries(myapp PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(myapp PRIVATE ${OpenXLSX_INCLUDES})
# Ensure configuration of install RPATH for myapp
set_target_properties(myapp PROPERTIES
INSTALL_RPATH_USE_LINK_PATH TRUE
)
# Installation steps for myapp
install(TARGETS myapp
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT Runtime
)
OpenXLSX is still work in progress. The following is a list of features which have been implemented and should be working properly:
Features related to plots and figures have not been implemented as of yet, and at least plot functionality is not planned to be implemented at all.
It should be noted that creating const XLDocument objects is currently not working!
Note: As of 2026-04-19 this section is severely outdated. It is not sure how well the numbers from ~2024 hold up with recent changes.
The table below is the output from a benchmark (using the Google Benchmark library), which shows that read/write access can be done at a rate of around 4,000,000 cells per second. Floating point numbers are somewhat lower, due to conversion to/from strings in the .xml file.
Run on (16 X 2300 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 256 KiB (x8)
L3 Unified 16384 KiB (x1)
Load Average: 2.46, 2.25, 2.19
---------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
---------------------------------------------------------------------------
BM_WriteStrings 2484 ms 2482 ms 1 items=8.38861M items_per_second=3.37956M/s
BM_WriteIntegers 1949 ms 1949 ms 1 items=8.38861M items_per_second=4.30485M/s
BM_WriteFloats 4720 ms 4719 ms 1 items=8.38861M items_per_second=1.77767M/s
BM_WriteBools 2167 ms 2166 ms 1 items=8.38861M items_per_second=3.87247M/s
BM_ReadStrings 1883 ms 1882 ms 1 items=8.38861M items_per_second=4.45776M/s
BM_ReadIntegers 1641 ms 1641 ms 1 items=8.38861M items_per_second=5.11252M/s
BM_ReadFloats 4173 ms 4172 ms 1 items=8.38861M items_per_second=2.01078M/s
BM_ReadBools 1898 ms 1898 ms 1 items=8.38861M items_per_second=4.4205M/s
An .xlsx file is essentially a bunch of .xml files in a .zip archive. Internally, OpenXLSX uses the miniz library to compress/decompress the .zip archive, and it turns out that miniz has an upper limit regarding the file sizes it can handle.
The maximum allowable file size for a file in an archive (i.e. en entry in a .zip archive, not the archive itself) is 4 GB (uncompressed). Usually, the largest file in an .xlsx file/archive, will be the .xml files holding the worksheet data. I.e., the worksheet data may not exceed 4 GB. What that translates to in terms of rows and columns depend a lot on the type of data, but 1,048,576 rows x 128 columns filled with 4-digit integers will take up approx. 4 GB. The size of the compressed archive also depends on the data held in the worksheet, as well as the compression algorithm used, but a workbook with a single worksheet of 4 GB will usually have a compressed size of 300-350 MB.
The 4 GB limitation is only related to a single entry in an archive, not the total archive size. That means that if an archive holds multiple entries with a size of 4GB, miniz can still handle it. For OpenXLSX, this means that a workbook with several large worksheets can still be opened.
OpenXLSX uses the PugiXML library for parsing and manipulating .xml files in .xlsx archive. PugiXML is a DOM parser, which reads the entire .xml document into memory. That makes parsing and manipulation incredibly fast.
However, all choices have consequences, and using a DOM parser can also demand a lot of memory. For small spreadsheets, it shouldn't be a problem, but if you need to manipulate large spreadsheets, you may need a lot of memory.
The table below gives an indication of how many columns of data can be handled by OpenXLSX (assuming 1,048,576 rows):
| Columns | |
|---|---|
| 8 GB RAM | 8-16 |
| 16 GB RAM | 32-64 |
| 32 GB RAM | 128-256 |
Your milage may vary. The performance of OpenXLSX will depend on the type of data in the spreadsheet.
Note also that it is recommended to use OpenXLSX in 64-bit mode. While it can easily be used in 32-bit mode, it can only access 4 GB of RAM, which will severely limit the usefulness when handling large spreadsheets.
If memory consumption is an issue for you, you can build the OpenXLSX library in compact mode (look for the ENABLE_COMPACT_MODE in the CMakeLists.txt file), which will enable PugiXML's compact mode. OpenXLSX will then use less memory, but also run slower. See further details in the PugiXML documentation here. A test case run on Linux VM with 8 GB RAM revealed that OpenXLSX could handle a worksheet with 1,048,576 rows x 32 columns in compact mode, versus 1,048,576 rows x 16 columns in default mode.
By far the most questions I get about OpenXLSX on Github, is related to Unicode. It is apparently (and understandably) a source of great confusion for many people.
Early on, I decided that OpenXLSX should focus on the Excel part, and not be a text encoding/conversion utility also. Therefore, all text input/output to OpenXLSX MUST be in UTF-8 encoding... Otherwise it won't work as expected. It may also be necessary that the source code files are saved in UTF-8 format. If, for example, a source file is saved in UTF-16 format, then any string literals will also be in UTF-16. So if you have any hard-coded string literals in your source code, then the source file must also be saved in UTF-8 format.
All string manipulations and usage in OpenXLSX uses the C++ std::string, which is encoding agnostic, but can easily be used for UTF-8 encoding. Also, Excel uses UTF-8 encoding internally (actually, it might be possible to use other encodings, but I'm not sure about that).
For the above reason, if you work with other text encodings, you have to convert to/from UTF-8 yourself. There are a number of options (e.g. Boost.Nowide or Boost.Text). Internally, OpenXLSX uses Boost.Nowide; it has a number of handy features for opening files and converting between std::string and std::wstring etc. I will also suggest that you watch James McNellis' presentation at CppCon 2014, and read Joel Spolsky's blog.
Unicode on Windows is particularly challenging. While UTF-8 is well supported on Linux and MacOS, support on Windows is more limited. For example, output of non-ASCII characters (e.g. Chinese or Japanese characters) to the terminal window will look like gibberish. As mentioned, sometimes you also have to be mindful of the text encoding of the source files themselves. Some users have had problems with OpenXLSX crashing when opening/creating .xlsx files with non-ASCII filenames, where it turned out that the source code for the test program was in a non-UTF-8 encoding, and hence the input string to OpenXLSX was also non-UTF-8. To stay sane, I recommend that source code files are always in UTF-8 files; all IDE's I know of can handle source code files in UTF-8 encoding. Welcome to the wonderful world of unicode on Windows 🤮
An Excel-file is essentially just a bunch of .xml files wrapped in a .zip archive. OpenXLSX uses a 3rd party library to extract the .xml files from the .zip archive. The default library used by OpenXLSX is Zippy, which is an object-oriented wrapper around miniz. The miniz library is fast, and is header-only, which is ideal for OpenXLSX.
However, it is possible to use a different zip-library, if you want to. In rare cases, you may experience stability issues with miniz. In those cases, it may be useful to try a different zip-library.
Using the Zippy/miniz library requires no special efforts; it will work straight out of the box. Using a different zip-library, however, will require some work.
In order to use a different zip-library, you must create a wrapper class that conforms to the interface specified by the IZipArchive class. Note that this is implemented using type erasure, meaning that no inheritance is required; the class just needs to have a conforming interface, thats all. After that, provide an object of the class and supply it to the OpenXLSX constructor.
To see an example of how this is done, take a look at Demo1A in the Examples folder. This example uses a class called CustomZip (using libzip as the zip library) which can be found under Examples/external/CustomZip. In order to build the example program, make sure that libzip (and its dependencies) is installed on your computer, and enable the OPENXLSX_ENABLE_LIBZIP_EXAMPLE option in the CMakeLists.txt file in the OpenXLSX root.
As mentioned, the Demo1A example program uses libzip. libzip is a very stable library and widely used. However, my experience is that it is quite slow for large zip files, such as large spreadsheets. For that reason, libzip may not be the ideal solution, but it is useful for showing how a different zip library can be used.
In the 'Examples' folder, you will find several example programs, that illustrates how to use OpenXLSX. Studying those example programs is the best way to learn how to use OpenXLSX. The example programs are annotated, so it should be relatively easy to understand what's going on.
OpenXLSX now pulls in dependencies either from the operating system (if installed) or directly from the upstream source repositories.
OpenXLSX can now use other zip libraries than the default Zippy/miniz library. See Demo1A as an example of how it's done
This version includes row ranges and iterators. It also support assignment of containers of cell values to XLRow objects. This is significantly faster (up to x2) than using cell ranges or accessing cells by cell references.
The internal architecture of OpenXLSX has been significantly re-designed since the previous version. The reason is that the library was turning into a big ball of mud, and it was increasingly difficult to add features and fix bugs. With the new architecture, it will (hopefully) be easier to manage and to add new features.
Due to the re-design of the architecture, there are a few changes to the public interface. These changes, however, are not significant, and it should be easy to update:
I realise that these changes may cause problems for some users. Because of that, the previous version of OpenXLSX can be found in the "legacy" branch of this repository. However, I strongly recommend that you transition to the new version instead.
XLZipArchive.hpp provides two new functions const char *OpenXLSX::ZipLibraryName() and const char *OpenXLSX::ZipLibraryVersion() for the user to obtain info about the zip library in use. NOTE: These do not reflect information about a custom zip implementation such as used in Demo1A.cppOpenXLSX and dependencies are installed into /usr/local/lib/OpenXLSX subfolder to avoid version conflicts for parallel installations of zip library (miniz or libzip), pugixml, nowidepugixml and libzip package config (.pc) files are now part of the installation (miniz package config was already installed before if needed)pugixml-OpenXLSX.pc, libzip-OpenXLSX.pc, miniz-OpenXLSX.pc respectively to avoid conflicts/usr/local/lib/OpenXLSX0.5.0XLWorksheet::range() to prevent an exception raised from XLCellReference constructorcmake/get-git-HEAD-ID.cmake and cmake/libopenxlsxCPackOptions.cmake.inCMakeLists.txt: CPack configuration is generated and can be invoked with cpack -G DEB - CAUTION: the debian package will most likely not function at this stage due to missing dependenciesOPENXLSX_ENABLE_LIBZIP=ON now works with OPENXLSX_CPM_LOCAL_PACKAGES_ONLY=OFF - pending confirmation of a test on WindowsXLRowReverseIterator (XLRow.hpp)XLRowRange::rbegin() and XLRowRange::rend() to reverse-iterate over a row rangeXLReverseRange (XLIterator.hpp) to reverse a range of class T that exposes T::rbegin() and T::rend() and typedef T::reverse_iteratorXLReverseRange, range-based reverse iteration is demonstrated in Examples/Demo6.cpp, Example usage: for (auto& row : XLReverseRange(wks.rows(firstRow, lastRow)))pugixml headers from the library interfacepkg-config files that can be used as demonstrated in the new Scripts/compile.shOPENXLSX_BUNDLED_STATIC_LIB will now create libOpenXLSX-bundled.a library file that is not installed, but can be linked against while including all dependencies (only works with BUILD_SHARED_LIBS=OFF, and OPENXLSX_CPM_LOCAL_PACKAGES_ONLY=OFF or all dependencies available as static libraries on the build system). This uses the newly added OpenXLSX/bundle_static_library.cmake (under MIT License, Copyright (c) 2019 Cristian Adam).Makefile.GNU, but until full support for options is back, this Makefile is overriding some options to the only supported configurationsexternal source code from repository, refined cmake configurationMakefile.GNU is currently non-functional!OPENXLSX_CPM_LOCAL_PACKAGES_ONLY):
find_package for LibZip and PugiXMLOpenXLSX/CMakeLists.txt: added find_package for LibZip and PugiXML. Unfortunately, for LibZip, this generates an error unless the unneeded components zipcmp, zipmerge & ziptool are also installed on the system. TBD how to ignore those missing.nowide installed on the operating systemOPENXLSX_FORCE_NOWIDE - set to ON to use force the use of nowide even on non-Windows systems (this flag is for testing purposes)OPENXLSX_ENABLE_LIBBOOST_NOWIDE - set to ON to use nowide from an installed libboostboost nowide (include path starts with boost/ and namespace is boost::nowide vs. nowide)#include <memory> in XLZipArchive.hpp, #include <stdexcept> in detail/LibZip.hppDemo1A to Makefile.GNUnowide status to Demo4OpenXLSXFileSystemTools, cleaned up cmake and GNU make optionsExamples/CMakeLists.txt for Demo4 (to be tested): correctly add external/nowide to the include pathExamples/CMakeLists.txt for Demo1A (to be tested): correctly add external/nowide to the include pathDemo1A CustomZip implementation to fit the modified IZipArchive conceptOPENXLSX_ENABLE_LIBPUGIXML - set to ON to use an installed libpugixmlOPENXLSX_ENABLE_LIBZIP - set to ON to use an installed libzipOPENXLSX_SHARED_LIBRARY - set to ON for shared library build, OFF builds the static libraryOPENXLSX_SHARED_LIBRARYlibpugixml installed on the operating systemXLXmlParser from public OpenXLSX API - this should address conflicts with pugixml.hpp headers available elsewherelibpugixml - for cmake, variable is OPENXLSX_ENABLE_LIBPUGIXML, in Makefile.GNU, variable is USE_LIBPUGIXML - set to yes if system installed library shall be useddetail/OpenXLSXFileSystemTools.hpp now comprises all functions where unicode (filename) support might be relevant, to be implemented centrally - currently on the To-Do listXLDocument::create: creating a new document no longer creates a file under that name until an explicit call of XLDocument::save or ::saveAs. This is to remove a dependency of XLDocument on boost::nowide on Windows.OpenXLSX/headers/detail/: new headers LipZip.hpp (libzip wrapper) and Zippy.hpp (miniz wrapper)CMakeLists.txt: Option OPENXLSX_ENABLE_LIBZIP activates libzip use, disabling the option defaults to the miniz / Zippy wrapperCMakeLists.txt: Option OPENXLSX_ENABLE_LIBZIP_EXAMPLE replaces the prior use of OPENXLSX_ENABLE_LIBZIP for Demo1Aunzip complains about the flag mismatch. This issue is on my to-to list.bool XLDocument::validateSheetName(std::string sheetName, bool throwOnInvalid = false) - can be called by the user to test whether a name would throwXLSheet::setName, XLWorkbook.addWorksheet or XLWorkbook.cloneSheet are invoked with a name for which validateSheetName would return false, an XLInputError is thrown with the validation rule that was violated.CAUTION: this change is potentially code-breaking as it can throw an exception on code that previously executed without errors - However, when it throws, previous versions would have produced a workbook that Excel refuses to read.
OPENXLSX_ENABLE_LTO that permits disabling link-time optimization altogether. It remains ON by default.XLMergeCells is now constructed with the worksheet root XML node (unfortunately necessary) and will use this access to create/delete the node as necessary, this addresses https://github.com/troldal/OpenXLSX/issues/351XLMergeCells::deleteAll to clear all merges in the worksheetXLMergeIndex as the parameter / return type for all functions using a merge index - the underlying int32_t remains unchangedconstexpr const XLMergeIndex XLMergeNotFound = -1 for code readabilityXLFont::underline, ::scheme, ::vertAlign: fix default value to set for attribute val when tag doesn't existXLFont::setUnderline: return correct "none" value for XLUnderlineNone from XLUnderlineStyleToString (was returning empty string)getBoolAttributeWhenOmittedMeansTrue to XLUtilitiesXLStyles XLFont: changed bool getter functions to return true when tag exists, but attribute val is omitted, to be in line with OOXML spec. This addresses https://github.com/troldal/OpenXLSX/issues/347. Affected getters: bold(), italic(), strikethrough(), outline(), shadow(), condense(), extend()XLSheet::findCell that allow to try and fetch a cell without creating the row/cell XML (like the non-creating XLCellIterator). This function complements XLSheet::cell (which always creates the XML cell node and returns a valid object)findCell, the returned XLCellAssignable::empty() method must be checked to ensure success before accessing any cell propertiesXLSheet::findCell provides a solution to https://github.com/troldal/OpenXLSX/issues/333, a demonstration of this solution has been added to Demo1.cppXLFormula to an empty (zero-length) string will now delete the formula XML node from the cell without further actionsCMakeLists.txt in Examples/external/nowide/* to have cmake_minimum_required VERSION 3.15XLSheet.cppXLSheet.hpp clarifying that sheet index is 1-based#include <cctype> to XLSheet.cpp and XLDrawing.cppSTAT, STATSTRUCT) to link to the platform specific implementation of stat without naming conflictsBefore I start working on the next items on my to-do list (tables/filters, hyperlink support), I am merging all recent patches into master. I have not yet had much feedback on whether the changes work with MS Office, but I am confident that if you discover any issues, I can fix them quickly.
Should you experience stability issues, please revert to commit https://github.com/troldal/OpenXLSX/commit/4ed9c97ad613526bf1544296acd24639dcbe2846 and submit a bug report.
New features
XLComments -> see Demo1.cppXLRowIterator no longer creates the XML for rows that do not exist until the iterator is dereferencedXLDocument::cleanupSharedStrings() can now be called manually to rewrite the shared strings cache (and remove all strings that are no longer referenced from any cell)XLDocument now has a member function void cleanupSharedStrings() that will reindex shared strings for the complete workbook and remove all shared strings that are no longer referenced anywhere, or that have been set to the empty string. This addresses https://github.com/troldal/OpenXLSX/issues/193.XLRowIterator: can now iterate over a range of rows and test bool XLRowIterator::rowExists() before accessing it. This allows to skip non-existing rows without creating them. Functionality is analogous to XLCellIterator and bool XLCellIterator::cellExists()XLWorksheet::range(..) will no longer create all missing rows in the rangeXLCellValueProxy two functions to manipulate shared string indexes directly, bypassing XLSharedStrings:
int32_t stringIndex() constbool setStringIndex(int32_t newIndex)XLSharedStrings:
int32_t stringCount() const - returns the amount of strings currently in the shared strings cacheint32_t rewriteXmlFromCache() - called from XLDocument::cleanupSharedStrings - triggers a full wipe of the shared strings XML & re-creation from the string cache. Returns the number of shared strings written to XMLXLRowIterator:
bool rowExists() - test whether the XLRowIterator currently points to a row that already exists in the XMLbool endReached() - equivalent to (XLRowIterator) it == (XLRowRange) range.end()uint32_t rowNumber() const - return the current row that the iterator is pointing to (m_lastRow + 1 if endReached() == true)XLRow:
bool empty() const returns true if the XLRow instance is not linked to valid XMLexplicit operator bool() const the opposite of empty()XLCellRange.hpp to XLSheet.hppXLContentTypeToString function from XLContentTypes.cpp, as a function XLContentTypeString already exists in utilities/XLUtilities.hppExamples/Demo1.cpp) as they appear in the underlying XML. This is much more practical when searching for comments in a worksheet created by another application.Override entries for the worksheet dependencies (comments, vmlDrawing, table) in [Content Types].xmlThe support for comments is now in a stage where it can be used - please refer to Demo1 line 124ff for a quick "howto". This feature is still in alpha stage, with a few open TBDs:
XLShape XLComments::shape(std::string const& cellRef) - for methods of XLShape please refer to the XLDrawing header file // XLShapeShadow& shadow(); // v:shape subnode v:shadow
// XLShapeFill& fill(); // v:shape subnode v:fill
// XLShapeStroke& stroke(); // v:shape subnode v:stroke
// XLShapePath& path(); // v:shape subnode v:path
// XLShapeTextbox& textbox(); // v:shape subnode v:textbox
Override entries for the worksheet dependencies (comments, vmlDrawing, table)XLKeepCellValue::privateGet as a library internal that can be used with the old behavior for performance reasons, from functions that can guarantee the validity of the XLCellValue for the duration of access to the string referencestd::ostream& operator<<for XLCellValue and XLCellValueProxy now fetch string types as std::string, this addresses https://github.com/troldal/OpenXLSX/issues/166XLCellValue::get<double>() and XLCellValue::get<XLDateTime>(). Note: implicit conversion from string is available in VisitXLCellValueTypeToDouble, but disabled (forced throw)XLCfTypeFromString, XLCfTypeToString, XLCfOperatorFromString, XLCfOperatorToString, XLCfTimePeriodFromString, XLCfTimePeriodToStringXLSheet::isActive and XLSheet::setActive function definitions to ensure bug-free export of symbols to shared library - this addresses https://github.com/troldal/OpenXLSX/issues/316 - please do not ask me why this was never a problem for the static build, I am simply not smart enough to understand that :PBinaryAsHexString, ExcelPasswordHash, ExcelPasswordHashAsString so that they are also exported when the shared library is being builtExcelPasswordHash and ExcelPasswordHashAsString to XLDocument as global utility functionsBinaryAsHexString a global utility function so that XLWorksheet can use them as wellhexDigit and BinaryAsHexString from XLRelationships to XLDocumentbool protectSheet(bool set = true)bool protectObjects(bool set = true)bool protectScenarios(bool set = true)bool allowInsertColumns(bool set = true)bool allowInsertRows(bool set = true)bool allowDeleteColumns(bool set = true)bool allowDeleteRows(bool set = true)bool allowSelectLockedCells(bool set = true)bool allowSelectUnlockedCells(bool set = true)bool denyInsertColumns()bool denyInsertRows()bool denyDeleteColumns()bool denyDeleteRows()bool denySelectLockedCells()bool denySelectUnlockedCells()bool setPasswordHash(std::string hash)bool setPassword(std::string password)bool clearPassword()bool clearSheetProtection()bool sheetProtected()bool objectsProtected()bool scenariosProtected()bool insertColumnsAllowed()bool insertRowsAllowed()bool deleteColumnsAllowed()bool deleteRowsAllowed()bool selectLockedCellsAllowed()bool selectUnlockedCellsAllowed()std::string passwordHash()bool passwordIsSet()std::string XLWorksheet::sheetProtectionSummary() for easy control of established settingsThis is a major patch to address https://github.com/troldal/OpenXLSX/issues/315 - conditional formatting is now implemented in an experimental stage.
XLUnsupportedElement from XLStyles to XLXmlFile header, so that XLWorksheet can use it for conditional formatting functionalitybool isActive_impl() and bool setActive_impl() as no-op function stubs in the hopes this resolves https://github.com/troldal/OpenXLSX/issues/316experimental in this case means:
bool settingExists(std::string settingName)"true" and "false" - whereas LibreOffice appears to store them (for cfRules) as 1 and 0). The reason is: I want to know if this works, and if it does, stay consistent in how OpenXLSX stores boolean values. I may have to modify this as I learn moreaboveAverage="" when for aboveAverage, the documentation defines true as the default - does that mean an empty string gets evaluted as true?XLWorkbook::sharedStrings and XLWorkbook::hasSharedStringsXLDocument::sharedStrings() returns the same, and hasSharedStrings was always returning true anyways.strike(through) font property to address issue #314val is omitted in the <strike> XML tag, the value is now interpreted as true as described in the format specification - previously this was wrongly interpreted as "strikethrough is not set". This addresses issue https://github.com/troldal/OpenXLSX/issues/314XLDeleteProperty == XLInvalidUInt32 == 0xffffffff to delete the theme attribute from XML. This was necessary because even an empty theme="" attribute affects formatting.not node.empty()xl/_rels/workbook.xml.rels should again open without errors for both relative (to xl/ folder) and absolute archive pathsReviewed the XLDateTime code in response to https://github.com/troldal/OpenXLSX/issues/299 and fixed a bug that I think I may have introduced myself. Apologies, dates should now correctly construct from double, struct tm and time_t and convert back to struct tm.
It appears that MS Office does not tolerate any formatting XML nodes prior to the <mergeCells> XML node - in order to get rid of an according error message, the latest commit modifies the XLSheet::merges function to insert a newly created <mergeCells> node directly after the <sheetData> node.
These missing defaults could lead to followup errors when any style index of this cell was later assumed valid to access said style by index (Exception if the index was not in a valid range). All style indexes available in a cell format are now zero-initialized (with no assumptions what the style with index 0 may be configured as, normally it's defaults - if you want to be sure, provide a cell with a known format as copyFrom template to XLCellFormats::create).
XLDocument.hpp: added showWarnings() (default setting) and suppressWarnings()XLStyles.hpp: added suppressWarnings parameter to constructor (default: false)XLDocument::open: if suppressWarnings() was called, suppress warnings about ignored comment xml files and unhandled workbook itemsXLDocument::open: m_suppressWarnings setting is forwarded to XLStyles constructorXLException.hpp: added missing #include <string>XLDocument::open will create a missing workbook relationship in _rels/.rels if, and only if, a workbook with the default path xl/workbook.xml exists in the archiveMerged development branch into the main branch. In summary:
OpenXLSX/headers/XLStyles.hpp: XLStyles class (and lots of subclasses) has been added, providing nearly complete access to all Excel formatting capabilities.OpenXLSX/headers/XLMergeCells.hpp and XLSheet.hpp: XLMergeCells class is made accessible through XLWorksheet in order to create / delete cell mergesExamples/Demo10.cpp demonstrates how styles and merges are used Note: The section that is disabled with testBasics = false will break the resulting Excel Spreadsheet if enabled, the only purpose is to demonstrate access to all new classes and methods. If you want to use them, make sure to use them correctlyNote on XLNumberFormat(s): Contrary to all other XLStyles elements, these do not use an index within the XML as the referrable ID (XLCellFormat::setNumberFormatId), but instead a user-defined ID that can be set via XLNumberFormat::setNumberFormatId - and for an XLCellFormat, can be set to either a self-defined number format ID, or to a format predefined by MS. Generally, for custom formats, it is recommended to use IDs > 100.
XLDocument::create and XLDocument::saveAs function interfaces, but marked them as [[deprecated]]. The new interfaces require explicit specification of XLForceOverwrite or XLDoNotOverwrite. Once the deprecated function definitions can be removed, XLDoNotOverwrite could become the new default behaviorOpenXLSX/external/nowide/nowideDemo0 / kept it in the Makefile as a test vehicleNotes folderScripts folder with xml-format.sh (XML linting, useful to analyze XLSX zip contents in a text editor)make-gnu.sh to Scripts/make-gnu.shScripts/cmake-cleanup.sh to prepare (not execute!) commands that remove all temporary files generated by cmakeScripts/demos-cleanup.sh to remove all xlsx files created by the Demosvoid setSavingDeclaration(XLXmlSavingDeclaration const& savingDeclaration) using class XLXmlSavingDeclaration (defined in XLXmlData.hpp) that can be used to pass a custom XML version, encoding, and standalone property to pugixmlNotes/todo-list.txtXLWorksheet now allows to access an object managing the worksheet's merged cell ranges
XLMergeCells XLWorksheet::merges() - access the XLMergeCells class for the worksheet directlyvoid mergeCells(XLCellRange const& rangeToMerge, bool emptyHiddenCells = false) - merge cells defined by rangeToMergevoid mergeCells(const std::string& rangeReference, bool emptyHiddenCells = false) - merge cells defined by rangeReferencevoid unmergeCells(XLCellRange const& rangeToUnmerge) - unmerge cells defined by rangeToUnmergevoid unmergeCells(const std::string& rangeReference) - unmerge cells defined by rangeReferenceXLMergeCells: added methods
int32_t XLMergeCells::findMerge(const std::string& reference) - find a merge matching reference
* bool mergeExists(const std::string& reference) - test if a merge with reference existsint32_t XLMergeCells::findMergeByCell(const std::string& cellRef) - find a merge containing std::string cellRefint32_t XLMergeCells::findMergeByCell(XLCellReference cellRef) - find a merge containing XLCellReference cellRefsize_t count() - get count of merges defined in the worksheetconst char* merge(int32_t index) - get merge reference string at indexconst char* operator[](int32_t index) - overload of operator[] as a shortcut to ::mergeint32_t appendMerge(const std::string& reference) - define a new merge, invoked by XLWorksheet::mergeCellsvoid deleteMerge(int32_t index) - delete merge with the given index from the worksheet (= unmerge cells), invoked by XLWorksheet::unmergeCellsadded example usage of this functionality to Demo10.cpp
XLDocument::open will now ignore unknown subfolders (they remain unmodified and unaccessible in the zip in memory and stay in the archive upon saving). This prevents throwing an exception for any XLSX file written by a "creative" application that added items unknown to this libraryconstexpr from const unsigned int pugi_parse_settings and moved it to XLDocument.hpp so that the const becomes available to XLStyles and XLSharedStringsXLStyles class - interface can be found in OpenXLSX/headers/XLStyles.hppExamples/Demo10.cpp demonstrates use of the new XLStyles & cell merging functionalityXLCellIterator: can now iterate over a range and test XLCellIterator::cellExists before accessing it. This allows to skip non-existing cells without creating them.workbook##.xml, XML namespaces and random 64bit (relationship) identifiers
xl/workbook.xml) workbook XML name is now accepted if it is correctly referenced in _rels/.relsbool OpenXLSX::enable_xml_namespaces() must be used to enable namespace support before opening a document using e.g. a namespace x (like so: <x:row r="1">) everywhere
insert_child_before("x:row", curRow ) in the <y:sheetData> node will strip the x: and insert a row element named <y:row>, using the parent node's namespaceOpenXLSX/headers/XLXmlParser.hpp) take as an optional last argument a bool force_ns that - if true - will respect a namespace passed into the function for node creation / access. A helper const bool OpenXLSX::XLForceNamespace = true is available for code readability
XMLNode::insert_child_before("x:row", curRow, XLForceNamespace) in the <y:sheetData> node like above, will insert a row element named x:rowid="rId##" where ## is the sequence number, and when a new component is added to the workbook, a new relationship ID is determined by taking the highest existing value within the workbook, and adding +1 to it. During investigation of [https://github.com/troldal/OpenXLSX/issues/254] a workbook was found to use (seemingly) random 64 bit integers, stored in the form r:id="Rxx", with xx being a hexadecimal representation of a 64 bit integer.
OpenXLSX::UseRandomIDs() must be invoked to switch ID functionality before opening such a documentOpenXLSX::UseSequentialIDs() can be used to restore default (sequential) relationship ID functionalityNOTE on enable_xml_namespaces: Namespace support is transparent and can be used with documents that do not use such namespaces. However, it can have a small (<5%) performance impact on large workbooks and is therefore optional to enable.
CAUTION with UseRandomIDs: Please be aware that a mixed mode, where one document is opened with random ID support and another without sequential relationship IDs, is not supported for the time being. If you have to work with documents of different types, you should always configure the desired relationship ID behavior for the next document, work with that, close it, and change the relationship ID configuration before opening the next document.
Please disregard Examples/Demo0.cpp and Examples/Demo9.cpp for now (Demo0 is trivial and was used to test non-standard workbook support, and Demo9 requires a review with better comments). Demo9 showcases how to use the new XLCellAssignable to copy-assign cell contents (like Excel copy & paste).
XLCellIterator no longer creates empty cells just for iterating over them, and provides ::cellExists() to test if the currently pointed-to cell is already in the worksheet XML, before accessing itXLStyles supportXLWorksheet now provides XLMergeCells support for merging / unmerging cell rangesDemo10.cpp has a lot of examples on how to use the new XLStyles functionalitycustomXml etc in the xlsx archiveXLProperties.cpp XLAppProperties to create <TitlesOfParts> and <HeadingPairs> nodes (and subnodes) if missing, added method alignWorksheets, called by XLDocument::open to ensure that all worksheets listed in the workbook xml are also accounted for in docProps/app.xml.XLProperties.cpp prettyInsertXmlNodeBefore, maybe this can eventually become a global function, paired with a TBW function prettyInsertXmlNodeAfter, and could be used by all classes, cleaning up the code for whitespace support substantially.XLProperties.cpp for <HeadingPairs> subnodes: pairCount -> pairValueParent, pairCountValue -> pairValueCode refactored in XLDocument::open to read the shared strings table while consistently ignoring phonetic tags, which were previously only ignored if the very first child of an <si> tag was a phonetic tag. Will now be ignored anywhere before, after or in between text <t> and rich text <r> tags.
Included a "dumb" fallback solution in XLRelationships.cpp GetTypeFromString to support previously unknown relationship domains, e.g. type="http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet". Altered behavior will initially test against the hardcoded relationship domains, and if that test fails to identify a relationship type string, the type string will be searched for an occurrence of /relationships/ and if that substring is found, the type detection fallback will try to evaluate the relationship type based on the substring starting with /relationships/, ignoring the domain. For the above example, that would result in a test of typeString.substr( comparePos ) == "/relationships/worksheet", where comparePos == 41 (the position at which substring /relationships/ begins).
In anticipation of a potential future need for a similar "dumb" fallback solution, repeating hardcoded strings in XLContentTypes.cpp GetTypeFromString were also replaced with string constants.
Updated .gitignore to a more generic version that excludes everything and explicitly re-includes all desired files.
Closed a multitude of pull requests that had been implemented in the May 2024 Update, implemented two more editorials from PR #246 and #253.
BinaryAsHexString: replaced char array with std::string, as ISO C++ standard does not permit variable size arraysRand64: added explicit type cast, as bitwise shift-left does not do integer promotion to long on the left operand-Wpedantic -Wextra and removed all previously disabled flags after below patchesf( param ) -> f(param), a[ index ] -> a[index] and if( condition ) -> if (condition))warning: enumerated and non-enumerated type in conditional expression [-Wextra]void ZipArchive::Save(std::ostream& stream)void ZipArchive::ExtractDir(const std::string& dir, const std::string& dest)void ZipArchive::ExtractAll(const std::string& dest)-Wunused-function by pragma for functions fileExists and isDirectoryuint32_t (was uint64_t). CAUTION: there is no validity check on the underlying XML (nor was there ever one in case a value was inconsistent with OpenXLSX::MAX_ROWS)-Wsign-compare
bool endReached() to eliminate -Wignored-qualifiers (ignored because const on trivial return types accomplishes nothing)OpenXLSX::ignore template, can be used to suppress -Wunused-parameter and -Wunused-variable like so: OpenXLSX::ignore(unusedValue)
-Wunused-parameter#pragma warning lines in another pragma to disable -Wunknown-pragmas (on gcc/g++)
#pragma GCC diagnostic push#pragma GCC diagnostic ignored "-Wunknown-pragmas" // disable warning about below #pragma warning being unknown# pragma /* offending lines go here */#pragma GCC diagnostic popzippy.hppIZipArchive.hppXLCell.hppXLCellIterator.hppXLCellRange.hppXLCellReference.hppXLCellValue.hppXLColor.hppXLColumn.hppXLCommandQuery.hppXLContentTypes.hppXLDateTime.hppXLDocument.hppXLException.hppXLFormula.hppXLMergeCells.hppXLProperties.hppXLRelationships.hppXLRowData.hppXLRow.hppXLSharedStrings.hppXLSheet.hppXLStyles.hppXLWorkbook.hppXLXmlData.hppXLXmlFile.hppXLZipArchive.hppExamples/Demo5.cpp<Properties> (document) element, was previously wrongly appended to headingPairs/xl/worksheets/sheet*, /xl/sharedStrings.xml, /xl/styles.xml, /xl/theme/theme*) and otherwise ignored. This fixes an issue when the workbook contains /xl/pivotCache/ and /xl/pivotTables/ entries until support for those is implemented (if ever ;P)<cols> element obtained via a rowNode parent's parentstd::vector< XLStyleIndex > m_columnStyles, and a method fetchColumnStyles that will populate the vector so that it can be passed to the XLCellIterator constructor
XLCellIterator::cellExists() without creating the XML for the cell.<font><scheme val="major"/></font>)<font><vertAlign val="subscript"/></font>)<fills><fill><gradientFill>...</gradientFill></fill>...</fills> are now supportedPlease refer to Demo10 and XLStyles.hpp on how to set cell formatting. In short:
529 followers · starred Jan 2026
82 followers · starred Jan 2022
698 followers · starred Apr 2024
68 followers · starred Aug 2022
A C++ library for reading, writing, creating and modifying Microsoft Excel® (.xlsx) files.
C++
1,789
918 commits
updated Jun 15, 2026
OpenXLSX is a C++ library for reading, writing, creating and modifying Microsoft Excel® files, with the .xlsx format.
NOTE: With today's release v0.5.1, this repository is discontinued on github. It has been migrated to Codeberg, and will eventually be moved to @troldal's Codeberg.
Please do not open any more issues or pull requests on github, and instead submit your feature requests directly on Codeberg.
After creating an account on codeberg.org, you will be able to "own" and edit issues and comments previously created by you by linking your github account to codeberg via "Sign in with Github", direct link here.
This version, with updates from 2026-06-13, is the latest release.
Note: generally, for features awaiting implementation, refer to the open issues in the repository
BUILD_SHARED_LIBS functionality in Makefile.GNUMakefile.GNU, check for available dependencies and error out if any are missingFor the latest functionality updates, please refer to the development branch. Feel free to have a look. This way you don't have to wait until the main repository is updated.
0.5.1 - git tag will be updated in one of the next commitsOPENXLSX_MONOLITHIC_LIBRARY requires static, BUILD_SHARED_LIBS requires shared dependencies) and triggering (if enabled) automatic download from upstream if the required dependency is not availablevoid XLWorksheet::setDimension functions to set it, with auto-calculation of last cell, if desired. This addresses issue 361. Supported function overloads:void XLWorksheet::setDimension(XLCellReference topLeft, XLCellReference bottomRight, bool autoCalculateLastCell);
void XLWorksheet::setDimension(std::string topLeft, std::string bottomRight);
void XLWorksheet::setDimension(std::string dimension);
-DOPENXLSX_MONOLITHIC_LIBRARY=ON - this requires static dependencies and only works with miniz, fails with libzip (or rather: the libzip (sub-)dependencies will not be linked into the resulting bundled library)OpenXLSXFileSystemTools.hpp pathExists), nowide::stat is now used when nowide is in use. This should make calls to XLDocument::create and XLDocument::saveAs behave well with filenames containing unicode charactersOpenXLSXFileSystemTools fileSize to wrap call to stat with nowide compatibility - this is used in LibZip.hpp loadArchiveDataChange history is found in the detailed change log.
After a long period of inactivity, I have decided to resume development of OpenXLSX. The code has been cleaned up and a significant number of bugs have been fixed. The library has been tested on Windows, macOS and Linux, and should work on all platforms.
I would like to extend my sincere thanks to all the people who have contributed to the project, either by reporting bugs, suggesting features or by submitting pull requests. I would also like to thank all the people who have starred the project, and who have shown interest in the project.
In particular, I would like to thank Lars Uffmann (https://codeberg.org/lars_uffmann/) for his contributions to the project. Lars has spent significant time and effort in cleaning up the code, fixing bugs and implementing new features. Without his help, the project would not have been in the state it is today.
Many programming languages have the ability to modify Excel files, either natively or in the form of open source libraries. This includes Python, Java and C#. For C++, however, things are more scattered. While there are some libraries, they are generally less mature and have a smaller feature set than for other languages.
Because there are no open source library that fully fitted my needs, I decided to develop the OpenXLSX library.
The ambition is that OpenXLSX should be able to read, write, create and modify Excel files (data as well as formatting), and do so with as few dependencies as possible. Currently, OpenXLSX depends on the following 3rd party libraries:
-DOPENXLSX_ENABLE_LIBZIP=ONAs of version 0.5.0, these libraries are no longer included in the repository, and there are three ways to build OpenXLSX against them:
find_packagegitAlso, focus has been put on speed, not memory usage (although there are options for reducing the memory usage, at the cost of speed; more on that later).
OpenXLSX has been tested on the following platforms/compilers. Note that a '-' doesn't mean that OpenXLSX doesn't work; it just means that it hasn't been tested:
| GCC | Clang | MSVC | |
|---|---|---|---|
| Windows | MinGW | MinGW | + |
| Cygwin | - | - | N/A |
| MacOS | + | + | N/A |
| Linux | + | + | N/A |
The following compiler versions should be able to compile OpenXLSX without errors:
Clang 7 should be able to compile OpenXLSX, but apparently there is a bug in the implementation of std::variant, which causes compiler errors.
Visual Studio 2017 should also work, but hasn't been tested.
OpenXLSX uses CMake as the build system (or build system generator, to be exact) and git to pull in dependencies. Therefore, you must install CMake first, in order to build OpenXLSX. You can find (bad) installation instructions on www.cmake.org. If you wish the cmake to automatically fetch missing dependencies, you also need to install git.
Here is a summary to get a working configuration of cmake + git.
cmake & git on debian-based Linux distributionssudo apt update
sudo apt install build-essential cmake git
cmake & git on Windows 10/11 (for now only tested with MSYS Makefiles)Install MSYS2:
In a Powershell (run as Administrator): run winget install --id MSYS2.MSYS2 -e
→ After performing this step, the "MSYS2 MSYS shell" and the "MSYS2 MinGW 64-bit shell" should be accessible from the Start Menu
In MSYS2 MSYS shell: run pacman -Syu
The previous instruction might require a close & reopen of the MSYS2 MSYS shell
In MSYS2 MSYS shell: run pacman -Su
Install development toolchain:
In MSYS2 MinGW 64‑bit shell: run pacman -S --needed base-devel mingw-w64-x86_64-toolchain
Install cmake & git in MSYS2 environment:
pacman -S --needed mingw-w64-x86_64-cmake mingw-w64-x86_64-gitpacman -S --needed mingw-w64-x86_64-ninjaVerify installation:
In MSYS2 MinGW 64‑bit shell: verify versions of git, cmake, gcc, g++
git --version; cmake --version; gcc --version; g++ --version
In MSYS2 MinGW 64‑bit shell
git clone https://github.com/troldal/OpenXLSX <destination-folder>
cd <destination-folder>
mkdir build; cd build
Then build with MSYS Gnu make:
cmake .. -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel
Note: As of 2026-03-21, this configuration complains about miniz (if used) being incompatible with cmake versions >3.5; the following command sequence can be used to get rid of the warning:
cmake .. -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build . --parallel
or build with MinGW Gnu make (untested - should provide a working configuration that can be compiled from cmd/Powershell)
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel
or build with ninja (untested)
cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release
ninja
The OpenXLSX library is located in the OpenXLSX subdirectory to this repo. However, the root folder CMakeLists.txt establishes the library configuration and dependencies.
If you use CMake for your own project, you can add the OpenXLSX root folder as a subdirectory to your own project.
Alternatively, you can use CMake to generate make files or project files for a toolchain of your choice. Both methods are described in the following.
By far the easiest way to use OpenXLSX in your own project, is to use CMake yourself, and then add the OpenXLSX root folder as a subdirectory to the source tree of your own project. Several IDE's support CMake projects, most notably Visual Studio 2019, JetBrains CLion, and Qt Creator. If using Visual Studio, you have to specifically select 'CMake project' when creating a new project.
The main benefit of including the OpenXLSX library as a source subfolder, is that there is no need to locate the library and header files specifically; CMake will take care of that for you. Also, the library will be built using the same configuration (Debug, Release etc.) as your project. In particular, this a benefit on Windows, where is it not possible to use Release libraries in a Debug project (and vice versa) when STL objects are being passed through the library interface, as they are in OpenXLSX. When including the OpenXLSX source, this will not be a problem.
By using the add_subdirectory() command in the CMakeLists.txt file for your project, you can get access to the
headers and library files of OpenXLSX. OpenXLSX can generate either a shared library or a static library. By default
it will produce a static library, but you can change that by setting BUILD_SHARED_LIBS to ON. The library is
located in a namespace called OpenXLSX; hence the full name of the library is OpenXLSX::OpenXLSX.
Including OpenXLSX into your project would look like this inside your project's CMakeLists.txt:
# ============================================================================
# Configure OpenXLSX
# ============================================================================
set(OPENXLSX_CREATE_DOCS OFF)
set(OPENXLSX_BUILD_SAMPLES OFF)
set( BUILD_SHARED_LIBS OFF)
add_subdirectory( OpenXLSX )
Then you can use target_link_libraries and target_include_directories like so:
# Configure linkage for myapp
target_link_libraries(myapp PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(myapp PRIVATE ${OpenXLSX_INCLUDES})
For linking against a shared library, you should include the "rpath" into your final applications:
# Ensure configuration of install RPATH for myapp
set_target_properties(myapp PROPERTIES
INSTALL_RPATH_USE_LINK_PATH TRUE
)
The following snippet is a minimum CMakeLists.txt file for your own project, that includes OpenXLSX as a subdirectory. Note that the output location of the binaries are set to a common directory. On Linux and MacOS, this is not really required, but on Windows, this will make your life easier, as you would otherwise have to copy the OpenXLSX shared library file to the location of your executable in order to run.
cmake_minimum_required(VERSION 3.14)
project(myapp
VERSION 1.0.0
LANGUAGES CXX
)
# ============================================================================
# Example app configuration
# ============================================================================
add_executable(myapp myapp.cpp)
# ============================================================================
# Configure OpenXLSX
# ============================================================================
option(BUILD_SHARED_LIBS OFF "can be used to build shared library version of OpenXLSX")
set( OPENXLSX_CREATE_DOCS OFF)
set( OPENXLSX_BUILD_SAMPLES OFF)
add_subdirectory( OpenXLSX )
# Configure linkage for myapp
target_link_libraries(myapp PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(myapp PRIVATE ${OpenXLSX_INCLUDES})
# Ensure configuration of install RPATH for myapp
set_target_properties(myapp PROPERTIES
INSTALL_RPATH_USE_LINK_PATH TRUE
)
# Installation steps for myapp
install(TARGETS myapp
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT Runtime
)
Using the above, you should be able to compile and run the following code, which will generate a new Excel file named 'Spreadsheet.xlsx':
#include <OpenXLSX.hpp>
using namespace OpenXLSX;
int main() {
XLDocument doc;
doc.create("Spreadsheet.xlsx", XLForceOverwrite);
auto wks = doc.workbook().worksheet("Sheet1");
wks.cell("A1").value() = "Hello, OpenXLSX!";
doc.save();
return 0;
}
If you wish to produce the OpenXLSX binaries and include them in your project yourself, it can be done using CMake and a compiler toolchain of your choice.
From the command line, navigate the OpenXLSX subdirectory of the project root, and execute the following commands:
mkdir build
cd build
cmake ..
The last command will configure the project. This will configure the project using the default toolchain. If you
want to specify the toolchain, type cmake -G "<toolchain>" .. with <toolchain> being the toolchain you wish to
use, for example "Unix Makefiles", "Ninja", "Xcode", or "Visual Studio 16 2019". See the CMake documentation for
details.
Finally, you can build the library using the command:
cmake --build . --target OpenXLSX --config Release
You can change the --target and --config arguments to whatever you wish to use.
When built, you can install it using the following command (as superuser / sudo):
cmake --install .
This command will install the library and header files to the default location on your platform (usually /usr/local/ on Linux and MacOS, and C:\Program Files on Windows). You can set a different location using the --prefix argument.
Note that depending on the platform, it may not be possible to install both debug and release libraries. On Linux and MacOS, this is not a big issue, as release libraries can be used for both debug and release executables. Not so for Windows, where the configuration of the library must be the same as for the executable linking to it. For that reason, on Windows, it is much easier to just include the OpenXLSX source folder as a subdirectory to your CMake project; it will save you a lot of headaches.
g++With the most recent updates, the OpenXLSX CMake configuration will also configure (and install) a pkg-config file for libOpenXLSX (and libminiz), to simplify linking a program against OpenXLSX for systems on which pkg-config is available. Invoking pkg-config --cflags will yield the proper include flags, and pkg-config --static --libs will yield the linker instructions for the OpenXLSX library and its dependencies (pugixml and zip library).
The sequence of arguments to the compiler is important:
g++ `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp `pkg-config --static --libs OpenXLSX`
When linking against a shared library, the library runtime search path (rpath) should be included in the command. The OpenXLSX package config file provides the rpath setting via pkg-config --libs, so that the following, simplified line should work:
g++ `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp `pkg-config --libs OpenXLSX`
If this new feature does not work as intended, please try providing the rpath manually:
g++ -Wl,-rpath,/usr/local/lib `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp `pkg-config --libs OpenXLSX`
CAUTION: When attempting static linking while the shared library for OpenXLSX is also installed, the -lOpenXLSX flag returned from pkg-config --static --libs OpenXLSX will fail to link against the static library.
A manual fix like so should work (this is only an example, for libzip configuration, without nowide; see below):
g++ `pkg-config --cflags OpenXLSX` ../Examples/Demo1.cpp -L/usr/local/lib -l:libOpenXLSX.a -L/usr/local/lib/OpenXLSX -l:libpugixml.a -l:libzip.a -lpugixml -lbz2 -llzma -lzstd -lssl -lcrypto -lz
Note that you will have to adjust the linker flags according to your configuration:
-l:libpugixml.a
-l:libminiz.a
-l:libzip.a (which requires -lbz2 -llzma -lzstd -lssl -lcrypto -lz)
-l:libnowide.a
However, the recommended solution for static linking is to not install the shared library (for now - might support different naming in the future).
cmakeBelow is a simple CMakeLists.txt template with all necessary steps to compile & link against an installed version of OpenXLSX.
Steps to test this (assuming OpenXLSX has been installed):
myappCMakeLists.txt template into myapp/myapp/srcDemo1.cpp into myapp/src/myapp/buildmyapp/buildcmake ..make all./myappCMakeLists.txt template:cmake_minimum_required(VERSION 3.14)
project(myapp
VERSION 1.0.0
LANGUAGES CXX
)
# ============================================================================
# Example app configuration
# ============================================================================
add_executable(myapp src/Demo1.cpp)
# Find dependency OpenXLSX
find_package(OpenXLSX CONFIG REQUIRED)
if(OpenXLSX_FOUND)
message( STATUS "FOUND OpenXLSX" )
get_target_property(OpenXLSX_INCLUDES OpenXLSX::OpenXLSX INTERFACE_INCLUDE_DIRECTORIES) # get OpenXLSX include directories
message( STATUS "OpenXLSX_INCLUDES is ${OpenXLSX_INCLUDES}" )
else()
message( FATAL_ERROR "MISSING DEPENDENCY OpenXLSX" )
endif()
# Configure linkage for myapp
target_link_libraries(myapp PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(myapp PRIVATE ${OpenXLSX_INCLUDES})
# Ensure configuration of install RPATH for myapp
set_target_properties(myapp PROPERTIES
INSTALL_RPATH_USE_LINK_PATH TRUE
)
# Installation steps for myapp
install(TARGETS myapp
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT Runtime
)
OpenXLSX is still work in progress. The following is a list of features which have been implemented and should be working properly:
Features related to plots and figures have not been implemented as of yet, and at least plot functionality is not planned to be implemented at all.
It should be noted that creating const XLDocument objects is currently not working!
Note: As of 2026-04-19 this section is severely outdated. It is not sure how well the numbers from ~2024 hold up with recent changes.
The table below is the output from a benchmark (using the Google Benchmark library), which shows that read/write access can be done at a rate of around 4,000,000 cells per second. Floating point numbers are somewhat lower, due to conversion to/from strings in the .xml file.
Run on (16 X 2300 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 256 KiB (x8)
L3 Unified 16384 KiB (x1)
Load Average: 2.46, 2.25, 2.19
---------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
---------------------------------------------------------------------------
BM_WriteStrings 2484 ms 2482 ms 1 items=8.38861M items_per_second=3.37956M/s
BM_WriteIntegers 1949 ms 1949 ms 1 items=8.38861M items_per_second=4.30485M/s
BM_WriteFloats 4720 ms 4719 ms 1 items=8.38861M items_per_second=1.77767M/s
BM_WriteBools 2167 ms 2166 ms 1 items=8.38861M items_per_second=3.87247M/s
BM_ReadStrings 1883 ms 1882 ms 1 items=8.38861M items_per_second=4.45776M/s
BM_ReadIntegers 1641 ms 1641 ms 1 items=8.38861M items_per_second=5.11252M/s
BM_ReadFloats 4173 ms 4172 ms 1 items=8.38861M items_per_second=2.01078M/s
BM_ReadBools 1898 ms 1898 ms 1 items=8.38861M items_per_second=4.4205M/s
An .xlsx file is essentially a bunch of .xml files in a .zip archive. Internally, OpenXLSX uses the miniz library to compress/decompress the .zip archive, and it turns out that miniz has an upper limit regarding the file sizes it can handle.
The maximum allowable file size for a file in an archive (i.e. en entry in a .zip archive, not the archive itself) is 4 GB (uncompressed). Usually, the largest file in an .xlsx file/archive, will be the .xml files holding the worksheet data. I.e., the worksheet data may not exceed 4 GB. What that translates to in terms of rows and columns depend a lot on the type of data, but 1,048,576 rows x 128 columns filled with 4-digit integers will take up approx. 4 GB. The size of the compressed archive also depends on the data held in the worksheet, as well as the compression algorithm used, but a workbook with a single worksheet of 4 GB will usually have a compressed size of 300-350 MB.
The 4 GB limitation is only related to a single entry in an archive, not the total archive size. That means that if an archive holds multiple entries with a size of 4GB, miniz can still handle it. For OpenXLSX, this means that a workbook with several large worksheets can still be opened.
OpenXLSX uses the PugiXML library for parsing and manipulating .xml files in .xlsx archive. PugiXML is a DOM parser, which reads the entire .xml document into memory. That makes parsing and manipulation incredibly fast.
However, all choices have consequences, and using a DOM parser can also demand a lot of memory. For small spreadsheets, it shouldn't be a problem, but if you need to manipulate large spreadsheets, you may need a lot of memory.
The table below gives an indication of how many columns of data can be handled by OpenXLSX (assuming 1,048,576 rows):
| Columns | |
|---|---|
| 8 GB RAM | 8-16 |
| 16 GB RAM | 32-64 |
| 32 GB RAM | 128-256 |
Your milage may vary. The performance of OpenXLSX will depend on the type of data in the spreadsheet.
Note also that it is recommended to use OpenXLSX in 64-bit mode. While it can easily be used in 32-bit mode, it can only access 4 GB of RAM, which will severely limit the usefulness when handling large spreadsheets.
If memory consumption is an issue for you, you can build the OpenXLSX library in compact mode (look for the ENABLE_COMPACT_MODE in the CMakeLists.txt file), which will enable PugiXML's compact mode. OpenXLSX will then use less memory, but also run slower. See further details in the PugiXML documentation here. A test case run on Linux VM with 8 GB RAM revealed that OpenXLSX could handle a worksheet with 1,048,576 rows x 32 columns in compact mode, versus 1,048,576 rows x 16 columns in default mode.
By far the most questions I get about OpenXLSX on Github, is related to Unicode. It is apparently (and understandably) a source of great confusion for many people.
Early on, I decided that OpenXLSX should focus on the Excel part, and not be a text encoding/conversion utility also. Therefore, all text input/output to OpenXLSX MUST be in UTF-8 encoding... Otherwise it won't work as expected. It may also be necessary that the source code files are saved in UTF-8 format. If, for example, a source file is saved in UTF-16 format, then any string literals will also be in UTF-16. So if you have any hard-coded string literals in your source code, then the source file must also be saved in UTF-8 format.
All string manipulations and usage in OpenXLSX uses the C++ std::string, which is encoding agnostic, but can easily be used for UTF-8 encoding. Also, Excel uses UTF-8 encoding internally (actually, it might be possible to use other encodings, but I'm not sure about that).
For the above reason, if you work with other text encodings, you have to convert to/from UTF-8 yourself. There are a number of options (e.g. Boost.Nowide or Boost.Text). Internally, OpenXLSX uses Boost.Nowide; it has a number of handy features for opening files and converting between std::string and std::wstring etc. I will also suggest that you watch James McNellis' presentation at CppCon 2014, and read Joel Spolsky's blog.
Unicode on Windows is particularly challenging. While UTF-8 is well supported on Linux and MacOS, support on Windows is more limited. For example, output of non-ASCII characters (e.g. Chinese or Japanese characters) to the terminal window will look like gibberish. As mentioned, sometimes you also have to be mindful of the text encoding of the source files themselves. Some users have had problems with OpenXLSX crashing when opening/creating .xlsx files with non-ASCII filenames, where it turned out that the source code for the test program was in a non-UTF-8 encoding, and hence the input string to OpenXLSX was also non-UTF-8. To stay sane, I recommend that source code files are always in UTF-8 files; all IDE's I know of can handle source code files in UTF-8 encoding. Welcome to the wonderful world of unicode on Windows 🤮
An Excel-file is essentially just a bunch of .xml files wrapped in a .zip archive. OpenXLSX uses a 3rd party library to extract the .xml files from the .zip archive. The default library used by OpenXLSX is Zippy, which is an object-oriented wrapper around miniz. The miniz library is fast, and is header-only, which is ideal for OpenXLSX.
However, it is possible to use a different zip-library, if you want to. In rare cases, you may experience stability issues with miniz. In those cases, it may be useful to try a different zip-library.
Using the Zippy/miniz library requires no special efforts; it will work straight out of the box. Using a different zip-library, however, will require some work.
In order to use a different zip-library, you must create a wrapper class that conforms to the interface specified by the IZipArchive class. Note that this is implemented using type erasure, meaning that no inheritance is required; the class just needs to have a conforming interface, thats all. After that, provide an object of the class and supply it to the OpenXLSX constructor.
To see an example of how this is done, take a look at Demo1A in the Examples folder. This example uses a class called CustomZip (using libzip as the zip library) which can be found under Examples/external/CustomZip. In order to build the example program, make sure that libzip (and its dependencies) is installed on your computer, and enable the OPENXLSX_ENABLE_LIBZIP_EXAMPLE option in the CMakeLists.txt file in the OpenXLSX root.
As mentioned, the Demo1A example program uses libzip. libzip is a very stable library and widely used. However, my experience is that it is quite slow for large zip files, such as large spreadsheets. For that reason, libzip may not be the ideal solution, but it is useful for showing how a different zip library can be used.
In the 'Examples' folder, you will find several example programs, that illustrates how to use OpenXLSX. Studying those example programs is the best way to learn how to use OpenXLSX. The example programs are annotated, so it should be relatively easy to understand what's going on.
OpenXLSX now pulls in dependencies either from the operating system (if installed) or directly from the upstream source repositories.
OpenXLSX can now use other zip libraries than the default Zippy/miniz library. See Demo1A as an example of how it's done
This version includes row ranges and iterators. It also support assignment of containers of cell values to XLRow objects. This is significantly faster (up to x2) than using cell ranges or accessing cells by cell references.
The internal architecture of OpenXLSX has been significantly re-designed since the previous version. The reason is that the library was turning into a big ball of mud, and it was increasingly difficult to add features and fix bugs. With the new architecture, it will (hopefully) be easier to manage and to add new features.
Due to the re-design of the architecture, there are a few changes to the public interface. These changes, however, are not significant, and it should be easy to update:
I realise that these changes may cause problems for some users. Because of that, the previous version of OpenXLSX can be found in the "legacy" branch of this repository. However, I strongly recommend that you transition to the new version instead.
XLZipArchive.hpp provides two new functions const char *OpenXLSX::ZipLibraryName() and const char *OpenXLSX::ZipLibraryVersion() for the user to obtain info about the zip library in use. NOTE: These do not reflect information about a custom zip implementation such as used in Demo1A.cppOpenXLSX and dependencies are installed into /usr/local/lib/OpenXLSX subfolder to avoid version conflicts for parallel installations of zip library (miniz or libzip), pugixml, nowidepugixml and libzip package config (.pc) files are now part of the installation (miniz package config was already installed before if needed)pugixml-OpenXLSX.pc, libzip-OpenXLSX.pc, miniz-OpenXLSX.pc respectively to avoid conflicts/usr/local/lib/OpenXLSX0.5.0XLWorksheet::range() to prevent an exception raised from XLCellReference constructorcmake/get-git-HEAD-ID.cmake and cmake/libopenxlsxCPackOptions.cmake.inCMakeLists.txt: CPack configuration is generated and can be invoked with cpack -G DEB - CAUTION: the debian package will most likely not function at this stage due to missing dependenciesOPENXLSX_ENABLE_LIBZIP=ON now works with OPENXLSX_CPM_LOCAL_PACKAGES_ONLY=OFF - pending confirmation of a test on WindowsXLRowReverseIterator (XLRow.hpp)XLRowRange::rbegin() and XLRowRange::rend() to reverse-iterate over a row rangeXLReverseRange (XLIterator.hpp) to reverse a range of class T that exposes T::rbegin() and T::rend() and typedef T::reverse_iteratorXLReverseRange, range-based reverse iteration is demonstrated in Examples/Demo6.cpp, Example usage: for (auto& row : XLReverseRange(wks.rows(firstRow, lastRow)))pugixml headers from the library interfacepkg-config files that can be used as demonstrated in the new Scripts/compile.shOPENXLSX_BUNDLED_STATIC_LIB will now create libOpenXLSX-bundled.a library file that is not installed, but can be linked against while including all dependencies (only works with BUILD_SHARED_LIBS=OFF, and OPENXLSX_CPM_LOCAL_PACKAGES_ONLY=OFF or all dependencies available as static libraries on the build system). This uses the newly added OpenXLSX/bundle_static_library.cmake (under MIT License, Copyright (c) 2019 Cristian Adam).Makefile.GNU, but until full support for options is back, this Makefile is overriding some options to the only supported configurationsexternal source code from repository, refined cmake configurationMakefile.GNU is currently non-functional!OPENXLSX_CPM_LOCAL_PACKAGES_ONLY):
find_package for LibZip and PugiXMLOpenXLSX/CMakeLists.txt: added find_package for LibZip and PugiXML. Unfortunately, for LibZip, this generates an error unless the unneeded components zipcmp, zipmerge & ziptool are also installed on the system. TBD how to ignore those missing.nowide installed on the operating systemOPENXLSX_FORCE_NOWIDE - set to ON to use force the use of nowide even on non-Windows systems (this flag is for testing purposes)OPENXLSX_ENABLE_LIBBOOST_NOWIDE - set to ON to use nowide from an installed libboostboost nowide (include path starts with boost/ and namespace is boost::nowide vs. nowide)#include <memory> in XLZipArchive.hpp, #include <stdexcept> in detail/LibZip.hppDemo1A to Makefile.GNUnowide status to Demo4OpenXLSXFileSystemTools, cleaned up cmake and GNU make optionsExamples/CMakeLists.txt for Demo4 (to be tested): correctly add external/nowide to the include pathExamples/CMakeLists.txt for Demo1A (to be tested): correctly add external/nowide to the include pathDemo1A CustomZip implementation to fit the modified IZipArchive conceptOPENXLSX_ENABLE_LIBPUGIXML - set to ON to use an installed libpugixmlOPENXLSX_ENABLE_LIBZIP - set to ON to use an installed libzipOPENXLSX_SHARED_LIBRARY - set to ON for shared library build, OFF builds the static libraryOPENXLSX_SHARED_LIBRARYlibpugixml installed on the operating systemXLXmlParser from public OpenXLSX API - this should address conflicts with pugixml.hpp headers available elsewherelibpugixml - for cmake, variable is OPENXLSX_ENABLE_LIBPUGIXML, in Makefile.GNU, variable is USE_LIBPUGIXML - set to yes if system installed library shall be useddetail/OpenXLSXFileSystemTools.hpp now comprises all functions where unicode (filename) support might be relevant, to be implemented centrally - currently on the To-Do listXLDocument::create: creating a new document no longer creates a file under that name until an explicit call of XLDocument::save or ::saveAs. This is to remove a dependency of XLDocument on boost::nowide on Windows.OpenXLSX/headers/detail/: new headers LipZip.hpp (libzip wrapper) and Zippy.hpp (miniz wrapper)CMakeLists.txt: Option OPENXLSX_ENABLE_LIBZIP activates libzip use, disabling the option defaults to the miniz / Zippy wrapperCMakeLists.txt: Option OPENXLSX_ENABLE_LIBZIP_EXAMPLE replaces the prior use of OPENXLSX_ENABLE_LIBZIP for Demo1Aunzip complains about the flag mismatch. This issue is on my to-to list.bool XLDocument::validateSheetName(std::string sheetName, bool throwOnInvalid = false) - can be called by the user to test whether a name would throwXLSheet::setName, XLWorkbook.addWorksheet or XLWorkbook.cloneSheet are invoked with a name for which validateSheetName would return false, an XLInputError is thrown with the validation rule that was violated.CAUTION: this change is potentially code-breaking as it can throw an exception on code that previously executed without errors - However, when it throws, previous versions would have produced a workbook that Excel refuses to read.
OPENXLSX_ENABLE_LTO that permits disabling link-time optimization altogether. It remains ON by default.XLMergeCells is now constructed with the worksheet root XML node (unfortunately necessary) and will use this access to create/delete the node as necessary, this addresses https://github.com/troldal/OpenXLSX/issues/351XLMergeCells::deleteAll to clear all merges in the worksheetXLMergeIndex as the parameter / return type for all functions using a merge index - the underlying int32_t remains unchangedconstexpr const XLMergeIndex XLMergeNotFound = -1 for code readabilityXLFont::underline, ::scheme, ::vertAlign: fix default value to set for attribute val when tag doesn't existXLFont::setUnderline: return correct "none" value for XLUnderlineNone from XLUnderlineStyleToString (was returning empty string)getBoolAttributeWhenOmittedMeansTrue to XLUtilitiesXLStyles XLFont: changed bool getter functions to return true when tag exists, but attribute val is omitted, to be in line with OOXML spec. This addresses https://github.com/troldal/OpenXLSX/issues/347. Affected getters: bold(), italic(), strikethrough(), outline(), shadow(), condense(), extend()XLSheet::findCell that allow to try and fetch a cell without creating the row/cell XML (like the non-creating XLCellIterator). This function complements XLSheet::cell (which always creates the XML cell node and returns a valid object)findCell, the returned XLCellAssignable::empty() method must be checked to ensure success before accessing any cell propertiesXLSheet::findCell provides a solution to https://github.com/troldal/OpenXLSX/issues/333, a demonstration of this solution has been added to Demo1.cppXLFormula to an empty (zero-length) string will now delete the formula XML node from the cell without further actionsCMakeLists.txt in Examples/external/nowide/* to have cmake_minimum_required VERSION 3.15XLSheet.cppXLSheet.hpp clarifying that sheet index is 1-based#include <cctype> to XLSheet.cpp and XLDrawing.cppSTAT, STATSTRUCT) to link to the platform specific implementation of stat without naming conflictsBefore I start working on the next items on my to-do list (tables/filters, hyperlink support), I am merging all recent patches into master. I have not yet had much feedback on whether the changes work with MS Office, but I am confident that if you discover any issues, I can fix them quickly.
Should you experience stability issues, please revert to commit https://github.com/troldal/OpenXLSX/commit/4ed9c97ad613526bf1544296acd24639dcbe2846 and submit a bug report.
New features
XLComments -> see Demo1.cppXLRowIterator no longer creates the XML for rows that do not exist until the iterator is dereferencedXLDocument::cleanupSharedStrings() can now be called manually to rewrite the shared strings cache (and remove all strings that are no longer referenced from any cell)XLDocument now has a member function void cleanupSharedStrings() that will reindex shared strings for the complete workbook and remove all shared strings that are no longer referenced anywhere, or that have been set to the empty string. This addresses https://github.com/troldal/OpenXLSX/issues/193.XLRowIterator: can now iterate over a range of rows and test bool XLRowIterator::rowExists() before accessing it. This allows to skip non-existing rows without creating them. Functionality is analogous to XLCellIterator and bool XLCellIterator::cellExists()XLWorksheet::range(..) will no longer create all missing rows in the rangeXLCellValueProxy two functions to manipulate shared string indexes directly, bypassing XLSharedStrings:
int32_t stringIndex() constbool setStringIndex(int32_t newIndex)XLSharedStrings:
int32_t stringCount() const - returns the amount of strings currently in the shared strings cacheint32_t rewriteXmlFromCache() - called from XLDocument::cleanupSharedStrings - triggers a full wipe of the shared strings XML & re-creation from the string cache. Returns the number of shared strings written to XMLXLRowIterator:
bool rowExists() - test whether the XLRowIterator currently points to a row that already exists in the XMLbool endReached() - equivalent to (XLRowIterator) it == (XLRowRange) range.end()uint32_t rowNumber() const - return the current row that the iterator is pointing to (m_lastRow + 1 if endReached() == true)XLRow:
bool empty() const returns true if the XLRow instance is not linked to valid XMLexplicit operator bool() const the opposite of empty()XLCellRange.hpp to XLSheet.hppXLContentTypeToString function from XLContentTypes.cpp, as a function XLContentTypeString already exists in utilities/XLUtilities.hppExamples/Demo1.cpp) as they appear in the underlying XML. This is much more practical when searching for comments in a worksheet created by another application.Override entries for the worksheet dependencies (comments, vmlDrawing, table) in [Content Types].xmlThe support for comments is now in a stage where it can be used - please refer to Demo1 line 124ff for a quick "howto". This feature is still in alpha stage, with a few open TBDs:
XLShape XLComments::shape(std::string const& cellRef) - for methods of XLShape please refer to the XLDrawing header file // XLShapeShadow& shadow(); // v:shape subnode v:shadow
// XLShapeFill& fill(); // v:shape subnode v:fill
// XLShapeStroke& stroke(); // v:shape subnode v:stroke
// XLShapePath& path(); // v:shape subnode v:path
// XLShapeTextbox& textbox(); // v:shape subnode v:textbox
Override entries for the worksheet dependencies (comments, vmlDrawing, table)XLKeepCellValue::privateGet as a library internal that can be used with the old behavior for performance reasons, from functions that can guarantee the validity of the XLCellValue for the duration of access to the string referencestd::ostream& operator<<for XLCellValue and XLCellValueProxy now fetch string types as std::string, this addresses https://github.com/troldal/OpenXLSX/issues/166XLCellValue::get<double>() and XLCellValue::get<XLDateTime>(). Note: implicit conversion from string is available in VisitXLCellValueTypeToDouble, but disabled (forced throw)XLCfTypeFromString, XLCfTypeToString, XLCfOperatorFromString, XLCfOperatorToString, XLCfTimePeriodFromString, XLCfTimePeriodToStringXLSheet::isActive and XLSheet::setActive function definitions to ensure bug-free export of symbols to shared library - this addresses https://github.com/troldal/OpenXLSX/issues/316 - please do not ask me why this was never a problem for the static build, I am simply not smart enough to understand that :PBinaryAsHexString, ExcelPasswordHash, ExcelPasswordHashAsString so that they are also exported when the shared library is being builtExcelPasswordHash and ExcelPasswordHashAsString to XLDocument as global utility functionsBinaryAsHexString a global utility function so that XLWorksheet can use them as wellhexDigit and BinaryAsHexString from XLRelationships to XLDocumentbool protectSheet(bool set = true)bool protectObjects(bool set = true)bool protectScenarios(bool set = true)bool allowInsertColumns(bool set = true)bool allowInsertRows(bool set = true)bool allowDeleteColumns(bool set = true)bool allowDeleteRows(bool set = true)bool allowSelectLockedCells(bool set = true)bool allowSelectUnlockedCells(bool set = true)bool denyInsertColumns()bool denyInsertRows()bool denyDeleteColumns()bool denyDeleteRows()bool denySelectLockedCells()bool denySelectUnlockedCells()bool setPasswordHash(std::string hash)bool setPassword(std::string password)bool clearPassword()bool clearSheetProtection()bool sheetProtected()bool objectsProtected()bool scenariosProtected()bool insertColumnsAllowed()bool insertRowsAllowed()bool deleteColumnsAllowed()bool deleteRowsAllowed()bool selectLockedCellsAllowed()bool selectUnlockedCellsAllowed()std::string passwordHash()bool passwordIsSet()std::string XLWorksheet::sheetProtectionSummary() for easy control of established settingsThis is a major patch to address https://github.com/troldal/OpenXLSX/issues/315 - conditional formatting is now implemented in an experimental stage.
XLUnsupportedElement from XLStyles to XLXmlFile header, so that XLWorksheet can use it for conditional formatting functionalitybool isActive_impl() and bool setActive_impl() as no-op function stubs in the hopes this resolves https://github.com/troldal/OpenXLSX/issues/316experimental in this case means:
bool settingExists(std::string settingName)"true" and "false" - whereas LibreOffice appears to store them (for cfRules) as 1 and 0). The reason is: I want to know if this works, and if it does, stay consistent in how OpenXLSX stores boolean values. I may have to modify this as I learn moreaboveAverage="" when for aboveAverage, the documentation defines true as the default - does that mean an empty string gets evaluted as true?XLWorkbook::sharedStrings and XLWorkbook::hasSharedStringsXLDocument::sharedStrings() returns the same, and hasSharedStrings was always returning true anyways.strike(through) font property to address issue #314val is omitted in the <strike> XML tag, the value is now interpreted as true as described in the format specification - previously this was wrongly interpreted as "strikethrough is not set". This addresses issue https://github.com/troldal/OpenXLSX/issues/314XLDeleteProperty == XLInvalidUInt32 == 0xffffffff to delete the theme attribute from XML. This was necessary because even an empty theme="" attribute affects formatting.not node.empty()xl/_rels/workbook.xml.rels should again open without errors for both relative (to xl/ folder) and absolute archive pathsReviewed the XLDateTime code in response to https://github.com/troldal/OpenXLSX/issues/299 and fixed a bug that I think I may have introduced myself. Apologies, dates should now correctly construct from double, struct tm and time_t and convert back to struct tm.
It appears that MS Office does not tolerate any formatting XML nodes prior to the <mergeCells> XML node - in order to get rid of an according error message, the latest commit modifies the XLSheet::merges function to insert a newly created <mergeCells> node directly after the <sheetData> node.
These missing defaults could lead to followup errors when any style index of this cell was later assumed valid to access said style by index (Exception if the index was not in a valid range). All style indexes available in a cell format are now zero-initialized (with no assumptions what the style with index 0 may be configured as, normally it's defaults - if you want to be sure, provide a cell with a known format as copyFrom template to XLCellFormats::create).
XLDocument.hpp: added showWarnings() (default setting) and suppressWarnings()XLStyles.hpp: added suppressWarnings parameter to constructor (default: false)XLDocument::open: if suppressWarnings() was called, suppress warnings about ignored comment xml files and unhandled workbook itemsXLDocument::open: m_suppressWarnings setting is forwarded to XLStyles constructorXLException.hpp: added missing #include <string>XLDocument::open will create a missing workbook relationship in _rels/.rels if, and only if, a workbook with the default path xl/workbook.xml exists in the archiveMerged development branch into the main branch. In summary:
OpenXLSX/headers/XLStyles.hpp: XLStyles class (and lots of subclasses) has been added, providing nearly complete access to all Excel formatting capabilities.OpenXLSX/headers/XLMergeCells.hpp and XLSheet.hpp: XLMergeCells class is made accessible through XLWorksheet in order to create / delete cell mergesExamples/Demo10.cpp demonstrates how styles and merges are used Note: The section that is disabled with testBasics = false will break the resulting Excel Spreadsheet if enabled, the only purpose is to demonstrate access to all new classes and methods. If you want to use them, make sure to use them correctlyNote on XLNumberFormat(s): Contrary to all other XLStyles elements, these do not use an index within the XML as the referrable ID (XLCellFormat::setNumberFormatId), but instead a user-defined ID that can be set via XLNumberFormat::setNumberFormatId - and for an XLCellFormat, can be set to either a self-defined number format ID, or to a format predefined by MS. Generally, for custom formats, it is recommended to use IDs > 100.
XLDocument::create and XLDocument::saveAs function interfaces, but marked them as [[deprecated]]. The new interfaces require explicit specification of XLForceOverwrite or XLDoNotOverwrite. Once the deprecated function definitions can be removed, XLDoNotOverwrite could become the new default behaviorOpenXLSX/external/nowide/nowideDemo0 / kept it in the Makefile as a test vehicleNotes folderScripts folder with xml-format.sh (XML linting, useful to analyze XLSX zip contents in a text editor)make-gnu.sh to Scripts/make-gnu.shScripts/cmake-cleanup.sh to prepare (not execute!) commands that remove all temporary files generated by cmakeScripts/demos-cleanup.sh to remove all xlsx files created by the Demosvoid setSavingDeclaration(XLXmlSavingDeclaration const& savingDeclaration) using class XLXmlSavingDeclaration (defined in XLXmlData.hpp) that can be used to pass a custom XML version, encoding, and standalone property to pugixmlNotes/todo-list.txtXLWorksheet now allows to access an object managing the worksheet's merged cell ranges
XLMergeCells XLWorksheet::merges() - access the XLMergeCells class for the worksheet directlyvoid mergeCells(XLCellRange const& rangeToMerge, bool emptyHiddenCells = false) - merge cells defined by rangeToMergevoid mergeCells(const std::string& rangeReference, bool emptyHiddenCells = false) - merge cells defined by rangeReferencevoid unmergeCells(XLCellRange const& rangeToUnmerge) - unmerge cells defined by rangeToUnmergevoid unmergeCells(const std::string& rangeReference) - unmerge cells defined by rangeReferenceXLMergeCells: added methods
int32_t XLMergeCells::findMerge(const std::string& reference) - find a merge matching reference
* bool mergeExists(const std::string& reference) - test if a merge with reference existsint32_t XLMergeCells::findMergeByCell(const std::string& cellRef) - find a merge containing std::string cellRefint32_t XLMergeCells::findMergeByCell(XLCellReference cellRef) - find a merge containing XLCellReference cellRefsize_t count() - get count of merges defined in the worksheetconst char* merge(int32_t index) - get merge reference string at indexconst char* operator[](int32_t index) - overload of operator[] as a shortcut to ::mergeint32_t appendMerge(const std::string& reference) - define a new merge, invoked by XLWorksheet::mergeCellsvoid deleteMerge(int32_t index) - delete merge with the given index from the worksheet (= unmerge cells), invoked by XLWorksheet::unmergeCellsadded example usage of this functionality to Demo10.cpp
XLDocument::open will now ignore unknown subfolders (they remain unmodified and unaccessible in the zip in memory and stay in the archive upon saving). This prevents throwing an exception for any XLSX file written by a "creative" application that added items unknown to this libraryconstexpr from const unsigned int pugi_parse_settings and moved it to XLDocument.hpp so that the const becomes available to XLStyles and XLSharedStringsXLStyles class - interface can be found in OpenXLSX/headers/XLStyles.hppExamples/Demo10.cpp demonstrates use of the new XLStyles & cell merging functionalityXLCellIterator: can now iterate over a range and test XLCellIterator::cellExists before accessing it. This allows to skip non-existing cells without creating them.workbook##.xml, XML namespaces and random 64bit (relationship) identifiers
xl/workbook.xml) workbook XML name is now accepted if it is correctly referenced in _rels/.relsbool OpenXLSX::enable_xml_namespaces() must be used to enable namespace support before opening a document using e.g. a namespace x (like so: <x:row r="1">) everywhere
insert_child_before("x:row", curRow ) in the <y:sheetData> node will strip the x: and insert a row element named <y:row>, using the parent node's namespaceOpenXLSX/headers/XLXmlParser.hpp) take as an optional last argument a bool force_ns that - if true - will respect a namespace passed into the function for node creation / access. A helper const bool OpenXLSX::XLForceNamespace = true is available for code readability
XMLNode::insert_child_before("x:row", curRow, XLForceNamespace) in the <y:sheetData> node like above, will insert a row element named x:rowid="rId##" where ## is the sequence number, and when a new component is added to the workbook, a new relationship ID is determined by taking the highest existing value within the workbook, and adding +1 to it. During investigation of [https://github.com/troldal/OpenXLSX/issues/254] a workbook was found to use (seemingly) random 64 bit integers, stored in the form r:id="Rxx", with xx being a hexadecimal representation of a 64 bit integer.
OpenXLSX::UseRandomIDs() must be invoked to switch ID functionality before opening such a documentOpenXLSX::UseSequentialIDs() can be used to restore default (sequential) relationship ID functionalityNOTE on enable_xml_namespaces: Namespace support is transparent and can be used with documents that do not use such namespaces. However, it can have a small (<5%) performance impact on large workbooks and is therefore optional to enable.
CAUTION with UseRandomIDs: Please be aware that a mixed mode, where one document is opened with random ID support and another without sequential relationship IDs, is not supported for the time being. If you have to work with documents of different types, you should always configure the desired relationship ID behavior for the next document, work with that, close it, and change the relationship ID configuration before opening the next document.
Please disregard Examples/Demo0.cpp and Examples/Demo9.cpp for now (Demo0 is trivial and was used to test non-standard workbook support, and Demo9 requires a review with better comments). Demo9 showcases how to use the new XLCellAssignable to copy-assign cell contents (like Excel copy & paste).
XLCellIterator no longer creates empty cells just for iterating over them, and provides ::cellExists() to test if the currently pointed-to cell is already in the worksheet XML, before accessing itXLStyles supportXLWorksheet now provides XLMergeCells support for merging / unmerging cell rangesDemo10.cpp has a lot of examples on how to use the new XLStyles functionalitycustomXml etc in the xlsx archiveXLProperties.cpp XLAppProperties to create <TitlesOfParts> and <HeadingPairs> nodes (and subnodes) if missing, added method alignWorksheets, called by XLDocument::open to ensure that all worksheets listed in the workbook xml are also accounted for in docProps/app.xml.XLProperties.cpp prettyInsertXmlNodeBefore, maybe this can eventually become a global function, paired with a TBW function prettyInsertXmlNodeAfter, and could be used by all classes, cleaning up the code for whitespace support substantially.XLProperties.cpp for <HeadingPairs> subnodes: pairCount -> pairValueParent, pairCountValue -> pairValueCode refactored in XLDocument::open to read the shared strings table while consistently ignoring phonetic tags, which were previously only ignored if the very first child of an <si> tag was a phonetic tag. Will now be ignored anywhere before, after or in between text <t> and rich text <r> tags.
Included a "dumb" fallback solution in XLRelationships.cpp GetTypeFromString to support previously unknown relationship domains, e.g. type="http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet". Altered behavior will initially test against the hardcoded relationship domains, and if that test fails to identify a relationship type string, the type string will be searched for an occurrence of /relationships/ and if that substring is found, the type detection fallback will try to evaluate the relationship type based on the substring starting with /relationships/, ignoring the domain. For the above example, that would result in a test of typeString.substr( comparePos ) == "/relationships/worksheet", where comparePos == 41 (the position at which substring /relationships/ begins).
In anticipation of a potential future need for a similar "dumb" fallback solution, repeating hardcoded strings in XLContentTypes.cpp GetTypeFromString were also replaced with string constants.
Updated .gitignore to a more generic version that excludes everything and explicitly re-includes all desired files.
Closed a multitude of pull requests that had been implemented in the May 2024 Update, implemented two more editorials from PR #246 and #253.
BinaryAsHexString: replaced char array with std::string, as ISO C++ standard does not permit variable size arraysRand64: added explicit type cast, as bitwise shift-left does not do integer promotion to long on the left operand-Wpedantic -Wextra and removed all previously disabled flags after below patchesf( param ) -> f(param), a[ index ] -> a[index] and if( condition ) -> if (condition))warning: enumerated and non-enumerated type in conditional expression [-Wextra]void ZipArchive::Save(std::ostream& stream)void ZipArchive::ExtractDir(const std::string& dir, const std::string& dest)void ZipArchive::ExtractAll(const std::string& dest)-Wunused-function by pragma for functions fileExists and isDirectoryuint32_t (was uint64_t). CAUTION: there is no validity check on the underlying XML (nor was there ever one in case a value was inconsistent with OpenXLSX::MAX_ROWS)-Wsign-compare
bool endReached() to eliminate -Wignored-qualifiers (ignored because const on trivial return types accomplishes nothing)OpenXLSX::ignore template, can be used to suppress -Wunused-parameter and -Wunused-variable like so: OpenXLSX::ignore(unusedValue)
-Wunused-parameter#pragma warning lines in another pragma to disable -Wunknown-pragmas (on gcc/g++)
#pragma GCC diagnostic push#pragma GCC diagnostic ignored "-Wunknown-pragmas" // disable warning about below #pragma warning being unknown# pragma /* offending lines go here */#pragma GCC diagnostic popzippy.hppIZipArchive.hppXLCell.hppXLCellIterator.hppXLCellRange.hppXLCellReference.hppXLCellValue.hppXLColor.hppXLColumn.hppXLCommandQuery.hppXLContentTypes.hppXLDateTime.hppXLDocument.hppXLException.hppXLFormula.hppXLMergeCells.hppXLProperties.hppXLRelationships.hppXLRowData.hppXLRow.hppXLSharedStrings.hppXLSheet.hppXLStyles.hppXLWorkbook.hppXLXmlData.hppXLXmlFile.hppXLZipArchive.hppExamples/Demo5.cpp<Properties> (document) element, was previously wrongly appended to headingPairs/xl/worksheets/sheet*, /xl/sharedStrings.xml, /xl/styles.xml, /xl/theme/theme*) and otherwise ignored. This fixes an issue when the workbook contains /xl/pivotCache/ and /xl/pivotTables/ entries until support for those is implemented (if ever ;P)<cols> element obtained via a rowNode parent's parentstd::vector< XLStyleIndex > m_columnStyles, and a method fetchColumnStyles that will populate the vector so that it can be passed to the XLCellIterator constructor
XLCellIterator::cellExists() without creating the XML for the cell.<font><scheme val="major"/></font>)<font><vertAlign val="subscript"/></font>)<fills><fill><gradientFill>...</gradientFill></fill>...</fills> are now supportedPlease refer to Demo10 and XLStyles.hpp on how to set cell formatting. In short:
529 followers · starred Jan 2026
82 followers · starred Jan 2022
698 followers · starred Apr 2024
68 followers · starred Aug 2022