diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 0d2437de..a9710354 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -275,9 +275,14 @@ extension XMLKeyedDecodingContainer { } // If we are looking at a coding key value intrinsic where the expected type is `String` and - // the value is empty, return `""`. + // the value is empty, return CDATA if present otherwise `""`. if strategy(key) != .attribute, elements.isEmpty, attributes.isEmpty, type == String.self, key.stringValue == "", let emptyString = "" as? T { - return emptyString + let cdata = container.withShared { keyedBox in + keyedBox.elements["#CDATA"].map { + return ($0 as? KeyedBox)?.value ?? $0 + } + }.first + return ((cdata as? StringBox)?.unboxed as? T) ?? emptyString } switch strategy(key) { diff --git a/Tests/XMLCoderTests/CDATAMixedUsageTest.swift b/Tests/XMLCoderTests/CDATAMixedUsageTest.swift new file mode 100644 index 00000000..1d55bcf2 --- /dev/null +++ b/Tests/XMLCoderTests/CDATAMixedUsageTest.swift @@ -0,0 +1,36 @@ +// +// CDATAMixedUsageTest.swift +// XMLCoderTests +// +// Created by Johan Kool on 15/03/2023. +// + +import XCTest +import XMLCoder + +final class CDATAMixedUsageTest: XCTestCase { + private struct DataEntry: Codable, Equatable { + let value: String + enum CodingKeys: String, CodingKey { + case value = "" + } + } + + private struct Container: Codable, Equatable { + let data: [DataEntry] + } + + private let xml = + """ + + + bla bla + + """.data(using: .utf8)! + + func testXMLWithMixedCDATAUsage() throws { + let decoder = XMLDecoder() + let result = try decoder.decode(Container.self, from: xml) + XCTAssertEqual(result, Container(data: [.init(value: "lorem ipsum"), .init(value: "bla bla")])) + } +} diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 06ebbd00..2f8404d5 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ B5647C4824897589001F6507 /* Element.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5647C4724897589001F6507 /* Element.swift */; }; B5E67535238B4960006C8548 /* IntOrString.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E67534238B4960006C8548 /* IntOrString.swift */; }; B5F74472233F74E400BBDB15 /* RootLevelAttributeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */; }; + C7D23FB529C23A5F00CAD394 /* CDATAMixedUsageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D23FB429C23A5F00CAD394 /* CDATAMixedUsageTest.swift */; }; D11E094623491BCE00C24DCB /* DoubleBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = D11E094523491BCE00C24DCB /* DoubleBox.swift */; }; D11E094A234924C500C24DCB /* ValueBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = D11E0949234924C500C24DCB /* ValueBox.swift */; }; D18FBFB82348FAE500FA4F65 /* EscapedCharactersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D18FBFB72348FAE500FA4F65 /* EscapedCharactersTest.swift */; }; @@ -184,6 +185,7 @@ B5647C4724897589001F6507 /* Element.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Element.swift; sourceTree = ""; }; B5E67534238B4960006C8548 /* IntOrString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntOrString.swift; sourceTree = ""; }; B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootLevelAttributeTest.swift; sourceTree = ""; }; + C7D23FB429C23A5F00CAD394 /* CDATAMixedUsageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CDATAMixedUsageTest.swift; sourceTree = ""; }; D11E094523491BCE00C24DCB /* DoubleBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleBox.swift; sourceTree = ""; }; D11E0949234924C500C24DCB /* ValueBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueBox.swift; sourceTree = ""; }; D18FBFB72348FAE500FA4F65 /* EscapedCharactersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EscapedCharactersTest.swift; sourceTree = ""; }; @@ -500,6 +502,7 @@ D1A1838724842D710058E66D /* AdvancedFeatures */, D1A1839324842D710058E66D /* EndToEnd */, D1A1838324842C920058E66D /* CDATATest.swift */, + C7D23FB429C23A5F00CAD394 /* CDATAMixedUsageTest.swift */, D1A1838024842C7D0058E66D /* PrettyPrintTest.swift */, OBJ_68 /* BenchmarkTests.swift */, OBJ_88 /* ClassTests.swift */, @@ -833,6 +836,7 @@ D1A183C324842DE80058E66D /* AttributedIntrinsicTest.swift in Sources */, D1A183C424842DE80058E66D /* MixedChoiceAndNonChoiceTests.swift in Sources */, OBJ_256 /* URLTests.swift in Sources */, + C7D23FB529C23A5F00CAD394 /* CDATAMixedUsageTest.swift in Sources */, OBJ_257 /* UnkeyedIntTests.swift in Sources */, D1A183B824842DE20058E66D /* CDTest.swift in Sources */, OBJ_258 /* UnkeyedTests.swift in Sources */,