Excel spreadsheet (XLSX) format parser written in pure Swift

Overview

CoreXLSX

Excel spreadsheet (XLSX) format parser written in pure Swift

Build Status Version License Platform Coverage

CoreXLSX is a library focused on representing the low-level structure of the XML-based XLSX spreadsheet format. It allows you to open a spreadsheet archive with .xlsx extension and map its internal structure into model types expressed directly in Swift.

Important to note that this library provides read-only support only for the .xlsx format. As the older legacy .xls spreadsheet format has completely different internals, please refer to other libraries if you need to work with files of that type.

If your .xlsx files use ECMA-376 agile encryption (which seems to be the most popular variety), have a look at the CryptoOffice library.

Automatically generated documentation is available on our GitHub Pages.

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Model types in CoreXLSX directly map internal structure of XLSX format with more sensible naming applied to a few attributes. The API is pretty simple:

import CoreXLSX

let filepath = "./categories.xlsx"
guard let file = XLSXFile(filepath: filepath) else {
  fatalError("XLSX file at \(filepath) is corrupted or does not exist")
}

for wbk in try file.parseWorkbooks() {
  for (name, path) in try file.parseWorksheetPathsAndNames(workbook: wbk) {
    if let worksheetName = name {
      print("This worksheet has a name: \(worksheetName)")
    }

    let worksheet = try file.parseWorksheet(at: path)
    for row in worksheet.data?.rows ?? [] {
      for c in row.cells {
        print(c)
      }
    }
  }
}

This prints raw cell data from every worksheet in the given XLSX file. Please refer to the Worksheet model for more atttributes you might need to read from a parsed file.

Cell references

You should not address cells via their indices in the cells array. Every cell has a reference property, which you can read to understand where exactly a given cell is located. Corresponding properties on the CellReference struct give you the exact position of a cell.

Empty cells

The .xlsx format makes a clear distinction between an empty cell and absence of a cell. If you're not getting a cell or a row when iterating through the cells array, this means that there is no such cell or row in your document. Your .xlsx document should have empty cells and rows written in it in the first place for you to be able to read them.

Making this distinction makes the format more efficient, especially for sparse spreadsheets. If you had a spreadsheet with a single cell Z1000000, it wouldn't contain millions of empty cells and a single cell with a value. The file only stores a single cell, which allows sparse spreadsheets to be quickly saved and loaded, also taking less space on the filesystem.

Finding a cell by a cell reference

Given how the .xlsx format stores cells, you potentially have to iterate through all cells and build your own mapping from cell references to actual cell values. The CoreXLSX library does not currently do this automatically, and you will have to implement your own mapping if you need it. You're welcome to submit a pull request that adds such functionality as an optional step during parsing.

Shared strings

Strings in spreadsheet internals are frequently represented as strings shared between multiple worksheets. To parse a string value from a cell you should use stringValue(_: SharedStrings) function on Cell together with parseSharedString() on XLSXFile.

Here's how you can get all strings in column "C" for example:

if let sharedStrings = try file.parseSharedStrings() {
  let columnCStrings = worksheet.cells(atColumns: [ColumnReference("C")!])
    .compactMap { $0.stringValue(sharedStrings) }
}

To parse a date value from a cell, use dateValue property on the Cell type:

let columnCDates = worksheet.cells(atColumns: [ColumnReference("C")!])
  .compactMap { $0.dateValue }

Similarly, to parse rich strings, use the richStringValue function:

if let richStrings = try file.parseSharedStrings() {
  let columnCRichStrings = worksheet.cells(atColumns: [ColumnReference("C")!])
    .compactMap { $0.richStringValue(sharedStrings) }
}

Styles

Since version 0.5.0 you can parse style information from the archive with the new parseStyles() function. Please refer to the Styles model for more details. You should also note that not all XLSX files contain style information, so you should be prepared to handle the errors thrown from parseStyles() function in that case.

Here's a short example that fetches a list of fonts used:

let styles = try file.parseStyles()
let fonts = styles.fonts?.items.compactMap { $0.name?.value }

To get formatting for a given cell, use format(in:) and font(in:) functions, passing it the result of parseStyles:

let styles = try file.parseStyles()
let format = worksheet.data?.rows.first?.cells.first?.format(in: styles)
let font = worksheet.data?.rows.first?.cells.first?.font(in: styles)

Reporting compatibility issues

If you stumble upon a file that can't be parsed, please file an issue posting the exact error message. Thanks to use of standard Swift Codable protocol, detailed errors are generated listing a missing attribute, so it can be easily added to the model enabling broader format support. Attaching a file that can't be parsed would also greatly help in diagnosing issues. If these files contain any sensitive data, we suggest obfuscating or generating fake data with same tools that generated original files, assuming the issue can still be reproduced this way.

