Orcus Documentation Release 0.16
Total Page:16
File Type:pdf, Size:1020Kb
Orcus Documentation Release 0.16 Kohei Yoshida Sep 24, 2021 CONTENTS 1 Overview 3 2 C++ API 37 3 Python API 117 4 CLI 127 5 Notes 135 6 Indices and tables 147 Index 149 i ii Orcus Documentation, Release 0.16 Orcus is a library that provides a collection of standalone file processing filters and utilities. It was originally focused on providing filters for spreadsheet documents, but filters for other types of documents have been added tothemix. Contents: CONTENTS 1 Orcus Documentation, Release 0.16 2 CONTENTS CHAPTER ONE OVERVIEW 1.1 Composition of the library The primary goal of the orcus library is to provide a framework to import the contents of documents stored in various spreadsheet or spreadsheet-like formats. The library also provides several low-level parsers that can be used inde- pendently of the spreadsheet-related features if so desired. In addition, the library also provides support for some hierarchical documents, such as JSON and YAML, which were a later addition to the library. You can use this library either through its C++ API, Python API, or CLI. However, not all three methods equally expose all features of the library, and the C++ API is more complete than the other two. The library is physically split into four parts: 1. the parser part that provides the aforementioned low-level parsers, 2. the filter part that providers higher level import filters for spreadsheet and hierarchical documents that internally use the low-level parsers, 3. the spreadsheet document model part that includes the document model suitable for storing spreadsheet document contents, and 4. CLI for loading and converting spreadsheet and hierarchical documents. If you need to just use the parser part of the library, you need to only link against the liborcus-parser library file. If you need to use the import filter part, link againt boththe liborcus-parser and the liborcus libraries. Likewise, if you need to use the spreadsheet document model part, link against the aforementioned two plus the liborcus-spreadsheet-model library. Also note that the spreadsheet document model part has additional dependency on the ixion library for handling formula re-calculations on document load. 1.2 Loading spreadsheet documents The orcus library’s primary aim is to provide a framework to import the contents of documents stored in various spreadsheet, or spreadsheet-like formats. It supports two primary use cases. The first use case is where the client program does not have its own document model, but needs to import data from a spreadsheet-like document file and access its content without implementing its own document store from scratch. In this particular use case, you can simply use the document class to get it populated, and access its content through its API afterward. The second use case, which is a bit more advanced, is where the client program already has its own internal document model, and needs to use orcus to populate its document model. In this particular use case, you can implement your own set of classes that support necessary interfaces, and pass that to the orcus import filter. 3 Orcus Documentation, Release 0.16 For each document type that orcus supports, there is a top-level import filter class that serves as an entry point for loading the content of a document you wish to load. You don’t pass your document to this filter directly; instead, you wrap your document with what we call an import factory, then pass this factory instance to the loader. This import factory is then required to implement necessary interfaces that the filter class uses in order for it to pass data tothe document as the file is getting parsed. When using orcus’s own document model, you can simply use orcus’s own import factory implementation to wrap its document. When using your own document model, on the other hand, you’ll need to implement your own set of interface classes to wrap your document with. The following sections describe how to load a spreadsheet document by using 1) orcus’s own spreadsheet document class, and 2) a user-defined custom docuemnt class. 1.2.1 Use orcus’s spreadsheet document class If you want to use orcus’ document as your document store instead, then you can use the import_factory class that orcus provides which already implements all necessary interfaces. The example code shown below illustrates how to do this: #include <orcus/spreadsheet/document.hpp> #include <orcus/spreadsheet/factory.hpp> #include <orcus/orcus_ods.hpp> #include <ixion/model_context.hpp> #include <iostream> using namespace orcus; int main() { // Instantiate a document, and wrap it with a factory. spreadsheet::document doc; spreadsheet::import_factory factory(doc); // Pass the factory to the document loader, and read the content from a file // to populate the document. orcus_ods loader(&factory); loader.read_file("/path/to/document.ods"); // Now that the document is fully populated, access its content. const ixion::model_context& model= doc.get_model_context(); // Read the header row and print its content. ixion::abs_address_t pos(0,0,0); // Set the cell position to A1. ixion::string_id_t str_id= model.get_string_identifier(pos); const std::string*s= model.get_string(str_id); assert(s); std::cout<<"A1:"<<*s<< std::endl; pos.column=1; // Move to B1 str_id= model.get_string_identifier(pos); (continues on next page) 4 Chapter 1. Overview Orcus Documentation, Release 0.16 (continued from previous page) s= model.get_string(str_id); assert(s); std::cout<<"B1:"<<*s<< std::endl; pos.column=2; // Move to C1 str_id= model.get_string_identifier(pos); s= model.get_string(str_id); assert(s); std::cout<<"C1:"<<*s<< std::endl; return EXIT_SUCCESS; } This example code loads a file saved in the Open Document Spreadsheet format. It consists of the following content on its first sheet. While it is not clear from this screenshot, cell C2 contains the formula CONCATENATE(A2, ” “, B2) to concatenate the content of A2 and B2 with a space between them. Cells C3 through C7 also contain similar formula expressions. Let’s walk through this code step by step. First, we need to instantiate the document store. Here we are using the concrete document class available in orcus. Then immediately pass this document to the import_factory instance also from orcus: // Instantiate a document, and wrap it with a factory. spreadsheet::document doc; spreadsheet::import_factory factory(doc); The next step is to create the loader instance and pass the factory to it: // Pass the factory to the document loader, and read the content from a file // to populate the document. orcus_ods loader(&factory); In this example we are using the orcus_ods filter class because the document we are loading is of Open Document Spreadsheet type, but the process is the same for other document types, the only difference being the name of the class. Once the filter object is constructed, we’ll simply load the file by calling its read_file() method and passing the path to the file as its argument: loader.read_file("/path/to/document.ods"); Once this call returns, the document has been fully populated. What the rest of the code does is access the content of the first row of the first sheet of the document. First, you need to get a reference to the internal cell value storethatwe call model context: 1.2. Loading spreadsheet documents 5 Orcus Documentation, Release 0.16 const ixion::model_context& model= doc.get_model_context(); Since the content of cell A1 is a string, to get the value you need to first get the ID of the string: ixion::abs_address_t pos(0,0,0); // Set the cell position to A1. ixion::string_id_t str_id= model.get_string_identifier(pos); Once you have the ID of the string, you can pass that to the model to get the actual string value and print it to the standard output: const std::string*s= model.get_string(str_id); assert(s); std::cout<<"A1:"<<*s<< std::endl; Here we do assume that the string value exists for the given ID. In case you pass a string ID value to the get_string() method and there isn’t a string value associated with it, you’ll get a null pointer instead. The reason you need to take this 2-step process to get a string value is because all the string values stored in the cells are pooled at the document model level, and the cells themselves only store the ID values. You may also have noticed that the types surrounding the ixion::model_context class are all in the ixion names- pace. It is because orcus’ own document class uses the formula engine from the ixion library in order to calculate the results of the formula cells inside the document, and the formula engine requires all cell values to be stored in the ixion::model_context instance. Note: The document class in orcus uses the formula engine from the ixion library to calculate the results of the formula cells stored in the document. The rest of the code basically repeats the same process for cells B1 and C1: pos.column=1; // Move to B1 str_id= model.get_string_identifier(pos); s= model.get_string(str_id); assert(s); std::cout<<"B1:"<<*s<< std::endl; pos.column=2; // Move to C1 str_id= model.get_string_identifier(pos); s= model.get_string(str_id); assert(s); std::cout<<"C1:"<<*s<< std::endl; You will see the following output when you compile and run this code: A1: Number B1: String C1: Formula Accessing the numeric cell values are a bit simpler since the values are stored directly with the cells. Using the document from the above example code, the following code: for (spreadsheet::row_t row=1; row<=6;++row) { ixion::abs_address_t pos(0, row,0); (continues on next page) 6 Chapter 1.