### Using the grater Command-Line Tool (Bash) Source: https://context7.com/pbnjay/grate/llms.txt Provides instructions and examples for installing and using the `grater` command-line tool. `grater` extracts tabular data from various file formats and outputs it to standard output as tab-separated values. It supports processing multiple files and enabling verbose/debug output. ```bash # Install the tool go install github.com/pbnjay/grate/cmd/grater@latest # Basic usage - extract all sheets from a file grater data.xlsx # Multiple files grater file1.xls file2.xlsx file3.csv # Enable debug output grater -v data.xlsx ``` -------------------------------- ### Grate Source Interface Methods in Go Source: https://context7.com/pbnjay/grate/llms.txt Illustrates the usage of the `Source` interface in Go for workbook operations. It shows how to use `List()` to get sheet names, `Get()` to retrieve a specific sheet, and `Close()` to release resources. The example also includes checking if a sheet is empty using `IsEmpty()` and iterating through its rows. ```go package main import ( "fmt" "log" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" ) func main() { // Source interface methods: // - List() ([]string, error) - List sheet names // - Get(name string) (Collection, error) - Get sheet by name // - Close() error - Close and free resources wb, err := grate.Open("workbook.xlsx") if err != nil { log.Fatal(err) } defer wb.Close() // List returns visible sheet names sheets, _ := wb.List() for i, name := range sheets { fmt.Printf("Sheet %d: %s\n", i+1, name) } // Get retrieves a specific sheet by name if len(sheets) > 0 { sheet, err := wb.Get(sheets[0]) if err != nil { log.Fatal(err) } // Check if sheet has any data if sheet.IsEmpty() { fmt.Println("Sheet is empty") return } // Process sheet rows for sheet.Next() { fmt.Println(sheet.Strings()) } } } ``` -------------------------------- ### Command-Line Tool: grater Source: https://context7.com/pbnjay/grate/llms.txt Instructions on how to install and use the `grater` command-line tool to extract tabular data from files into tab-separated values (TSV) format. ```APIDOC ## Command-Line Tool: grater The `grater` command extracts tabular data to stdout as tab-separated values. ```bash # Install the tool go install github.com/pbnjay/grate/cmd/grater@latest # Basic usage - extract all sheets from a file grater data.xlsx # Multiple files grater file1.xls file2.xlsx file3.csv # Enable debug output grater -v data.xlsx ``` ```go // grater implementation pattern package main import ( "flag" "fmt" "os" "strings" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" _ "github.com/pbnjay/grate/xls" _ "github.com/pbnjay/grate/xlsx" ) func main() { debug := flag.Bool("v", false, "debug log") flag.Parse() grate.Debug = *debug for _, filename := range flag.Args() { wb, err := grate.Open(filename) if err != nil { fmt.Fprintln(os.Stderr, err) continue } sheets, _ := wb.List() for _, s := range sheets { sheet, err := wb.Get(s) if err != nil { fmt.Fprintln(os.Stderr, err) continue } for sheet.Next() { row := sheet.Strings() fmt.Println(strings.Join(row, "\t")) } } wb.Close() } } ``` ``` -------------------------------- ### Open Modern XLSX Files with Grate in Go Source: https://context7.com/pbnjay/grate/llms.txt This Go code snippet illustrates how to open modern Microsoft Excel (.xlsx) files using the Grate library. It leverages the `xlsx` package to parse the Office Open XML format, including shared strings and styles. The example shows opening a workbook, listing its sheets, and iterating through the data, applying number formats from workbook styles. ```Go package main import ( "fmt" "log" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" // Register XLSX handler (priority 5) ) func main() { // Open modern Excel file wb, err := grate.Open("report.xlsx") if err != nil { log.Fatal(err) } defer wb.Close() sheets, _ := wb.List() for _, name := range sheets { sheet, _ := wb.Get(name) if sheet.IsEmpty() { continue } fmt.Printf("=== %s ===\n", name) for sheet.Next() { // Strings() applies number formats from the workbook styles fmt.Println(sheet.Strings()) } } } ``` -------------------------------- ### Open Legacy XLS Files with Grate in Go Source: https://context7.com/pbnjay/grate/llms.txt This Go code snippet shows how to open legacy Microsoft Excel (.xls) files using the Grate library. It utilizes the `xls` package, which supports BIFF8 workbooks and RC4 encrypted files. The example demonstrates opening the file, listing visible sheets, and accessing XLS-specific features like checking for protection and listing hidden sheets via type assertion. ```Go package main import ( "fmt" "log" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xls" // Register XLS handler (priority 1) ) func main() { // Open legacy Excel file wb, err := grate.Open("legacy_data.xls") if err != nil { log.Fatal(err) } defer wb.Close() // XLS workbooks may have hidden sheets // List() returns only visible sheets sheets, _ := wb.List() fmt.Printf("Visible sheets: %v\n", sheets) // Access XLS-specific features by type assertion if xlsWB, ok := wb.(*xls.WorkBook); ok { if xlsWB.IsProtected() { fmt.Println("Workbook is password protected") } // List hidden sheets (XLS-specific) hidden, _ := xlsWB.ListHidden() fmt.Printf("Hidden sheets: %v\n", hidden) } // Standard iteration works the same way for _, name := range sheets { sheet, _ := wb.Get(name) for sheet.Next() { fmt.Println(sheet.Strings()) } } } ``` -------------------------------- ### Error Handling Source: https://context7.com/pbnjay/grate/llms.txt Explains Grate's specific error types for format detection and data scanning, providing examples of how to handle them. ```APIDOC ## Error Handling Grate provides specific error types for format detection and scanning operations. ```go package main import ( "errors" "fmt" "log" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" _ "github.com/pbnjay/grate/xlsx" ) func main() { // Error types: // grate.ErrNotInFormat - File is not in the expected format (used by handlers) // grate.ErrUnknownFormat - No registered handler recognized the file // grate.ErrInvalidScanType - Scan received invalid pointer type wb, err := grate.Open("unknown.dat") if err != nil { if errors.Is(err, grate.ErrUnknownFormat) { fmt.Println("File format not supported") } else { log.Fatal(err) } return } defer wb.Close() sheet, _ := wb.Get("Sheet1") for sheet.Next() { var s string var badType complex128 // Not supported err := sheet.Scan(&s, &badType) if errors.Is(err, grate.ErrInvalidScanType) { fmt.Println("Invalid scan type - use *bool, *int64, *float64, *string, or *time.Time") } } } ``` ``` -------------------------------- ### Open and Process Files with grate.Open in Go Source: https://context7.com/pbnjay/grate/llms.txt Demonstrates how to use `grate.Open` to automatically detect and open various file formats (.xlsx, .xls, .csv, .tsv). It shows how to list sheets, retrieve individual sheets, and iterate through rows, printing them as strings. Requires importing specific format plugins like `simple`, `xls`, and `xlsx`. ```go package main import ( "fmt" "log" "strings" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" // Register CSV/TSV support _ "github.com/pbnjay/grate/xls" // Register XLS support _ "github.com/pbnjay/grate/xlsx" // Register XLSX support ) func main() { // Open any supported file format - auto-detected wb, err := grate.Open("data.xlsx") if err != nil { log.Fatal(err) } defer wb.Close() // List all available sheets sheets, err := wb.List() if err != nil { log.Fatal(err) } fmt.Printf("Found %d sheets: %v\n", len(sheets), sheets) // Process each sheet for _, sheetName := range sheets { sheet, err := wb.Get(sheetName) if err != nil { log.Printf("Error opening sheet %s: %v", sheetName, err) continue } fmt.Printf("\n=== Sheet: %s ===\n", sheetName) rowNum := 0 for sheet.Next() { rowNum++ row := sheet.Strings() fmt.Printf("Row %d: %s\n", rowNum, strings.Join(row, "\t")) } if sheet.Err() != nil { log.Printf("Error reading sheet: %v", sheet.Err()) } } } ``` -------------------------------- ### Read CSV and TSV Files Source: https://context7.com/pbnjay/grate/llms.txt Illustrates how to register and read delimited files like CSV and TSV using the simple package. These formats are auto-detected and treated as single-sheet workbooks. ```go package main import ( "fmt" "log" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" ) func main() { wb, err := grate.Open("data.csv") if err != nil { log.Fatal(err) } defer wb.Close() sheets, _ := wb.List() sheet, _ := wb.Get(sheets[0]) for sheet.Next() { row := sheet.Strings() fmt.Printf("Data: %v\n", row) } } ``` -------------------------------- ### CSV and TSV Support Source: https://context7.com/pbnjay/grate/llms.txt Details how to use the `simple` package to handle CSV and TSV files, including auto-detection and reading data where cell types are typically strings or blank. ```APIDOC ## CSV and TSV Support The `simple` package provides support for CSV (comma-separated) and TSV (tab-separated) files. Import it with a blank import to register the handlers. ```go package main import ( "fmt" "log" "strings" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" // Registers CSV and TSV handlers ) func main() { // CSV files are auto-detected by content heuristics wb, err := grate.Open("data.csv") if err != nil { log.Fatal(err) } defer wb.Close() // For simple formats, List() returns the filename as the single "sheet" sheets, _ := wb.List() fmt.Printf("Available tables: %v\n", sheets) sheet, _ := wb.Get(sheets[0]) // Simple format types are always "string" or "blank" for sheet.Next() { row := sheet.Strings() types := sheet.Types() // Returns "string" or "blank" for each cell fmt.Printf("Data: %s | Types: %s\n", strings.Join(row, ","), strings.Join(types, ",")) } } // Output: // Available tables: [data.csv] // Data: name,age,city | Types: string,string,string // Data: Alice,30,NYC | Types: string,string,string ``` ``` -------------------------------- ### Open and Read Tabular Data with Grate (Go) Source: https://github.com/pbnjay/grate/blob/main/README.md This Go code snippet demonstrates how to use the Grate package to open a file (supporting .xls, .xlsx, .csv, .tsv), list its available sheets or tables, and then iterate through each row of a selected sheet, printing the data as tab-separated values. It utilizes the standard grate interface and requires importing specific format drivers. ```go package main import ( "fmt" "os" "strings" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" // tsv and csv support _ "github.com/pbnjay/grate/xls" _ "github.com/pbnjay/grate/xlsx" ) func main() { wb, _ := grate.Open(os.Args[1]) // open the file sheets, _ := wb.List() // list available sheets for _, s := range sheets { // enumerate each sheet name sheet, _ := wb.Get(s) // open the sheet for sheet.Next() { // enumerate each row of data row := sheet.Strings() // get the row's content as []string fmt.Println(strings.Join(row, "\t")) } } wb.Close() } ``` -------------------------------- ### Iterate Rows and Extract Metadata with Grate Source: https://context7.com/pbnjay/grate/llms.txt Demonstrates how to open a workbook, iterate through rows using the Collection interface, and extract raw string values, cell data types, and format codes. ```go package main import ( "fmt" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" ) func main() { wb, _ := grate.Open("sales.xlsx") defer wb.Close() sheets, _ := wb.List() sheet, _ := wb.Get(sheets[0]) for sheet.Next() { values := sheet.Strings() types := sheet.Types() formats := sheet.Formats() fmt.Printf("Values: %v, Types: %v, Formats: %v\n", values, types, formats) } } ``` -------------------------------- ### Command-Line Tool: grate2tsv Source: https://context7.com/pbnjay/grate/llms.txt Introduces the `grate2tsv` command-line tool, designed for high-performance, parallel batch extraction of data into TSV format. ```APIDOC ## Command-Line Tool: grate2tsv The `grate2tsv` command is a highly parallel batch extraction tool for converting large numbers of files. ```bash ``` -------------------------------- ### grater Command-Line Tool Implementation (Go) Source: https://context7.com/pbnjay/grate/llms.txt The Go implementation of the `grater` command-line tool. This code parses command-line arguments, opens specified files using Grate, iterates through all sheets and rows, and prints the row data as tab-separated values to standard output. It also handles debug flag for verbose output. ```go // grater implementation pattern package main import ( "flag" "fmt" "os" "strings" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" _ "github.com/pbnjay/grate/xls" _ "github.com/pbnjay/grate/xlsx" ) func main() { debug := flag.Bool("v", false, "debug log") flag.Parse() grate.Debug = *debug for _, filename := range flag.Args() { wb, err := grate.Open(filename) if err != nil { fmt.Fprintln(os.Stderr, err) continue } sheets, _ := wb.List() for _, s := range sheets { sheet, err := wb.Get(s) if err != nil { fmt.Fprintln(os.Stderr, err) continue } for sheet.Next() { row := sheet.Strings() fmt.Println(strings.Join(row, "\t")) } } wb.Close() } } ``` -------------------------------- ### Enabling Debug Logging in Grate (Go) Source: https://context7.com/pbnjay/grate/llms.txt Shows how to enable debug logging for the Grate library to observe format detection and internal processing steps. Debugging can be enabled by setting the global `grate.Debug` variable to true or by passing a build flag during compilation. ```go package main import ( "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" _ "github.com/pbnjay/grate/xls" _ "github.com/pbnjay/grate/xlsx" ) func main() { // Enable debug logging grate.Debug = true // Or set at build time: // go build -ldflags="-X github.com/pbnjay/grate.loglevel=debug" wb, _ := grate.Open("data.xlsx") defer wb.Close() // Debug output shows format detection and processing steps } ``` -------------------------------- ### Directly Open CSV and TSV Files in Go Source: https://context7.com/pbnjay/grate/llms.txt This Go code snippet demonstrates how to directly open CSV and TSV files using `simple.OpenCSV` and `simple.OpenTSV` respectively. This bypasses auto-detection when the file format is known, providing a more efficient way to read delimited data. It includes error handling and iterates through the data. ```Go package main import ( "fmt" "log" "github.com/pbnjay/grate/simple" ) func main() { // Directly open as CSV (priority 15) csvSource, err := simple.OpenCSV("data.csv") if err != nil { log.Fatal(err) } defer csvSource.Close() sheets, _ := csvSource.List() sheet, _ := csvSource.Get(sheets[0]) for sheet.Next() { fmt.Println(sheet.Strings()) } // Directly open as TSV (priority 10) tsvSource, err := simple.OpenTSV("data.tsv") if err != nil { log.Fatal(err) } defer tsvSource.Close() sheets, _ = tsvSource.List() sheet, _ = tsvSource.Get(sheets[0]) for sheet.Next() { fmt.Println(sheet.Strings()) } } ``` -------------------------------- ### Registering Custom Format Handlers in Go Source: https://context7.com/pbnjay/grate/llms.txt Demonstrates how to register a custom format handler with the Grate library. It defines a custom source type and an open function that returns ErrNotInFormat if the file is not of the custom type, allowing Grate to try other handlers. Handlers are registered with a priority, where lower numbers are tried first. ```go package main import ( "fmt" "github.com/pbnjay/grate" ) // Custom format handler example type customSource struct { data [][]string row int } func (c *customSource) List() ([]string, error) { return []string{"data"}, nil } func (c *customSource) Get(name string) (grate.Collection, error) { return c, nil } func (c *customSource) Close() error { return nil } func (c *customSource) Next() bool { c.row++ return c.row < len(c.data) } func (c *customSource) Strings() []string { return c.data[c.row] } func (c *customSource) Types() []string { return make([]string, len(c.data[c.row])) } func (c *customSource) Formats() []string { return make([]string, len(c.data[c.row])) } func (c *customSource) Scan(args ...interface{}) error { return nil } func (c *customSource) IsEmpty() bool { return len(c.data) == 0 } func (c *customSource) Err() error { return nil } func openCustom(filename string) (grate.Source, error) { // Return ErrNotInFormat if file doesn't match // This allows grate.Open to try the next handler return nil, grate.ErrNotInFormat } func init() { // Register with priority 20 (tried after xls=1, xlsx=5, tsv=10, csv=15) grate.Register("custom", 20, openCustom) } func main() { fmt.Println("Custom handler registered") } ``` -------------------------------- ### Registering Custom Format Handlers Source: https://context7.com/pbnjay/grate/llms.txt Demonstrates how to register a custom format handler with the Grate library. Handlers are prioritized by a numerical value, with lower numbers being tried first. ```APIDOC ## Registering Custom Format Handlers The `grate.Register` function allows adding custom format handlers. Handlers with lower priority numbers are tried first. ```go package main import ( "fmt" "github.com/pbnjay/grate" ) // Custom format handler example type customSource struct { data [][]string row int } func (c *customSource) List() ([]string, error) { return []string{"data"}, nil } func (c *customSource) Get(name string) (grate.Collection, error) { return c, nil } func (c *customSource) Close() error { return nil } func (c *customSource) Next() bool { c.row++ return c.row < len(c.data) } func (c *customSource) Strings() []string { return c.data[c.row] } func (c *customSource) Types() []string { return make([]string, len(c.data[c.row])) } func (c *customSource) Formats() []string { return make([]string, len(c.data[c.row])) } func (c *customSource) Scan(args ...interface{}) error { return nil } func (c *customSource) IsEmpty() bool { return len(c.data) == 0 } func (c *customSource) Err() error { return nil } func openCustom(filename string) (grate.Source, error) { // Return ErrNotInFormat if file doesn't match // This allows grate.Open to try the next handler return nil, grate.ErrNotInFormat } func init() { // Register with priority 20 (tried after xls=1, xlsx=5, tsv=10, csv=15) grate.Register("custom", 20, openCustom) } func main() { fmt.Println("Custom handler registered") } ``` ``` -------------------------------- ### Handling Grate Errors in Go Source: https://context7.com/pbnjay/grate/llms.txt Illustrates how to handle specific error types provided by the Grate library, such as `ErrUnknownFormat` for unsupported file types and `ErrInvalidScanType` for incorrect data scanning. It demonstrates checking errors using `errors.Is` for graceful failure. ```go package main import ( "errors" "fmt" "log" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" _ "github.com/pbnjay/grate/xlsx" ) func main() { // Error types: // grate.ErrNotInFormat - File is not in the expected format (used by handlers) // grate.ErrUnknownFormat - No registered handler recognized the file // grate.ErrInvalidScanType - Scan received invalid pointer type wb, err := grate.Open("unknown.dat") if err != nil { if errors.Is(err, grate.ErrUnknownFormat) { fmt.Println("File format not supported") } else { log.Fatal(err) } return } defer wb.Close() sheet, _ := wb.Get("Sheet1") for sheet.Next() { var s string var badType complex128 // Not supported err := sheet.Scan(&s, &badType) if errors.Is(err, grate.ErrInvalidScanType) { fmt.Println("Invalid scan type - use *bool, *int64, *float64, *string, or *time.Time") } } } ``` -------------------------------- ### Collection Interface - Row Iteration Source: https://context7.com/pbnjay/grate/llms.txt Demonstrates how to iterate over rows in a spreadsheet using the Collection interface, extracting values as strings, and checking cell types and formats. ```APIDOC ## Collection Interface - Row Iteration The `Collection` interface provides row-by-row iteration over sheet data. It supports extracting values as strings, typed data, or scanning into variables. ```go package main import ( "fmt" "log" "time" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" ) func main() { wb, _ := grate.Open("sales.xlsx") defer wb.Close() sheets, _ := wb.List() sheet, _ := wb.Get(sheets[0]) // Collection interface methods: // - Next() bool - Advance to next row (call before reading) // - Strings() []string - Get row as string slice // - Types() []string - Get cell types: "boolean", "integer", "float", "string", "date", "blank", "hyperlink" // - Formats() []string - Get cell format codes // - Scan(args ...interface{}) error - Scan into typed variables // - IsEmpty() bool - Check if collection has no data // - Err() error - Get last error for sheet.Next() { // Get raw string values values := sheet.Strings() fmt.Printf("Values: %v\n", values) // Get data types for each cell types := sheet.Types() fmt.Printf("Types: %v\n", types) // Get format codes (e.g., "General", "0.00", "mm-dd-yy") formats := sheet.Formats() fmt.Printf("Formats: %v\n", formats) } } // Output: // Values: [Product Price Quantity Date] // Types: [string string string string] // Formats: [General General General General] // Values: [Widget 19.99 100 2024-01-15] // Types: [string float integer date] // Formats: [General 0.00 General mm-dd-yy] ``` ``` -------------------------------- ### Scanning Row Data into Variables Source: https://context7.com/pbnjay/grate/llms.txt Explains how to use the `Scan` method to extract row data directly into typed Go variables, supporting common data types like strings, numbers, booleans, and time. ```APIDOC ## Scanning Row Data into Variables The `Scan` method extracts values from the current row into typed Go variables. Supported types are `*bool`, `*int64`, `*float64`, `*string`, and `*time.Time`. ```go package main import ( "fmt" "log" "time" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" ) type SalesRecord struct { Product string Price float64 Quantity int64 Date time.Time } func main() { wb, _ := grate.Open("sales.xlsx") defer wb.Close() sheet, _ := wb.Get("Sales") var records []SalesRecord // Skip header row sheet.Next() for sheet.Next() { var product string var price float64 var qty int64 var date time.Time // Scan requires pointers to: bool, int64, float64, string, or time.Time err := sheet.Scan(&product, &price, &qty, &date) if err != nil { // Handle type mismatch or column count mismatch log.Printf("Scan error: %v", err) continue } records = append(records, SalesRecord{ Product: product, Price: price, Quantity: qty, Date: date, }) } for _, r := range records { fmt.Printf("%s: $%.2f x %d on %s\n", r.Product, r.Price, r.Quantity, r.Date.Format("2006-01-02")) } } // Output: // Widget: $19.99 x 100 on 2024-01-15 // Gadget: $29.99 x 50 on 2024-01-16 ``` ``` -------------------------------- ### Scan Row Data into Typed Variables Source: https://context7.com/pbnjay/grate/llms.txt Shows how to map spreadsheet row data directly into Go structs using the Scan method. It supports pointers to bool, int64, float64, string, and time.Time types. ```go package main import ( "fmt" "log" "time" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" ) func main() { wb, _ := grate.Open("sales.xlsx") defer wb.Close() sheet, _ := wb.Get("Sales") sheet.Next() // Skip header for sheet.Next() { var product string var price float64 var qty int64 var date time.Time err := sheet.Scan(&product, &price, &qty, &date) if err != nil { log.Printf("Scan error: %v", err) continue } fmt.Printf("%s: $%.2f x %d on %s\n", product, price, qty, date.Format("2006-01-02")) } } ``` -------------------------------- ### Enable Debug Mode Source: https://context7.com/pbnjay/grate/llms.txt Enables debug logging in Grate to observe the format detection process and internal operations, which is useful for troubleshooting. ```APIDOC ## Debug Mode Enable debug logging to see which format handlers are tried and internal processing details. ```go package main import ( "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/simple" _ "github.com/pbnjay/grate/xls" _ "github.com/pbnjay/grate/xlsx" ) func main() { // Enable debug logging grate.Debug = true // Or set at build time: // go build -ldflags="-X github.com/pbnjay/grate.loglevel=debug" wb, _ := grate.Open("data.xlsx") defer wb.Close() // Debug output shows format detection and processing steps } // Example debug output: // Registering the xls format at priority 1 // Registering the xlsx format at priority 5 // Registering the tsv format at priority 10 // Registering the csv format at priority 15 // data.xlsx is not in xls format // openXML _rels/.rels // Processing substream 0/1 (45 records) ``` ``` -------------------------------- ### Handling Merged Cells in Excel Files with Grate in Go Source: https://context7.com/pbnjay/grate/llms.txt This Go code snippet demonstrates how Grate handles merged cells in Excel files. It shows how to detect and interpret special Unicode markers (`grate.ContinueColumnMerged`, `grate.EndColumnMerged`, `grate.ContinueRowMerged`, `grate.EndRowMerged`) that represent merged cell structures. The code iterates through a sheet and prints cell values along with indicators for merged cell continuations or endings. ```Go package main import ( "fmt" "github.com/pbnjay/grate" _ "github.com/pbnjay/grate/xlsx" ) func main() { // Merged cell markers: // grate.ContinueColumnMerged = "→" - Continue horizontally // grate.EndColumnMerged = "⇥" - End of horizontal merge // grate.ContinueRowMerged = "↓" - Continue vertically // grate.EndRowMerged = "⤓" - End of vertical merge wb, _ := grate.Open("merged.xlsx") defer wb.Close() sheet, _ := wb.Get("Sheet1") for sheet.Next() { row := sheet.Strings() for col, cell := range row { switch cell { case grate.ContinueColumnMerged: fmt.Printf("[%d] (merged →) ", col) case grate.EndColumnMerged: fmt.Printf("[%d] (merge end ⇥) ", col) case grate.ContinueRowMerged: fmt.Printf("[%d] (merged ↓) ", col) case grate.EndRowMerged: fmt.Printf("[%d] (merge end ⤓) ", col) default: fmt.Printf("[%d] %s ", col, cell) } } fmt.Println() } } // Example output for a 2x3 merged cell containing "Total": // [0] Total [1] (merged →) [2] (merge end ⇥) // [0] (merged ↓) [1] (merged →) [2] (merge end ⇥) // [0] (merge end ⤓) [1] (merged →) [2] (merge end ⇥) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.