From 5a94b1d967c8b5d812c5b0f1cd4a34cd735dcf3e Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 28 Nov 2020 22:16:08 +0000 Subject: [PATCH 1/3] Add `font(in:)` and `format(in:)` functions --- CoreXLSX.xcodeproj/project.pbxproj | 6 ++++++ README.md | 9 +++++++++ Sources/CoreXLSX/Worksheet/Cell.swift | 9 ++------- Sources/CoreXLSX/Worksheet/CellQueries.swift | 12 ++++++++++++ Sources/CoreXLSX/XLSXFile.swift | 2 +- Tests/CoreXLSXTests/CellQueries.swift | 20 ++++++++++---------- Tests/CoreXLSXTests/CellReference.swift | 16 ++++++++-------- Tests/CoreXLSXTests/Styles.swift | 9 +++++++++ Tests/CoreXLSXTests/XLSXFile.swift | 3 +++ 9 files changed, 60 insertions(+), 26 deletions(-) diff --git a/CoreXLSX.xcodeproj/project.pbxproj b/CoreXLSX.xcodeproj/project.pbxproj index cfdc36ee..9a8126a3 100644 --- a/CoreXLSX.xcodeproj/project.pbxproj +++ b/CoreXLSX.xcodeproj/project.pbxproj @@ -480,6 +480,12 @@ attributes = { LastUpgradeCheck = 9999; TargetAttributes = { + "CoreXLSX::CoreXLSX" = { + LastSwiftMigration = 1220; + }; + "CoreXLSX::CoreXLSXTests" = { + LastSwiftMigration = 1220; + }; D15021D021A1CA7D00BFA4FC = { CreatedOnToolsVersion = 10.1; }; diff --git a/README.md b/README.md index 718e9afe..62431c05 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,15 @@ 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`: + +```swift +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 diff --git a/Sources/CoreXLSX/Worksheet/Cell.swift b/Sources/CoreXLSX/Worksheet/Cell.swift index 6747daea..e3b53762 100644 --- a/Sources/CoreXLSX/Worksheet/Cell.swift +++ b/Sources/CoreXLSX/Worksheet/Cell.swift @@ -36,12 +36,7 @@ public enum CellType: String, Codable { public struct Cell: Codable, Equatable { public let reference: CellReference public let type: CellType? - - // FIXME: Attribute "s" in a cell is an index into the styles table, - // while the cell type "s" corresponds to the shared string table. - // Can XMLCoder distinguish between an attribute and an - // element having the same name? - public let s: String? + public let styleIndex: Int? /** Not every string in a cell is an inline string. You should use `stringValue(_: SharedStrings)` on the `Cell` type, supplying it the result of `parseSharedStrings()` called on your `XLSXFile` @@ -68,6 +63,6 @@ public struct Cell: Codable, Equatable { case inlineString = "is" case reference = "r" case type = "t" - case s + case styleIndex = "s" } } diff --git a/Sources/CoreXLSX/Worksheet/CellQueries.swift b/Sources/CoreXLSX/Worksheet/CellQueries.swift index 28f8cdd8..c5898e7f 100644 --- a/Sources/CoreXLSX/Worksheet/CellQueries.swift +++ b/Sources/CoreXLSX/Worksheet/CellQueries.swift @@ -105,4 +105,16 @@ public extension Cell { return referenceCalendar.date(byAdding: .second, value: seconds, to: addedDays) } + + func format(in styles: Styles) -> Format? { + guard let styleIndex = styleIndex else { return nil } + + return styles.cellFormats?.items[styleIndex] + } + + func font(in styles: Styles) -> Font? { + guard let fontID = format(in: styles)?.fontId else { return nil } + + return styles.fonts?.items[fontID] + } } diff --git a/Sources/CoreXLSX/XLSXFile.swift b/Sources/CoreXLSX/XLSXFile.swift index 848de01a..29ea31d4 100644 --- a/Sources/CoreXLSX/XLSXFile.swift +++ b/Sources/CoreXLSX/XLSXFile.swift @@ -154,7 +154,7 @@ public class XLSXFile { let range = NSRange(location: 0, length: path.utf16.count) if let match = regex.firstMatch(in: path, options: [], range: range), - let worksheetIdRange = Range(match.range(at: 1), in: path) + let worksheetIdRange = Range(match.range(at: 1), in: path) { let worksheetId = path[worksheetIdRange] return "xl/comments\(worksheetId).xml" diff --git a/Tests/CoreXLSXTests/CellQueries.swift b/Tests/CoreXLSXTests/CellQueries.swift index 6f5b58a1..cb9d1dad 100644 --- a/Tests/CoreXLSXTests/CellQueries.swift +++ b/Tests/CoreXLSXTests/CellQueries.swift @@ -25,7 +25,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("I")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.39583333333212067" @@ -33,7 +33,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("J")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.54166666666787933" @@ -41,7 +41,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("K")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.625" @@ -49,7 +49,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("L")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.8125" @@ -57,7 +57,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("O")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.625" @@ -65,7 +65,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("P")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.75" @@ -73,7 +73,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("U")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.33333333333212067" @@ -81,7 +81,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("V")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.45833333333212067" @@ -89,7 +89,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("Y")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.33333333333212067" @@ -97,7 +97,7 @@ final class CellQueriesTests: XCTestCase { Cell( reference: CellReference(ColumnReference("Z")!, 2), type: nil, - s: Optional("7"), + styleIndex: 7, inlineString: nil, formula: nil, value: "0.45833333333212067" diff --git a/Tests/CoreXLSXTests/CellReference.swift b/Tests/CoreXLSXTests/CellReference.swift index 85b9c82d..e1f14ad5 100644 --- a/Tests/CoreXLSXTests/CellReference.swift +++ b/Tests/CoreXLSXTests/CellReference.swift @@ -43,7 +43,7 @@ final class CellReferenceTests: XCTestCase { c1, Cell( reference: cr1, - type: nil, s: nil, inlineString: nil, formula: nil, + type: nil, styleIndex: nil, inlineString: nil, formula: nil, value: nil ) ) @@ -58,7 +58,7 @@ final class CellReferenceTests: XCTestCase { c2, Cell( reference: cr2, - type: nil, s: nil, inlineString: nil, formula: nil, + type: nil, styleIndex: nil, inlineString: nil, formula: nil, value: nil ) ) @@ -89,8 +89,8 @@ final class CellReferenceTests: XCTestCase { func testColumnReferenceDistance() { guard let a = ColumnReference("A"), let z = ColumnReference("z"), - let aa = ColumnReference("AA"), let az = ColumnReference("Az"), - let ba = ColumnReference("ba"), let bz = ColumnReference("bz") + let aa = ColumnReference("AA"), let az = ColumnReference("Az"), + let ba = ColumnReference("ba"), let bz = ColumnReference("bz") else { XCTFail("failed to create simple column references") return @@ -111,10 +111,10 @@ final class CellReferenceTests: XCTestCase { func testColumnReferenceIntInitializer() { guard let a = ColumnReference("A"), let z = ColumnReference("z"), - let aa = ColumnReference("AA"), let az = ColumnReference("Az"), - let ba = ColumnReference("ba"), let bz = ColumnReference("bz"), - let abc = ColumnReference("abc"), let azz = ColumnReference("azz"), - let zz = ColumnReference("zz"), let azza = ColumnReference("azza") + let aa = ColumnReference("AA"), let az = ColumnReference("Az"), + let ba = ColumnReference("ba"), let bz = ColumnReference("bz"), + let abc = ColumnReference("abc"), let azz = ColumnReference("azz"), + let zz = ColumnReference("zz"), let azza = ColumnReference("azza") else { XCTFail("failed to create simple column references") return diff --git a/Tests/CoreXLSXTests/Styles.swift b/Tests/CoreXLSXTests/Styles.swift index 0abc3188..543f5d64 100644 --- a/Tests/CoreXLSXTests/Styles.swift +++ b/Tests/CoreXLSXTests/Styles.swift @@ -106,5 +106,14 @@ final class StylesTests: XCTestCase { XCTAssertEqual(styles.differentialFormats!.count, 0) XCTAssertEqual(styles.tableStyles!.count, 0) XCTAssertEqual(styles.colors!.indexed.rgbColors.count, 14) + + let ws = try file.parseWorksheet(at: file.parseWorksheetPaths()[0]) + guard let sd = ws.data else { + XCTFail("no sheet data available") + return + } + + XCTAssertEqual(sd.rows.first?.cells.first?.font(in: styles)?.size?.value, 12) + XCTAssertEqual(sd.rows.last?.cells.first?.font(in: styles)?.size?.value, 10) } } diff --git a/Tests/CoreXLSXTests/XLSXFile.swift b/Tests/CoreXLSXTests/XLSXFile.swift index b8bcc999..895ea6be 100644 --- a/Tests/CoreXLSXTests/XLSXFile.swift +++ b/Tests/CoreXLSXTests/XLSXFile.swift @@ -44,6 +44,9 @@ final class CoreXLSXTests: XCTestCase { let ws = try file.parseWorksheet(at: "xl/worksheets/sheet1.xml") XCTAssertEqual(ws.data?.rows.count, 1) + + let cell = ws.data?.rows.first?.cells.first + XCTAssertEqual(cell?.font(in: styles)?.size, nil) } func testMultiline() throws { From e4ddfa2f7149b9239cd01e9de4aab65d30a3c891 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 28 Nov 2020 22:36:49 +0000 Subject: [PATCH 2/3] Update azure-pipelines.yml --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 67a3eeee..b40726da 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -99,7 +99,7 @@ jobs: - bash: ./test_xcodebuild.sh Xcode_11.7 env: IOS_DEVICE: "platform=iOS Simulator,OS=13.7,name=iPhone 8" - TVOS_DEVICE: "platform=tvOS Simulator,OS=13.4,name=Apple TV 4K" + TVOS_DEVICE: "platform=tvOS Simulator,OS=13.4.1,name=Apple TV 4K" CODECOV_JOB: "true" CODECOV_TOKEN: $(codecovToken) - job: test_swiftpm From 158076b9ac40fdbac6b603709fc0f1c539f51d2c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 28 Nov 2020 22:53:05 +0000 Subject: [PATCH 3/3] Update azure-pipelines.yml --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b40726da..4d9256a9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -74,7 +74,7 @@ jobs: steps: - bash: ./test_xcodebuild.sh Xcode_11.4 env: - IOS_DEVICE: "platform=iOS Simulator,OS=13.4,name=iPhone 8" + IOS_DEVICE: "platform=iOS Simulator,OS=13.4.1,name=iPhone 8" TVOS_DEVICE: "platform=tvOS Simulator,OS=13.4,name=Apple TV 4K" - job: test_xcodebuild_11_5 pool: @@ -99,7 +99,7 @@ jobs: - bash: ./test_xcodebuild.sh Xcode_11.7 env: IOS_DEVICE: "platform=iOS Simulator,OS=13.7,name=iPhone 8" - TVOS_DEVICE: "platform=tvOS Simulator,OS=13.4.1,name=Apple TV 4K" + TVOS_DEVICE: "platform=tvOS Simulator,OS=13.4,name=Apple TV 4K" CODECOV_JOB: "true" CODECOV_TOKEN: $(codecovToken) - job: test_swiftpm