If the whole file can't be attached, try passing a sufficiently large value (between 10 and 20 usually works well) to errorContextLength argument of XLSXFile initializer. This will bundle the failing XML snippet with the debug description of thrown errors. Please also attach the full debug description if possible when reporting issues.

How does it work?

Since every XLSX file is a zip archive of XML files, CoreXLSX uses XMLCoder library and standard Codable protocols to map XML nodes and atrributes into plain Swift structs. ZIPFoundation is used for in-memory decompression of zip archives. A detailed description is available here.

Requirements

Apple Platforms

  • Xcode 11.3 or later
  • Swift 5.1 or later
  • iOS 9.0 / watchOS 2.0 / tvOS 9.0 / macOS 10.11 or later deployment targets

Linux

  • Ubuntu 16.04 or later
  • Swift 5.1 or later

Installation

Swift Package Manager

Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies on all platforms.

Once you have your Swift package set up, adding CoreXLSX as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
  .package(url: "https://github.com/CoreOffice/CoreXLSX.git",
           .upToNextMinor(from: "0.14.1"))
]

If you're using CoreXLSX in an app built with Xcode, you can also add it as a direct dependency using Xcode's GUI.

CocoaPods

CoreXLSX is available through CocoaPods on Apple's platforms. To install it, simply add pod 'CoreXLSX', '~> 0.14.1' to your Podfile like shown here:

source 'https://github.com/CocoaPods/Specs.git'
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
use_frameworks!
target '<Your Target Name>' do
  pod 'CoreXLSX', '~> 0.14.1'
end

Contributing

Sponsorship

If this library saved you any amount of time or money, please consider sponsoring the work of its maintainer. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.

Development Workflow

On macOS the easiest way to start working on the project is to open the Package.swift file in Xcode 11 or later. There is an extensive test suite that both tests files end-to-end and isolated snippets against their corresponding model values.

If you prefer not to work with Xcode, the project fully supports SwiftPM and the usual workflow with swift build and swift test should work, otherwise please report this as a bug.

Coding Style

This project uses SwiftFormat and SwiftLint to enforce formatting and coding style. We encourage you to run SwiftFormat within a local clone of the repository in whatever way works best for you either manually or automatically via an Xcode extension, build phase or git pre-commit hook etc.

To guarantee that these tools run before you commit your changes on macOS, you're encouraged to run this once to set up the pre-commit hook:

brew bundle # installs SwiftLint, SwiftFormat and pre-commit
pre-commit install # installs pre-commit hook to run checks before you commit

Refer to the pre-commit documentation page for more details and installation instructions for other platforms.

SwiftFormat and SwiftLint also run on CI for every PR and thus a CI build can fail with inconsistent formatting or style. We require CI builds to pass for all PRs before merging.

Code of Conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [email protected].

Maintainers

Max Desiatov.

License

CoreXLSX is available under the Apache 2.0 license. See the LICENSE file for more info.

