Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions Sources/YouVersionPlatformCore/Bible/BibleTextNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,32 @@ public class BibleTextNode {
}

func parser(_ parser: XMLParser, foundCharacters string: String) {
let collapsed = string.replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
let core = collapsed.trimmingCharacters(in: .whitespacesAndNewlines)
guard !core.isEmpty else {
guard let current = stack.last else {
return
}
let leadingSpace = string.first?.isWhitespace == true
let trailingSpace = string.last?.isWhitespace == true
var segment = core
if leadingSpace {
segment = " " + segment
}
if trailingSpace {
segment += " "
}
guard let current = stack.last else {

let segment = string.replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
guard !segment.isEmpty else {
return
}

if segment == " " {
guard let previousChild = current.children.last else {
return
}
guard previousChild.type == .span || previousChild.type == .text else {
return
}
}

if let lastChild = current.children.last, lastChild.type == .text {
lastChild.textSegments.append(segment)
let joined = lastChild.textSegments.joined()
let joined = (lastChild.text + segment)
.replacingOccurrences(of: " {2,}", with: " ", options: .regularExpression)
guard !joined.isEmpty else {
return
}
lastChild.textSegments = [joined]
lastChild.text = joined
lastChild.textSegments = joined.isEmpty ? [] : [joined]
} else {
let textNode = BibleTextNode(name: "text")
textNode.textSegments = [segment]
Expand All @@ -148,7 +151,6 @@ public class BibleTextNode {
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
_ = stack.popLast()
}

}
}

Expand Down
49 changes: 49 additions & 0 deletions Tests/YouVersionPlatformCoreTests/BibleTextNodeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,52 @@ func testParse_GenesisIntroContainsText() throws {
let texts = collectTexts(root)
#expect(texts.contains("In the beginning, God created the heavens and the earth."))
}

@Test
func testParse_SpacesBetweenInlineSpansArePreserved() throws {
let html = "<div><span>One</span> <span>Two</span> <span>Three three three</span>.</div>"

let root = try #require(try BibleTextNode.parse(html))
let block = try #require(root.children.first)

let renderedText = collectRenderedText(from: block)
#expect(renderedText == "One Two Three three three.")
}

@Test
func testParse_MixedWhitespaceAndInlineNodesCollapseToSingleSpaces() throws {
let html = "<div> Start <span>middle</span>\n\t <span>end</span> done </div>"

let root = try #require(try BibleTextNode.parse(html))
let block = try #require(root.children.first)

let renderedText = collectRenderedText(from: block)
#expect(renderedText == "Start middle end done")
}

@Test
func testParse_LeadingWhitespaceBeforeFirstChildIsIgnored() throws {
let html = "<div> <span>One</span> <span>Two</span></div>"

let root = try #require(try BibleTextNode.parse(html))
let block = try #require(root.children.first)

let renderedText = collectRenderedText(from: block)
#expect(renderedText == "One Two")
}

private func collectRenderedText(from node: BibleTextNode) -> String {
var text = ""
appendRenderedText(from: node, into: &text)
return text.trimmingCharacters(in: .whitespacesAndNewlines)
}

private func appendRenderedText(from node: BibleTextNode, into text: inout String) {
if node.type == .text {
text += node.text
}

for child in node.children {
appendRenderedText(from: child, into: &text)
}
}