Explore decoding not just JSON but also CSV, XML, Plist, and YAML using Codable is interesting because developers often work with diverse data formats beyond JSON. While Codable is primarily designed for JSON, showcasing how to extend its functionality to handle other formats efficiently can help developers streamline their data parsing workflow.
In this post, we will build an iOS sample app that will present how to parse codable data text format in JSON, CSV, XML, Plist and Yaml.
JSON
JSON (JavaScript Object Notation) is a lightweight data format used for storing and exchanging data in a human-readable and structured way. It is widely used because of its simplicity, readability, and compatibility with various programming languages. JSON represents data as key-value pairs, similar to a JavaScript object, making it easy to parse and generate. It is commonly used in web APIs, configurations, and data storage due to its efficiency, flexibility, and seamless integration with modern web technologies.
Parsing code is implemented along with with its presentation:
struct JSONView: View {
@State private var people: [Person] = []
func loadPeople() {
let json = """
[
{"name": "Juan", "age": 30},
{"name": "Ana", "age": 25},
{"name": "Carlos", "age": 35}
]
"""
let data = Data(json.utf8)
do {
let decodedPeople = try JSONDecoder().decode([Person].self, from: data)
self.people = decodedPeople
} catch {
print("\(error)")
}
}
var body: some View {
NavigationView {
PeopleListView(people: people)
.navigationTitle("Persons List (JSON)")
}
.task {
loadPeople()
}
}
}
This SwiftUI code defines a JSONView
struct that loads and displays a list of people from a hardcoded JSON string. The loadPeople()
function decodes the JSON into an array of Person
objects and assigns it to the @State
variable people
. The body
property presents a NavigationView
containing a PeopleListView
, passing the people
array to it. The .task
modifier ensures loadPeople()
runs asynchronously when the view appears, populating the list.
XML
XML (Extensible Markup Language) is a structured text format used to store and transport data in a human-readable and machine-readable way. It organizes data using custom tags that define elements hierarchically, making it widely used for data exchange between systems. XML is closely related to SOAP (Simple Object Access Protocol), as SOAP messages are formatted using XML. SOAP is a protocol for exchanging structured information in web services, relying on XML to define message structure, including headers and body content. This enables platform-independent communication between applications over protocols like HTTP and SMTP.
XML is not supperted natively, so we have to import an SPM package such as SWXMLHash:

Code for parsing and presenting:
struct XMLView: View {
@State private var people: [Person] = []
func loadPeople() {
let xmlString = """
<Persons>
<Person>
<Name>Teresa</Name>
<Age>35</Age>
</Person>
<Person>
<Name>Ana</Name>
<Age>45</Age>
</Person>
<Person>
<Name>Carlos</Name>
<Age>35</Age>
</Person>
</Persons>
"""
let xml = XMLHash.config { _ in }.parse(xmlString)
do {
let fetchedPeople: [Person] = try xml["Persons"].children.map { element in
let name: String = try element["Name"].value() ?? ""
let age: Int = try element["Age"].value() ?? -1
return Person(name: name, age: age)
}
people = fetchedPeople
} catch {
print("Error decoding XML: \(error)")
}
}
var body: some View {
NavigationView {
PeopleListView(people: people)
.navigationTitle("Persons List (XML)")
}
.task {
loadPeople()
}
}
}
The XMLView
SwiftUI struct parses an XML string containing a list of people and displays them in a PeopleListView
. It defines a @State
variable people
to store the parsed data and a loadPeople()
function that uses the XMLHash
library to extract names and ages from the XML. The parsed data is then stored in people
, which updates the UI. The body
consists of a NavigationView
that displays PeopleListView
, and loadPeople()
is called asynchronously using .task {}
when the view appears. This setup ensures that the list is populated dynamically from the XML data.
CSV
CSV (Comma-Separated Values) is a widely used data text file format because it is simple, lightweight, and universally compatible across different software and programming languages. It stores tabular data in plain text, making it easy to read, edit, and process without requiring specialized software. CSV files are also highly efficient for data exchange between applications, databases, and spreadsheets since they maintain a structured yet human-readable format. Additionally, their lack of complex metadata or formatting ensures broad support and ease of integration in data processing workflows.
Parse in case of this file is are very simple string processing operations:
struct CSVView: View {
@State private var people: [Person] = []
func loadPeople() {
let csvString = """
name,age
Ricardo,40
Priscila,25
Carlos,35
"""
let lines = csvString.components(separatedBy: "\n")
var persons: [Person] = []
for line in lines.dropFirst() { // Remove header
let values = line.components(separatedBy: ",")
if values.count == 2, let age = Int(values[1]) {
persons.append(Person(name: values[0], age: age))
}
}
people = persons
}
var body: some View {
NavigationView {
PeopleListView(people: people)
.navigationTitle("Persons List (CSV)")
}
.task {
loadPeople()
}
}
}
The CSVView
struct in SwiftUI loads a hardcoded CSV string containing names and ages, parses it into an array of Person
objects, and displays them using PeopleListView
. It first defines a @State
variable people
to store the parsed data. The loadPeople()
function splits the CSV string into lines, ignores the header, extracts name and age values, converts them into Person
objects, and updates people
. The body
contains a NavigationView
that presents PeopleListView
, and the .task
modifier ensures loadPeople()
runs when the view appears, allowing dynamic data population.
Yaml
YAML is a common data text file format because it is human-readable, easy to write, and supports complex data structures like lists and key-value mappings in a simple, indentation-based syntax. It is widely used for configuration files, data serialization, and automation scripts in DevOps, Kubernetes, and CI/CD pipelines due to its readability compared to JSON and XML. Additionally, YAML supports comments, anchors, and references, making it more flexible for structured data representation while remaining easy to integrate with various programming languages.
Yaml, as well as XML, is also not supperted natively, so we have to import an SPM package such as Yams:

