Skip to content

Commit

Permalink
Add SharedStrings model, parse sharedStrings.xml (#8)
Browse files Browse the repository at this point in the history
As reported in #21, there's no obvious way to get values for some values. That's caused by the fact that some of the values are stored in a separate file, which is usually located at the path `sharedStrings.xml`. This can be parsed to a corresponding model type and then processed by users of `CoreXLSX` to get the string values.

* Add SharedStrings model, general cleanup
* Add link to Open XML SDK docs for SharedStrings
* Fix rebase conflicts
* Add public `parseSharedStrings` API with tests
  • Loading branch information
MaxDesiatov authored Dec 3, 2018
1 parent bd48966 commit bffbcd8
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 32 deletions.
56 changes: 35 additions & 21 deletions CoreXLSX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
D150221321A1D97E00BFA4FC /* CoreXLSX.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* CoreXLSX.swift */; };
D150221421A1D97E00BFA4FC /* Relationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* Relationships.swift */; };
D150221521A1D97E00BFA4FC /* Worksheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Worksheet.swift */; };
D1A8190921A9CB89004FCA33 /* WorksheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8190821A9CB89004FCA33 /* WorksheetTests.swift */; };
D1A8190921A9CB89004FCA33 /* Worksheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8190821A9CB89004FCA33 /* Worksheet.swift */; };
D1A8190B21A9D0EF004FCA33 /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8190A21A9D0EF004FCA33 /* Cell.swift */; };
D1A8190D21A9D139004FCA33 /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8190A21A9D0EF004FCA33 /* Cell.swift */; };
D1A8190E21A9D13B004FCA33 /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8190A21A9D0EF004FCA33 /* Cell.swift */; };
Expand All @@ -44,18 +44,23 @@
D1A8191321A9D4F8004FCA33 /* CellQueries.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8191021A9D4ED004FCA33 /* CellQueries.swift */; };
D1A8191421A9D4F8004FCA33 /* CellQueries.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A8191021A9D4ED004FCA33 /* CellQueries.swift */; };
D1C96B8021A806A500303975 /* Workbook.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C96B7F21A806A500303975 /* Workbook.swift */; };
D1C96B8321A80EC000303975 /* WorkbookTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C96B8121A80E5900303975 /* WorkbookTests.swift */; };
D1C96B8321A80EC000303975 /* Workbook.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C96B8121A80E5900303975 /* Workbook.swift */; };
D1EB1B3421B151440043CD1E /* SharedStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1EB1B3321B151440043CD1E /* SharedStrings.swift */; };
D1EB9C6C21A98FFE002F2254 /* Workbook.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C96B7F21A806A500303975 /* Workbook.swift */; };
D1EB9C6D21A98FFE002F2254 /* Workbook.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C96B7F21A806A500303975 /* Workbook.swift */; };
D1EB9C6E21A98FFE002F2254 /* Workbook.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C96B7F21A806A500303975 /* Workbook.swift */; };
D1FD863E21A1F09E00B7F8D6 /* SharedStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FD863D21A1F09E00B7F8D6 /* SharedStrings.swift */; };
D1FD863F21A1F09E00B7F8D6 /* SharedStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FD863D21A1F09E00B7F8D6 /* SharedStrings.swift */; };
D1FD864021A1F09E00B7F8D6 /* SharedStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FD863D21A1F09E00B7F8D6 /* SharedStrings.swift */; };
D1FD864121A1F09E00B7F8D6 /* SharedStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FD863D21A1F09E00B7F8D6 /* SharedStrings.swift */; };
OBJ_62 /* CellReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* CellReference.swift */; };
OBJ_63 /* ColumnReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* ColumnReference.swift */; };
OBJ_64 /* CoreXLSX.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* CoreXLSX.swift */; };
OBJ_65 /* Relationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* Relationships.swift */; };
OBJ_66 /* Worksheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Worksheet.swift */; };
OBJ_90 /* CellReferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* CellReferenceTests.swift */; };
OBJ_91 /* CoreXLSXTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* CoreXLSXTests.swift */; };
OBJ_92 /* RelationshipsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* RelationshipsTests.swift */; };
OBJ_90 /* CellReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* CellReference.swift */; };
OBJ_91 /* CoreXLSX.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* CoreXLSX.swift */; };
OBJ_92 /* Relationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* Relationships.swift */; };
OBJ_93 /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* XCTestManifests.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -103,19 +108,21 @@
D150220521A1D8DC00BFA4FC /* CoreXLSX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreXLSX.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D150220D21A1D95400BFA4FC /* XMLCoder.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XMLCoder.framework; path = Carthage/Build/watchOS/XMLCoder.framework; sourceTree = "<group>"; };
D150220E21A1D95400BFA4FC /* ZIPFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZIPFoundation.framework; path = Carthage/Build/watchOS/ZIPFoundation.framework; sourceTree = "<group>"; };
D1A8190821A9CB89004FCA33 /* WorksheetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorksheetTests.swift; sourceTree = "<group>"; };
D1A8190821A9CB89004FCA33 /* Worksheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Worksheet.swift; sourceTree = "<group>"; };
D1A8190A21A9D0EF004FCA33 /* Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = "<group>"; };
D1A8191021A9D4ED004FCA33 /* CellQueries.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellQueries.swift; sourceTree = "<group>"; };
D1C96B7F21A806A500303975 /* Workbook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workbook.swift; sourceTree = "<group>"; };
D1C96B8121A80E5900303975 /* WorkbookTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkbookTests.swift; sourceTree = "<group>"; };
D1C96B8121A80E5900303975 /* Workbook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workbook.swift; sourceTree = "<group>"; };
D1EB1B3321B151440043CD1E /* SharedStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedStrings.swift; sourceTree = "<group>"; };
D1FD863D21A1F09E00B7F8D6 /* SharedStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedStrings.swift; sourceTree = "<group>"; };
OBJ_11 /* CellReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellReference.swift; sourceTree = "<group>"; };
OBJ_12 /* ColumnReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColumnReference.swift; sourceTree = "<group>"; };
OBJ_13 /* CoreXLSX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreXLSX.swift; sourceTree = "<group>"; };
OBJ_14 /* Relationships.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Relationships.swift; sourceTree = "<group>"; };
OBJ_15 /* Worksheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Worksheet.swift; sourceTree = "<group>"; };
OBJ_18 /* CellReferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellReferenceTests.swift; sourceTree = "<group>"; };
OBJ_19 /* CoreXLSXTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreXLSXTests.swift; sourceTree = "<group>"; };
OBJ_20 /* RelationshipsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationshipsTests.swift; sourceTree = "<group>"; };
OBJ_18 /* CellReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellReference.swift; sourceTree = "<group>"; };
OBJ_19 /* CoreXLSX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreXLSX.swift; sourceTree = "<group>"; };
OBJ_20 /* Relationships.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Relationships.swift; sourceTree = "<group>"; };
OBJ_21 /* XCTestManifests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestManifests.swift; sourceTree = "<group>"; };
OBJ_27 /* Archive+Reading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Archive+Reading.swift"; sourceTree = "<group>"; };
OBJ_28 /* Archive+Writing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Archive+Writing.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -243,9 +250,9 @@
children = (
OBJ_11 /* CellReference.swift */,
OBJ_12 /* ColumnReference.swift */,
OBJ_15 /* Worksheet.swift */,
D1A8190A21A9D0EF004FCA33 /* Cell.swift */,
D1A8191021A9D4ED004FCA33 /* CellQueries.swift */,
OBJ_15 /* Worksheet.swift */,
);
path = Worksheet;
sourceTree = "<group>";
Expand All @@ -257,6 +264,7 @@
OBJ_13 /* CoreXLSX.swift */,
OBJ_14 /* Relationships.swift */,
D1C96B7F21A806A500303975 /* Workbook.swift */,
D1FD863D21A1F09E00B7F8D6 /* SharedStrings.swift */,
);
name = CoreXLSX;
path = Sources/CoreXLSX;
Expand All @@ -273,12 +281,13 @@
OBJ_17 /* CoreXLSXTests */ = {
isa = PBXGroup;
children = (
OBJ_18 /* CellReferenceTests.swift */,
OBJ_19 /* CoreXLSXTests.swift */,
OBJ_20 /* RelationshipsTests.swift */,
OBJ_18 /* CellReference.swift */,
OBJ_19 /* CoreXLSX.swift */,
OBJ_20 /* Relationships.swift */,
OBJ_21 /* XCTestManifests.swift */,
D1C96B8121A80E5900303975 /* WorkbookTests.swift */,
D1A8190821A9CB89004FCA33 /* WorksheetTests.swift */,
D1C96B8121A80E5900303975 /* Workbook.swift */,
D1A8190821A9CB89004FCA33 /* Worksheet.swift */,
D1EB1B3321B151440043CD1E /* SharedStrings.swift */,
);
name = CoreXLSXTests;
path = Tests/CoreXLSXTests;
Expand Down Expand Up @@ -596,6 +605,7 @@
buildActionMask = 2147483647;
files = (
D15021E121A1CB0500BFA4FC /* CoreXLSX.swift in Sources */,
D1FD863F21A1F09E00B7F8D6 /* SharedStrings.swift in Sources */,
D15021DF21A1CB0500BFA4FC /* CellReference.swift in Sources */,
D1A8191221A9D4F7004FCA33 /* CellQueries.swift in Sources */,
D1A8190D21A9D139004FCA33 /* Cell.swift in Sources */,
Expand All @@ -611,6 +621,7 @@
buildActionMask = 2147483647;
files = (
D15021FD21A1D1DB00BFA4FC /* CoreXLSX.swift in Sources */,
D1FD864021A1F09E00B7F8D6 /* SharedStrings.swift in Sources */,
D15021FB21A1D1DB00BFA4FC /* CellReference.swift in Sources */,
D1A8191321A9D4F8004FCA33 /* CellQueries.swift in Sources */,
D1A8190E21A9D13B004FCA33 /* Cell.swift in Sources */,
Expand All @@ -626,6 +637,7 @@
buildActionMask = 2147483647;
files = (
D150221321A1D97E00BFA4FC /* CoreXLSX.swift in Sources */,
D1FD864121A1F09E00B7F8D6 /* SharedStrings.swift in Sources */,
D150221121A1D97E00BFA4FC /* CellReference.swift in Sources */,
D1A8191421A9D4F8004FCA33 /* CellQueries.swift in Sources */,
D1A8190F21A9D13B004FCA33 /* Cell.swift in Sources */,
Expand All @@ -641,6 +653,7 @@
buildActionMask = 0;
files = (
OBJ_62 /* CellReference.swift in Sources */,
D1FD863E21A1F09E00B7F8D6 /* SharedStrings.swift in Sources */,
OBJ_63 /* ColumnReference.swift in Sources */,
D1A8191121A9D4ED004FCA33 /* CellQueries.swift in Sources */,
D1A8190B21A9D0EF004FCA33 /* Cell.swift in Sources */,
Expand All @@ -655,11 +668,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 0;
files = (
D1C96B8321A80EC000303975 /* WorkbookTests.swift in Sources */,
OBJ_90 /* CellReferenceTests.swift in Sources */,
D1A8190921A9CB89004FCA33 /* WorksheetTests.swift in Sources */,
OBJ_91 /* CoreXLSXTests.swift in Sources */,
OBJ_92 /* RelationshipsTests.swift in Sources */,
D1C96B8321A80EC000303975 /* Workbook.swift in Sources */,
OBJ_90 /* CellReference.swift in Sources */,
D1EB1B3421B151440043CD1E /* SharedStrings.swift in Sources */,
D1A8190921A9CB89004FCA33 /* Worksheet.swift in Sources */,
OBJ_91 /* CoreXLSX.swift in Sources */,
OBJ_92 /* Relationships.swift in Sources */,
OBJ_93 /* XCTestManifests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
13 changes: 13 additions & 0 deletions Sources/CoreXLSX/CoreXLSX.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
//
// CoreXLSX.swift
// CoreXLSX
//
// Created by Max Desiatov on 27/10/2018.
//

import Foundation
import ZIPFoundation
import XMLCoder
Expand Down Expand Up @@ -53,6 +60,12 @@ public struct XLSXFile {
.map { $0.target }
}

public func parseSharedStrings() throws -> SharedStrings {
decoder.keyDecodingStrategy = .useDefaultKeys

return try parseEntry("xl/sharedStrings.xml", SharedStrings.self)
}

public func parseWorkbooks() throws -> [Workbook] {
let paths = try parseDocumentPaths()

Expand Down
2 changes: 0 additions & 2 deletions Sources/CoreXLSX/Relationships.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// Created by Max Desiatov on 27/10/2018.
//

import Foundation

struct Relationships: Codable {
let items: [Relationship]

Expand Down
85 changes: 85 additions & 0 deletions Sources/CoreXLSX/SharedStrings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// SharedStrings.swift
// CoreXLSX
//
// Created by Max Desiatov on 18/11/2018.
//

/// Attributes and nodes are documented at this url:
/// https://docs.microsoft.com/en-us/office/open-xml/working-with-the-shared-string-table
public struct SharedStrings: Codable, Equatable {
public struct Item: Codable, Equatable {
public let text: String?
public let richText: RichText?

enum CodingKeys: String, CodingKey {
case text = "t"
case richText = "r"
}
}

public let uniqueCount: UInt
public let items: [Item]

enum CodingKeys: String, CodingKey {
case items = "si"
case uniqueCount
}
}

public struct RichText: Codable, Equatable {
public struct Family: Codable, Equatable {
public let value: String

enum CodingKeys: String, CodingKey {
case value = "val"
}
}

public struct Scheme: Codable, Equatable {
public let value: String

enum CodingKeys: String, CodingKey {
case value = "val"
}
}

public struct Size: Codable, Equatable {
public let value: String

enum CodingKeys: String, CodingKey {
case value = "val"
}
}

public struct Color: Codable, Equatable {
let theme: String?
let rgb: String?
}

public struct Font: Codable, Equatable {
public let value: String

enum CodingKeys: String, CodingKey {
case value = "val"
}
}

public struct Properties: Codable, Equatable {
public let size: Size
public let color: Color
public let font: Font
public let family: Family
public let scheme: Scheme

enum CodingKeys: String, CodingKey {
case size = "sz"
case color
case font = "rFont"
case family
case scheme
}
}

public let properties: Properties
}
2 changes: 0 additions & 2 deletions Sources/CoreXLSX/Worksheet/Worksheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// Created by Max Desiatov on 31/10/2018.
//

import Foundation

@available(*, deprecated, renamed: "Worksheet.Data")
public typealias SheetData = Worksheet.Data

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// CellReferenceTests.swift
// CellReference.swift
// CoreXLSXTests
//
// Created by Max Desiatov on 15/11/2018.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
//
// CoreXLSX.swift
// CoreXLSXTests
//
// Created by Max Desiatov on 27/10/2018.
//

import XCTest
@testable import CoreXLSX

let currentWorkingPath = ProcessInfo.processInfo.environment["TESTS_PATH"]!

final class XLSXReaderTests: XCTestCase {
let sheetPath = "xl/worksheets/sheet1.xml"
final class CoreXLSXTests: XCTestCase {
private let sheetPath = "xl/worksheets/sheet1.xml"

func testPublicAPI() {
do {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// RelationshipsTests.swift
// Relationships.swift
// CoreXLSXTests
//
// Created by Max Desiatov on 15/11/2018.
Expand Down
62 changes: 62 additions & 0 deletions Tests/CoreXLSXTests/SharedStrings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// SharedStrings.swift
// CoreXLSXTests
//
// Created by Max Desiatov on 30/11/2018.
//

import XCTest
import XMLCoder
@testable import CoreXLSX

private let parsed = SharedStrings(uniqueCount: 18, items: [
SharedStrings.Item(text: "Table 1", richText: nil),
SharedStrings.Item(text: "Item", richText: nil),
SharedStrings.Item(text: "Name", richText: nil),
SharedStrings.Item(text: "Amount", richText: nil),
SharedStrings.Item(text: "Name:", richText: nil),
SharedStrings.Item(text: "Subtotal:", richText: nil),
SharedStrings.Item(text: "Andy", richText: nil),
SharedStrings.Item(text: "Item 1", richText: nil),
SharedStrings.Item(text: "Item 2", richText: nil),
SharedStrings.Item(text: "Item 3", richText: nil),
SharedStrings.Item(text: "Item 4", richText: nil),
SharedStrings.Item(text: "Item 5", richText: nil),
SharedStrings.Item(text: "Chloe", richText: nil),
SharedStrings.Item(text: "Item 6", richText: nil),
SharedStrings.Item(text: "Item 7", richText: nil),
SharedStrings.Item(text: "Item 8", richText: nil),
SharedStrings.Item(text: "Item 9", richText: nil),
SharedStrings.Item(text: "Item 10", richText: nil),
]
)


final class SharedStringsTests: XCTestCase {
func testSharedStrings() {
do {
guard let file =
XLSXFile(filepath: "\(currentWorkingPath)/categories.xlsx") else {
XCTAssert(false, "failed to open the file")
return
}

let sharedStrings = try file.parseSharedStrings()

// check each individual item so that it's easier to debug when something
// goes wrong
for (i, item) in sharedStrings.items.enumerated() {
XCTAssertEqual(item, parsed.items[i])
}

// check the complete value anyway to make sure all properties are equal
XCTAssertEqual(sharedStrings, parsed)
} catch {
XCTAssert(false, "unexpected error \(error)")
}
}

static let allTests = [
("testSharedStrings", testSharedStrings),
]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// WorkbookTests.swift
// CoreXLSXmacOS
// Workbook.swift
// CoreXLSXTests
//
// Created by Max Desiatov on 23/11/2018.
//
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// WorksheetTests.swift
// Worksheet.swift
// CoreXLSXTests
//
// Created by Max Desiatov on 24/11/2018.
Expand Down

0 comments on commit bffbcd8

Please sign in to comment.