Comments
  • "No value associated with key CodingKeys(stringValue: \"cols\", intValue: nil)

    (lldb) po file.parseWorksheetPaths() ▿ 3 elements

    • 0 : "xl/worksheets/sheet3.xml"
    • 1 : "xl/worksheets/sheet2.xml"
    • 2 : "xl/worksheets/sheet1.xml"

    (lldb) po file.parseWorksheet(at: "xl/worksheets/sheet3.xml") ▿ DecodingError ▿ keyNotFound : 2 elements - .0 : CodingKeys(stringValue: "cols", intValue: nil) ▿ .1 : Context - codingPath : 0 elements - debugDescription : "No value associated with key CodingKeys(stringValue: "cols", intValue: nil) ("cols")." - underlyingError : nil

    (lldb) po file.parseWorksheet(at: "xl/worksheets/sheet2.xml") ▿ DecodingError ▿ keyNotFound : 2 elements - .0 : CodingKeys(stringValue: "cols", intValue: nil) ▿ .1 : Context - codingPath : 0 elements - debugDescription : "No value associated with key CodingKeys(stringValue: "cols", intValue: nil) ("cols")." - underlyingError : nil

    (lldb) po file.parseWorksheet(at: "xl/worksheets/sheet1.xml") Error Domain=NSXMLParserErrorDomain Code=39 "(null)" UserInfo={NSXMLParserErrorColumn=16328, NSXMLParserErrorLineNumber=2, NSXMLParserErrorMessage=AttValue: " or ' expected } ▿ DecodingError ▿ dataCorrupted : Context - codingPath : 0 elements - debugDescription : "The given data was not valid XML." ▿ underlyingError : Optional - some : Error Domain=NSXMLParserErrorDomain Code=111 "(null)"

    opened by maxvol 27
  • how to get actual cell values?

    how to get actual cell values?

    i see that cells contain some kind of indices instead of actual values (i.e. some kind of integer number instead of string) how can i get actual value of a cell? probably there is some kind of reference table for it?

    opened by maxvol 18
  • file.parseWorksheet(at: path) dies

    file.parseWorksheet(at: path) dies

    Version 0.9.1

    Describe the bug file.parseWorksheet(at: path) throws CoreXLSXError.archiveEntryNotFound when trying to access a single sheet spreadsheet.

    parseWorksheetPaths() returns [ "xl//xl/worksheets/sheet1.xml" ], which looks wrong. I'd guess, because parseWorksheetPaths() does not check that a worksheet.target ("/xl/worksheets/sheet1.xml" in this case) contains a root path and adds the directory prefix ("xl") on top of that.

    File for reproduction Unfortunately, I cannot provide the file in question. Try generating one in Windows version fo Excel.

    Additional context Add any other context about the problem here.

    more info needed 
    opened by leuski 12
  • archiveEntryNotFound error

    archiveEntryNotFound error

    Version

    0.12.0

    Description of the bug

    An archiveEntryNotFound error is thrown for certain files (but I couldn't figure out what exactly causes the issue)

    Steps to reproduce

    1. Load the file attached bellow (let file = XLSXFile(filepath: tableFilePath))
    2. Call parseSharedStrings

    File for reproduction

    Test.xlsx https://tools.hb.bizmrg.com/Test.xlsx

    bug 
    opened by Davvie 11
  • parseDocumentRelationships() crash

    parseDocumentRelationships() crash

    Hi @MaxDesiatov - function was working but I'm now getting a crash on a test sheet, any ideas?

    Crash message is: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "relationship", intValue: nil), _XMLKey(stringValue: "Index 3", intValue: 3), CodingKeys(stringValue: "type", intValue: nil)], debugDescription: "Cannot initialize SchemaType from invalid String value http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain", underlyingError: nil))

    Spreadsheet is: Logbook.xlsx

    Update: the issue seems to affect any document with formulas, where a calcChain relationship is included in the relationships file

    Thanks, Phil

    opened by FleetPhil 10
  • Printing Strings in a Column

    Printing Strings in a Column

    Hi there, I am new to CoreXLSX. When I print the data in column C as in the Readme.md, this error occurs.

    'keyNotFound(CodingKeys(stringValue: "sz", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "si", intValue: nil), XMLKey(stringValue: "374", intValue: 374), XMLKey(stringValue: "374", intValue: 374), CodingKeys(stringValue: "r", intValue: nil), XMLKey(stringValue: "1", intValue: 1), XMLKey(stringValue: "1", intValue: 1), CodingKeys(stringValue: "rPr", intValue: nil), CodingKeys(stringValue: "sz", intValue: nil)], debugDescription: "No attribute or element found for key CodingKeys(stringValue: "sz", intValue: nil) ("sz").", underlyingError: nil)): file /Users/My Macbook/Documents/Programs:Codes/Data Collection Test/Data Collection Test/ViewController.swift, line 46 2020-06-25 18:55:21.956351+0800 Pocket Science Framework Test[32426:2275624] Fatal error: keyNotFound(CodingKeys(stringValue: "sz", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "si", intValue: nil), XMLKey(stringValue: "374", intValue: 374), XMLKey(stringValue: "374", intValue: 374), CodingKeys(stringValue: "r", intValue: nil), XMLKey(stringValue: "1", intValue: 1), XMLKey(stringValue: "1", intValue: 1), CodingKeys(stringValue: "rPr", intValue: nil), CodingKeys(stringValue: "sz", intValue: nil)], debugDescription: "No attribute or element found for key CodingKeys(stringValue: "sz", intValue: nil) ("sz").", underlyingError: nil)): file /Users/My Macbook/Documents/Programs:Codes/Data Collection Test/Data Collection Test/ViewController.swift, line 46'

    I have attached my code

    do {
                let filepath = "/Users/My Macbook/Documents/Programs:Codes/Data Collection Test/Data Collection Test/data.xlsx"
                guard let file = XLSXFile(filepath: filepath) else {
                  fatalError("XLSX file at \(filepath) is corrupted or does not exist")
                }
                for wbk in try file.parseWorkbooks() {
                  for (name, path) in try file.parseWorksheetPathsAndNames(workbook: wbk) {
                    if let worksheetName = name {
                      print("This worksheet has a name: \(worksheetName)")
                    }
                    let sharedStrings = try file.parseSharedStrings()
                    let worksheet = try file.parseWorksheet(at: path)
                    
                    let columnCStrings = worksheet.cells(atColumns: [ColumnReference("C")!])
                    .compactMap { $0.stringValue(sharedStrings) }
                    
                    print(columnCStrings)
                    
                    for row in worksheet.data?.rows ?? [] {
                      for c in row.cells {
                        print(c)
                      }
                    }
                  }
                }
            } catch {
                fatalError("\(error)")
            }
    
    bug 
    opened by Ethan-Chew 8
  • Reading Date values from cell

    Reading Date values from cell

    I tried the parsing with sharedStrings and the value of cells directly in case of numbers. Both work fine. But when there is a date in the cell field. It's not returned as String, which I thought it would be. But I get a rather random number 4328 something.

    enhancement 
    opened by sourav13 8
  • Can't open xml

    Can't open xml

    I download xml from bank and I want convert it to csv I try last version CoreXLSX, but I can't open file (numbers and Microsoft excel already can open this file) is can be opened file like this format, by CoreXLSX? Screen Shot 2019-08-24 at 23 52 44

    question 
    opened by EvGeniyLell 8
  • Cannot initialize SchemaType from invalid String value

    Cannot initialize SchemaType from invalid String value

    Version

    0.14.0

    Description of the bug

    While trying to parse, there is an error being thrown with the message:

    "Cannot initialize SchemaType from invalid String valuehttp://purl.oclc.org/ooxml/officeDocument/relationships/extendedProperties"

    Looks to be reoccurring of https://github.com/CoreOffice/CoreXLSX/issues/136

    Expected behavior

    File should be able to be parsed

    File for reproduction

    Cannot attach file publicly - will email.

    If this problem is reproducible only with a specific file, please attach this file to the issue, or send it to [email protected] if you can't share the file publicly.

    Additional context

    (lldb) po masterDataFile.parseWorkbooks()
    ▿ DecodingError
      ▿ dataCorrupted : Context
        ▿ codingPath : 4 elements
          - 0 : CodingKeys(stringValue: "relationship", intValue: nil)
          ▿ 1 : XMLKey(stringValue: "0", intValue: 0)
            - stringValue : "0"
            ▿ intValue : Optional<Int>
              - some : 0
          ▿ 2 : XMLKey(stringValue: "0", intValue: 0)
            - stringValue : "0"
            ▿ intValue : Optional<Int>
              - some : 0
          - 3 : CodingKeys(stringValue: "type", intValue: nil)
        - debugDescription : "Cannot initialize SchemaType from invalid String value http://purl.oclc.org/ooxml/officeDocument/relationships/extendedProperties"
        - underlyingError : nil
        ```
    bug 
    opened by rajeejones 7
  • Getting Data From a specific Worksheet

    Getting Data From a specific Worksheet

    I am so sorry to ask so many questions...

    May I know how I can get the data from a specific worksheet, rather than letting the code run through all worksheets? Thanks

    question 
    opened by Ethan-Chew 6
  • Cannot initialize SchemaType from invalid String value http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml

    Cannot initialize SchemaType from invalid String value http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml

    Version 0.9.0

    Describe the bug Parsing a spreadsheet from a customer throws this error. I can provide a sanitized version if required, but looking over the code, it seems like this is just an omitted type from Relationships.swift.

    bug 
    opened by mxcl 6
  • Excel Parser Truncates Leading 0's and Maybe Trailing 0's

    Excel Parser Truncates Leading 0's and Maybe Trailing 0's

    Version

    Current

    Description of the bug

    The leading and trailing zeros of formatted numbers maybe truncated. Usually numbers don't start with zero so it's probably just the leading 0's

    Steps to reproduce

    Steps to reproduce the behavior, for example:

    1. Create an Excel File with leading zeros
    2. Parse worksheet and strings
    3. Append to an object or print into the console
    4. 00017 is actually 17

    Expected behavior

    Leading zeros should display

    Additional context

    I'm interested in implementing a workaround to get the truncated 0's This attached screenshot shows a possible solution. If you search truncated 0's with xlsx parser you get the solution that I found. Maybe you guys have a workaround for this Swift package?

    Screen Shot 2023-01-03 at 4 35 27 PM
    opened by Senbazuru1075 0
  • XLSX File is not Read from documentPicker

    XLSX File is not Read from documentPicker

    Version 0.14.1

    Description of the bug using documentPicker I tried opening an xlsx file however it does not open and it crashes to excel file is corrupted, I tried the solution from #160 but it did not work, I also tried to copy the file first to the bundle but it still does the same, also I tried to use fileExists originally with the url and filepath variable but still the same result Steps to reproduce

    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
                        let url = urls[0]
                        let filepath = url.path
                        let filemanager: FileManager = FileManager.default
                        
                        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
                        let docDir = paths.first! as NSString
                        let excelfile = docDir.appendingPathComponent("temp.xlsx")
                        let fExcelFile = URL(fileURLWithPath: excelfile)
                        //try to save to internal memory
                        if filemanager.fileExists(atPath: excelfile) {
                            try! filemanager.removeItem(at: URL(fileURLWithPath: excelfile))
                        }
                        try! filemanager.copyItem(at: urls.first!, to: URL(fileURLWithPath: excelfile))
                        if filemanager.fileExists(atPath: excelfile) {
                            print("file is here\(excelfile) \(filemanager.isReadableFile(atPath: excelfile))")
                            //print(filemanager.pe)
                        }
                        guard fExcelFile.startAccessingSecurityScopedResource() else {
                            print("failed accessing security scope")
                            return
                        }
                        defer { fExcelFile.stopAccessingSecurityScopedResource() }
                        
                        guard let file = XLSXFile(filepath: excelfile) else {
                            fatalError("excel file is corrupted")
                            return;
                        }
                        do {
                            for wbk in try file.parseWorkbooks() {
                                do {
                                    for(name, path) in try file.parseWorksheetPathsAndNames(workbook: wbk) {
                                        if let worksheetname = name {
                                            print("This worksheet has a name \(worksheetname)")
                                        }
                                        let worksheet = try file.parseWorksheet(at: path)
                                        for row in worksheet.data?.rows ?? [] {
                                            for c  in row.cells {
                                                print(c)
                                            }
                                        }
                                    }
                                }
                                catch {
                                    
                                }
                            }
                        }
                        catch {
                            
                        }
                    }
    }
    

    Expected behavior code should read the xlsx file

    opened by tburnt 8
  • Unable to parse excel with following code

    Unable to parse excel with following code

    I am using main branch which i have installed using following pod

    pod 'CoreXLSX'

    I am trying to read one excel but its giving me random integer number instead of string.

    Test12.xlsx

        func getExcelData(pathNew: URL) {
                    
            let k: UInt32 = 10 * 1024 * 1024
            
            guard let file = try? XLSXFile(data: Data(contentsOf: pathNew), bufferSize: k, errorContextLength: 10) else {
                return }
    
            do {
                for wbk in try file.parseWorkbooks() {
                    for (name, path) in try file.parseWorksheetPathsAndNames(workbook: wbk) {
                        if let worksheetName = name {
                            print("This worksheet has a name: \(worksheetName)")
                        }
    
                        
                        let worksheet = try file.parseWorksheet(at: path)
                        
                        let array = worksheet.data?.rows.map { $0.cells.map { $0.value ?? "" } }
                    }
                }
            } catch {
                print(error)
            }
    
    Screenshot 2022-04-15 at 8 46 01 PM
    opened by manish12jain 4
  • Get a dropdown list

    Get a dropdown list

    Hello,

    First of all, thank you for you work, it's amazing.

    I have one question : is it possible to access to a dropdown list ? :

    Capture d’écran 2021-06-11 à 00 17 52

    Thank you again,

    have a good day

    enhancement 
    opened by ALLNDR 1
Releases(0.14.1)
  • 0.14.1(May 6, 2021)

    This is a patch release improving compatibility with different spreadsheet formats.

    Closed issues:

    • Cannot initialize SchemaType from invalid String value extendedProperties (#145)
    • Cannot initialize SchemaType from invalid String value workbookmetadata (#142)

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.14.0(Dec 9, 2020)

    This release improves compatibility with different spreadsheet formats, simplifies cell font and formatting APIs, and drops support for Carthage. Additionally, Xcode 11.3 on macOS is now the oldest supported version for building CoreXLSX.

    Breaking changes:

    Closed issues:

    • Unable to sort columns by intValue (#137)
    • Cannot initialize SchemaType from invalid String value (#136)
    • Odd cell.s value (#134)
    • 0.13.0 not available on Cocoapods (#133)
    • Unable to read xlsx file (#130)
    • Increase speed of parsing? (#127)
    • .xlsx File not opening with XLSXFile() (#125)
    • Getting Data From a specific Worksheet (#124)
    • ArchiveEntryNotFound error (#121)
    • Printing an empty cell? (#118)
    • Handling encrypted spreadsheets? (#101)

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.13.0(Jul 8, 2020)

  • 0.12.0(Jun 26, 2020)

    The is a bugfix release with a breaking change, it makes size and font properties optional on the RichText.Properties type to improve compatibility with certain spreadsheets. Thanks to @Ethan-Chew for reporting this in #116.

    Source code(tar.gz)
    Source code(zip)
  • 0.11.1(Jun 12, 2020)

    This is a bugfix release that resolves an issue with parsing cells that contain time values. Thanks to @mb812 for reporting it!

    Closed issues:

    • Error parsing cells with Time value (#114)
    • file.parseWorksheetPathsAndNames() wanna workbook: <#Workbook#> (#113)
    • XLSXFile not initialising when passing document directory path (#108)

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.11.0(May 30, 2020)

    This is a feature release that enables compatibility with CryptoOffice for decrypting spreadsheets. Additionally, with 0.11.0 you can easily get worksheet names with a new parseWorksheetPathsAndNames function on XLSXFile and get rich text values from cells with a new richStringValue function on Cell.

    Due to technical issues, Swift 5.0 CI job for Linux has been removed, so compatibility with Swift 5.0 on Linux can no longer be guaranteed. While CoreXLSX may continue to work with Swift 5.0 on Linux, please update to Swift 5.1 or later to avoid unexpected issues.

    Thanks to @kobylyanets and @duodo2412 for their contributions to this release!

    New APIs:

    • XLSXFile now provides a new initializer that takes an argument of Data type. This allows opening in-memory documents, the primary example being spreadsheets decrypted with CryptoOffice.

    • XLSXFile now has a new parseWorksheetPathsAndNames function that returns an array of worksheet names and their paths in a given workbook, while previously you had to use parseWorksheetPaths and match paths manually with results of the parseWorkbooks function.

    • Cell now has a richStringValue function that takes a result of the XLSXFile.parseSharedStrings function and produces an array of RichText values. This makes it easier to query rich text content from cells, while previously you had to match cell values against SharedStrings manually.

    Breaking change:

    Due to the introduction of the new XLSXFile.init(data:) initializer, the filepath property on XLSXFile no longer makes sense. This property was not used internally in any way and in-memory files don't have any filepaths. If you need to refer to a filepath of an .xlsx file after you've parsed from your filesystem, you should retain it manually and process it separately as you see fit.

    Closed issues:

    • API for matching sheet names to sheet paths (#105)

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.10.0(Apr 6, 2020)

    This is a release with bugfixes and a few improvements to usability of the spreadsheet cell values API. Thanks to all contributors and users, you provide an invaluable amount of feedback and help!

    New API:

    The library now provides a simplified API to fetch string and date values from cells, which is much easier to use than the previous version (which is still available).

    Here's how you can get all strings (including shared strings) in column "C" for example:

    let sharedStrings = try file.parseSharedStrings()
    let columnCStrings = worksheet.cells(atColumns: [ColumnReference("C")!])
      .compactMap { $0.stringValue(sharedStrings) }
    

    To parse a date value from a cell, use dateValue property on the Cell type:

    let columnCDates = worksheet.cells(atColumns: [ColumnReference("C")!])
      .compactMap { $0.dateValue }
    

    Breaking change:

    The type property on Cell is no longer of String type. It was previously used to check if cell's type is equal to "s", which denoted a shared string. You should use enum values for that since this release, which for shared strings now is (unsurprisingly) .sharedString.

    Closed issues:

    • Xcode 11 installation and build (#90)
    • Reading Date values from cell (#89)
    • Can't open xml (#82)
    • Not able to read Numeric data from Sheet (#81)
    • Getting the value of a cell with number format? (#71)
    • Opening xlsx file Document Directory, Crashes (#52)

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.9.1(Nov 8, 2019)

    This release adds a new value to the Relationship.SchemaType enum, which fixes compatibility with some spreadsheet files. Thanks to @mxcl for the bug report!

    Fixed bugs:

    • Cannot initialize SchemaType from invalid String value #87

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.9.0(Oct 19, 2019)

    This release adds Linux support and improves compatibility with .xlsx files that contain shared strings. Thanks to @CloseServer, @funnel20 and @LiewLi for bug reports and contributions!

    Implemented enhancements:

    • Bump XMLCoder to 0.9.0, add CI jobs for Linux, Xcode 11 #86 (MaxDesiatov)

    Fixed bugs:

    • Multi-line text in an Excel cell is parsed into single line in the SharedStrings property text #83

    Closed issues:

    • I crashed while calling try file.parsesharedstrings() with an error #79

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.8.0(Jul 12, 2019)

    Feature and bugfix release that makes the library compatible with more spreadsheet types. It also adds support for Comments structure, which can be parsed with the new parseComments API.

    Many thanks to @grin, @GoldenJoe and @LiewLi for reporting and fixing issues in this release.

    Closed issues:

    • parseDocumentPaths has internal protection, but is needed by parseDocumentRelationships #74 (GoldenJoe)
    • Missing Documentation #73 (GoldenJoe)

    Merged pull requests:

    Source code(tar.gz)
    Source code(zip)
  • 0.7.0(May 25, 2019)

    Bugfix release that improves compatibility with different spreadsheet types.

    Thanks to @grin for reporting and fixing issues in this release.

    Breaking changes

    All properties on struct Format except fontId and numberFormatId are now optional.

    Additions

    New borderId and fillId properties on struct Format.

    Fixed bugs

    • Can't get cell string #58
    • Can't load basic spreadsheets created in Google Docs #64
    • fillId and borderId attributes missing from CoreXLSX.Format #65

    Merged pull requests

    Source code(tar.gz)
    Source code(zip)
  • 0.6.1(May 9, 2019)

  • 0.6.0(May 2, 2019)

    This is a bugfix release with changes to the model API that improve compatibility with files containing formulas and varied shared strings formats.

    Specifically:

    • new struct Formula added with a corresponding property on struct Cell
    • property color on struct Properties became optional
    • properties on struct RichText became optional
    • new chartsheet case added to enum Relationship
    • richText on struct SharedStrings became an array, not optional

    Closed issues

    • Error Domain=NSCocoaErrorDomain Code=4865 "Expected String but found null instead." #59
    • Importing XLSX file #56
    • Error ParseCellContent #51
    • error parseWorksheet #50
    • Couldn't find end of Start Tag c #37

    Merged pull requests

    Source code(tar.gz)
    Source code(zip)
    CoreXLSX.framework.zip(14.27 MB)
  • 0.5.0(Apr 18, 2019)

    This is a release with API additions and bug fixes.

    This release of CoreXLSX can be integrated as a Swift 5 module if you're using Xcode 10.2, but support for Swift 4.2 and earlier Xcode 10 versions is also maintained.

    Compatibility is improved for big files and files that internally contain namespaced XML. A few other previously reported compatibility issues are now fixed. Many thanks to everyone who reported the issues, the improvements in this release wouldn't be possible without your contribution!

    Breaking changes

    Several properties on the model types became optional when there's no guarantee they are always available in files generated by different apps and tools.

    Additions

    Now you can parse style information from the archive with the new parseStyles() function. Please refer to the Styles model for more details. Please note that not all XLSX files contain style information, so you should be prepared to handle the errors thrown from parseStyles() function in that case.

    Merged pull requests

    Source code(tar.gz)
    Source code(zip)
    CoreXLSX.framework.zip(14.04 MB)
  • 0.4.0(Feb 7, 2019)

    This is a release with API improvements and bug fixes. A big thank you to everyone who provided bug reports and contributions that made this release possible!

    Breaking changes

    • A few properties on the model types were added with cleaner names and better fitting types. Most of the old versions of those properties were kept as deprecated, but you might get some breakage with optionality, where we couldn't find a good deprecation path.

    Additions

    • New parseSharedStrings function on XLSXFile allows you get values of cells with shared string value. Quite frequently those strings are unavailable and are only referenced in the original model types you get with parseWorksheet.

    • Previously when addressing cells and columns you had to use a stringly-typed API. It was also not very convenient for specifying a range of columns. This is now fixed with the new type-safe ColumnReference struct, which conforms to Comparable and Strideable.

    • Following the addition of an error context to XMLCoder, which is the main dependency of CoreXLSX, it is now exposed on struct XLSXFile. Pass a non-zero value to errorContextLength argument (default is 0) of XLSXFile initializer and you'll get a snippet of XML that failed to parse in the debug description of the error value.

    • Additional optional argument bufferSize was added to XLSXFile initializer as a response to previous reports about problems with zip file extraction. The default value is 10 MiB, which seems to be enough in most cases, but you can still try passing a larger value for bigger files if you see that an XML file stops abruptly in the middle of the file. Unfortunately, we haven't found a good way to adjust this value dynamically based on the file size, but please let us know if you did.

    • Support for Carthage was added as well as support for tvOS and watchOS.

    Bugfixes

    Some files that couldn't be previously parsed should now be handled better thanks to fixes in optionality and more properties added to the model types.

    All changes

    Source code(tar.gz)
    Source code(zip)
    CoreXLSX.framework.zip(9.82 MB)
  • 0.3.0(Nov 13, 2018)

    • Improve Worksheet model property naming (#2). Some properties on Worksheet and its descendants had obscure names, most of that is fixed now with old names marked as deprecated.
    Source code(tar.gz)
    Source code(zip)
  • 0.2.3(Nov 12, 2018)

  • 0.2.2(Nov 11, 2018)

  • 0.2.1(Nov 11, 2018)

  • 0.2.0(Nov 11, 2018)

    • Cell by row/column filtering API with worksheetCache (#1) This new API allows users to filter all cells by a row or column reference. To avoid re-parsing of worksheets, a new private worksheetCache property is added on XLSXFile.
    Source code(tar.gz)
    Source code(zip)
  • 0.1.2(Nov 10, 2018)

  • 0.1.1(Nov 10, 2018)

  • 0.1.0(Nov 10, 2018)

Owner
Spreadsheet format support and helper libraries for Swift
null
An RSS, Atom and JSON Feed parser written in Swift

Features Atom RSS 0.90, 0.91, 1.00, 2.00 JSON Namespaces Dublin Core Syndication Content Media RSS iTunes Podcasting Tags Documentation Unit Test Cove

Nuno Dias 1k Jan 7, 2023
Recursive Length Prefix encoding written in Swift

RLPSwift This is a basic Swift implementation of Recursive Length Prefix Encoding, a serialisation method for encoding arbitrarily structured binary d

bitfwd community 22 Oct 6, 2020
Swift wrappers for the tree-sitter incremental parsing system

SwiftTreeSitter Swift wrappers for the tree-sitter incremental parsing system. Remember that tree-sitter has both runtime and per-language dependencie

Chime 153 Dec 8, 2022
WKZombie is a Swift framework for iOS/OSX to navigate within websites and collect data without the need of User Interface or API, also known as Headless browser.

WKZombie WKZombie is an iOS/OSX web-browser without a graphical user interface. It was developed as an experiment in order to familiarize myself with

Mathias Köhnke 1.1k Dec 16, 2022
Excel spreadsheet (XLSX) format parser written in pure Swift

CoreXLSX Excel spreadsheet (XLSX) format parser written in pure Swift CoreXLSX is a library focused on representing the low-level structure of the XML

null 684 Dec 21, 2022
SwiftXLSX - A library focused creating Excel spreadsheet (XLSX) files directly on mobile devices

SwiftXLSX Excel spreadsheet (XLSX) format writer on pure SWIFT. SwiftXLSX is a l

null 19 Dec 13, 2022
Full configurable spreadsheet view user interfaces for iOS applications. With this framework, you can easily create complex layouts like schedule, gantt chart or timetable as if you are using Excel.

kishikawakatsumi/SpreadsheetView has moved! It is being actively maintained at bannzai/SpreadsheetView. This fork was created when the project was mov

Kishikawa Katsumi 34 Sep 26, 2022
Full configurable spreadsheet view user interfaces for iOS applications. With this framework, you can easily create complex layouts like schedule, gantt chart or timetable as if you are using Excel.

kishikawakatsumi/SpreadsheetView has moved! It is being actively maintained at bannzai/SpreadsheetView. This fork was created when the project was mov

Kishikawa Katsumi 34 Sep 26, 2022
null 13 Oct 28, 2022
Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Toto Tvalavadze 31 Nov 22, 2021
A Powerful , Extensible CSS Parser written in pure Swift.

A Powerful , Extensible CSS Parser written in pure Swift. Basic Usage From CSS: #View { "width" : 118; "height" : 120.5; "color1" : "#888888"; "co

null 273 Sep 9, 2022
A Powerful , Extensible CSS Parser written in pure Swift.

A Powerful , Extensible CSS Parser written in pure Swift.

null 273 Sep 9, 2022
A Powerful , Extensible CSS Parser written in pure Swift.

A Powerful , Extensible CSS Parser written in pure Swift. Basic Usage From CSS: #View { "width" : 118; "height" : 120.5; "color1" : "#888888"; "co

null 273 Sep 9, 2022
Spreadsheet CollectionViewLayout in Swift. Fully customizable. 🔶

SwiftSpreadsheet Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Swift 5.0 Inst

Wojtek Kordylewski 637 Dec 30, 2022
Spreadsheet CollectionViewLayout in Swift. Fully customizable. 🔶

SwiftSpreadsheet Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Swift 5.0 Inst

Wojtek Kordylewski 637 Dec 30, 2022
Reusable GridView with excellent performance and customization that can be time table, spreadsheet, paging and more.

GridView GridView can tile the view while reusing it. It has an API like UIKit that works fast. Even when device rotates it smoothly relayout. Appetiz

Kyohei Ito 830 Dec 23, 2022
SwiftSoup: Pure Swift HTML Parser, with best of DOM, CSS, and jquery (Supports Linux, iOS, Mac, tvOS, watchOS)

SwiftSoup is a pure Swift library, cross-platform (macOS, iOS, tvOS, watchOS and Linux!), for working with real-world HTML. It provides a very conveni

Nabil Chatbi 3.7k Jan 6, 2023
SwiftSoup: Pure Swift HTML Parser, with best of DOM, CSS, and jquery (Supports Linux, iOS, Mac, tvOS, watchOS)

SwiftSoup is a pure Swift library, cross-platform (macOS, iOS, tvOS, watchOS and Linux!), for working with real-world HTML. It provides a very conveni

Nabil Chatbi 3.7k Dec 28, 2022
Pure Swift 2.0 S-expression Parser

SwiftExP This is an S-expression parser written in pure Swift 2.0, where pure means without making any necessary usage of Foundation APIs at its core.

Marius Rackwitz 16 Jul 25, 2021
Jay - Pure-Swift JSON parser & formatter. Fully streamable input and output. Linux & OS X ready.

Pure-Swift JSON parser & formatter. Fully streamable input and output. Linux & OS X ready. Replacement for NSJSONSerialization.

Danielle 132 Dec 5, 2021