Code for parsing and presenting:
struct YamlView: View {
@State private var people: [Person] = []
func loadPeople() {
let json = """
- name: Sebastián
age: 32
- name: Ana
age: 26
- name: Pedro
age: 35
"""
let data = Data(json.utf8)
do {
let decodedPeople = try YAMLDecoder().decode([Person].self, from: data)
self.people = decodedPeople
} catch {
print("\(error)")
}
}
var body: some View {
NavigationView {
PeopleListView(people: people)
.navigationTitle("Persons List (Yaml)")
}
.task {
loadPeople()
}
}
}
This SwiftUI view, YamlView
, loads a list of people from a YAML-formatted string and displays them in a PeopleListView
. It uses @State
to store an array of Person
objects and defines a loadPeople()
function that converts a hardcoded YAML string into a Data
object, decodes it into an array of Person
structs using YAMLDecoder()
, and updates the state. In the body
, it presents a NavigationView
with PeopleListView
, setting “Persons List (Yaml)” as the navigation title. The .task
modifier ensures loadPeople()
runs asynchronously when the view appears.
PList
Last but not least, and old fatigue companiong that get along with us during many years in XCode projects.PLIST (Property List) is a common data text file format, especially in Apple’s ecosystem, because it is human-readable, structured, and easily parsed by both machines and developers. It supports hierarchical data storage, making it ideal for configuration files, preferences, and serialization in macOS and iOS applications. PLIST files can be formatted in XML or binary, allowing flexibility in readability and performance. Their native support in Apple frameworks, such as Core Foundation and Swift, makes them a default choice for storing structured data in a standardized way.
A god point it that is supported natively:
struct Plist: View {
@State private var people: [Person] = []
func loadPeople() {
let plist = """
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Juan Pérez</string>
<key>age</key>
<integer>30</integer>
</dict>
<dict>
<key>name</key>
<string>Ana Gómez</string>
<key>age</key>
<integer>25</integer>
</dict>
<dict>
<key>name</key>
<string>Sílvia</string>
<key>age</key>
<integer>55</integer>
</dict>
</array>
</plist>
"""
let data = Data(plist.utf8)
do {
let decodedPeople = try PropertyListDecoder().decode([Person].self, from: data)
self.people = decodedPeople
} catch {
print("\(error)")
}
}
var body: some View {
NavigationView {
PeopleListView(people: people)
.navigationTitle("Persons List (Plist)")
}
.task {
loadPeople()
}
}
}
This SwiftUI View
named Plist
loads a hardcoded Property List (Plist) containing an array of people, decodes it into an array of Person
objects using PropertyListDecoder()
, and displays the list using a PeopleListView
. The loadPeople()
function parses the embedded XML-based Plist data, converting it into Data
, decodes it into an array of Person
structs, and assigns it to the @State
variable people
. The body
of the view contains a NavigationView
that initializes PeopleListView
with the decoded list and sets the navigation title. The .task
modifier ensures that loadPeople()
runs when the view appears, populating the list dynamically. If decoding fails, an error message is printed.
Conclusions
In this project, we have seen the most common data text formats and how to parse them. You can find source code used for writing this post in following repository.