Repository: CoreOffice/CoreXLSX (swift)

Issue:
Odd cell.s value 
**Version**

0.13.0

**Description of the bug**

When querying a cell's "s" value, cell.s, defined in the documentation as 
```swift
  // 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?
```

Then querying the styles table as: 
```swift
let styles = file.parseStyles() 
styles.cellStyles[Int(cell.s)]

//or 

styles.cellStyles?.items.first(where: {$0.builtinId == Int(cell.s ?? "") || $0.formatId == Int(cell.s ?? "")})

```
offers index out of range or nil in each respectively.


**Expected behavior**

I expected the cellsStyle table with index of cell.s to be the style sought.

Pull request:
Resolve #134

Patch:
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/azure-pipelines.yml b/azure-pipelines.yml
index 67a3eeee..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:


Test patch:
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 {