Blame

3aab9f lisa 2026-08-11 23:24:06
Add C06 skill-code study pages, linked from the SD hub Eleven pages ported from the applied-computing-au C06-Reference-Godot standard: home page with the 34-code lookup, per-topic pages with labelled GDScript examples, evidence standards, and Check Your Understanding fold blocks. Generated mirror — repo copy is canonical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1
<!-- Generated from applied-computing-au vic/unit3-4/sat/C06-2026/C06-Reference-Godot — do not hand-edit; re-run the port. -->
2
# Data Sources — GDScript
3
4
*VCE scope only. The study design names exactly three data sources: **plain text (TXT), delimited (CSV) and XML files**. JSON, databases (SQLite), REST APIs and Godot's own `.tres`/`.res` resources are **out of scope** — they do not earn source codes, however natural they feel in Godot.*
5
6
**Skill codes on this page**
7
8
| Code | Level | Skill |
9
|---|---|---|
10
| C644 | 7–8 | uses appropriate data types, data structures and data sources — *"including plain text, delimited and XML files"* |
11
| C645 | 7–8 | describes, in the internal documentation, why the selected data sources were used |
12
| C657 | 9–10 | uses a range of data types, data structures and data sources |
13
| C658 | 9–10 | explains, in the internal documentation, why the selected data types, data structures and data sources were used |
14
15
**Before you build:** a data layer built on JSON, SQLite or `.tres` earns **none** of C644–C658, however natural those feel in Godot — and graders (human or AI) apply that rule mechanically. The sources you demonstrate must be TXT, CSV and/or XML.
16
17
## The three sources
18
19
**Definitions.**
20
21
- *Plain text (TXT) file:* a structured file that contains characters of readable data.
22
23
- *CSV:* a comma-separated value file — a delimited file separated by commas. The *delimiter* is the character separating the values. A CSV is a flat table: rows, each row the same fields.
24
25
- *XML:* Extensible Markup Language — data in **elements** marked by opening and closing **tags**. Elements can hold other elements, so the data is **nested** rather than flat: a *tree* with a *root element* at the top, and a *prolog* (version, encoding) before the content.
26
27
**Know the difference:** `res://` is your project's read-only data; `user://` is the writable save location. Naming that in validation is easy marks. club-ladder runs on exactly this split — the bundled season ships in `res://seasons/`, the player's copy lives at `user://ladder.xml`, and `load_season()` picks between them with one `if FileAccess.file_exists(save_path)`.
28
29
## TXT in Godot
30
31
```gdscript
32
# C644 — TXT source: write
33
var file = FileAccess.open("user://balance.txt", FileAccess.WRITE)
34
file.store_line(str(balance))
35
```
36
37
```gdscript
38
# C644 — TXT source: read
39
var file = FileAccess.open("user://balance.txt", FileAccess.READ)
40
balance = float(file.get_line())
41
```
42
43
## CSV in Godot
44
45
`FileAccess` speaks CSV natively — `get_csv_line()` and `store_csv_line()` handle the delimiter for you.
46
47
```gdscript
48
# C644 — CSV source: read journeys.csv, one journey per row (zone,fare)
49
var journeys: Array[Dictionary] = []
50
var file = FileAccess.open("user://journeys.csv", FileAccess.READ)
51
file.get_csv_line() # skip the header row
52
while not file.eof_reached():
53
var row: PackedStringArray = file.get_csv_line()
54
if row.size() >= 2:
55
journeys.append({"zone": int(row[0]), "fare": float(row[1])})
56
```
57
58
```gdscript
59
# C644 — CSV source: write journeys.csv
60
var file = FileAccess.open("user://journeys.csv", FileAccess.WRITE)
61
file.store_csv_line(PackedStringArray(["zone", "fare"])) # header
62
for journey in journeys:
63
file.store_csv_line(PackedStringArray([str(journey["zone"]), str(journey["fare"])]))
64
```
65
66
**In tile-matching-game** (`deck.gd`) — the whole game is driven by one CSV read; each row becomes a record in an array:
67
68
```gdscript
69
# tile-matching-game — deck.gd
70
var file := FileAccess.open(path, FileAccess.READ) # C644 — CSV source
71
var header := file.get_csv_line() # skip the pair,text,image header
72
while not file.eof_reached():
73
var row := file.get_csv_line()
74
if row.size() < 2:
75
continue
76
cards.append({"pair": row[0].strip_edges(), "text": row[1].strip_edges()})
77
```
78
79
The real file (`decks/spanish.csv`):
80
81
```csv
82
pair,text,image
83
dog,perro,
84
dog,dog,
85
cat,gato,
86
cat,cat,
87
```
88
89
Defensive touches worth copying: check `FileAccess.file_exists(path)` first, skip short rows, `strip_edges()` every field. And a Godot trap: **`.csv` imports as a translation file by default** — select the file, Import tab → *Keep File (exported as is)* → Reimport, or deck loading breaks in exported builds.
90
91
## XML in Godot
92
93
Read XML with the built-in `XMLParser`. There is no built-in XML *writer* — either write your outputs as TXT/CSV, or build the XML text yourself as club-ladder does below.
94
95
```xml
96
<?xml version="1.0" encoding="UTF-8"?>
97
<fares>
98
<fare zone="1" cost="5.30"/>
99
<fare zone="2" cost="8.00"/>
100
</fares>
101
```
102
103
```gdscript
104
# C644 — XML source: read fares.xml into a Dictionary (zone → cost)
105
var fares: Dictionary = {}
106
var parser = XMLParser.new()
107
parser.open("res://data/fares.xml")
108
while parser.read() == OK:
109
if parser.get_node_type() == XMLParser.NODE_ELEMENT \
110
and parser.get_node_name() == "fare":
111
var zone: int = int(parser.get_named_attribute_value("zone"))
112
fares[zone] = float(parser.get_named_attribute_value("cost"))
113
```
114
115
Here `<fares>` is the root element and each `<fare>` is a child element carrying its data in attributes.
116
117
**In club-ladder** (`season.gd`) — XML both ways, in a studied project. Reading, with a `_attribute()` helper that falls back when a value is missing ("real files are often missing things"):
118
119
```gdscript
120
# club-ladder — season.gd
121
while parser.read() == OK: # C644 — XML source
122
if parser.get_node_type() != XMLParser.NODE_ELEMENT:
123
continue
124
match parser.get_node_name():
125
"season":
126
season.title = _attribute(parser, "title", "Season")
127
"team":
128
var team_name := _attribute(parser, "name", "")
129
if team_name == "":
130
continue # a team with no name is not worth keeping
131
season.teams.append(Team.new(team_name,
132
int(_attribute(parser, "wins", "0")),
133
int(_attribute(parser, "draws", "0")),
134
int(_attribute(parser, "losses", "0"))))
135
```
136
137
And writing — the season builds the text line by line, escaping XML's five special characters first:
138
139
```gdscript
140
# club-ladder — season.gd
141
lines.append('<season title="%s">' % _escape(title)) # C644 — XML written by hand
142
for team in teams:
143
lines.append('\t<team name="%s" wins="%d" draws="%d" losses="%d"/>'
144
% [_escape(team.team_name), team.wins, team.draws, team.losses])
145
lines.append("</season>")
146
file.store_string("\n".join(lines) + "\n")
147
```
148
149
A team called "Smith & Sons" would corrupt the file without `_escape()` — and the `&` must be replaced first, or it would mangle the entities just added.
150
151
## C644 — Uses appropriate types, structures and sources
152
153
Level 7–8 is the three layers working together: a file (**source**) parsed into a **structure** of typed **values** — like the CSV reader above (`journeys.csv` → `Array[Dictionary]` → `int` and `float` fields), labelled:
154
155
```gdscript
156
# C644 — CSV source → Array[Dictionary] structure → typed values
157
```
158
159
## C645 — Why these data sources
160
161
Level 7–8 asks you to **describe** the reason — a sentence or two per source, in internal documentation:
162
163
```gdscript
164
# C645 — CSV for journeys: one journey per row with the same two fields;
165
# a flat table that also opens in Excel for checking
166
```
167
168
**Described in the wild:** tile-matching-game's README describes its source choice at exactly this level — the game "reads its cards from a CSV file, so the same game can be re-skinned for any subject … without changing a line of code." One sentence that says why CSV earns its place.
169
170
## C657 and C658 — Range, and the full explanation
171
172
**C657** (9–10): a **range** — several types, several structures, several sources, each doing a job the others could not. A Myki-app spread using only VCE sources: XML fare table in `res://` (nested: zones × day types), CSV journey log in `user://` (flat table), TXT save file in `user://` (one balance value).
173
174
**C658** (9–10): **explains** why — reasons that weigh alternatives:
175
176
```gdscript
177
# C658 — chose CSV for the journey log: flat table, one row per journey;
178
# XML would wrap every value in tags for no gain. Kept the fare table in
179
# XML: fares nest by zone then day type, and nesting is what XML does
180
# that CSV cannot. TXT for the save file: one value needs no structure.
181
```
182
183
**Explained in the wild:** `club-ladder/season.gd`'s header comment explains its XML design *by weighing the alternative* — every value is an attribute because "one call gets each one", whereas nested `<name>` tags would mean "tracking which tag you are inside while text arrives separately". That is C658-grade reasoning, written where the marker will find it.
184
185
The verb ladder (outlines → identifies → describes → explains) is in the [C06 home page](/sd/C06/C06-home).
186
187
## Check Your Understanding
188
189
1. Which sources earn C644–C658?
190
191
>| ### Answer
192
>| Only TXT, CSV and XML. JSON, SQLite and `.tres` earn nothing here.
193
194
2. What reads XML in Godot, and what is missing?
195
196
>| ### Answer
197
>| `XMLParser` reads it; there is no built-in writer — build the text yourself, escaping `&` first.
198
199
3. `res://` vs `user://`?
200
201
>| ### Answer
202
>| `res://` is the project's read-only data; `user://` is the writable save location.
203
204
4. You add `fares.csv` to your project and loading breaks in the exported build. First thing to check?
205
206
>| ### Answer
207
>| The Import setting — Godot treats `.csv` as a translation file by default. Set **Import As: Keep File (exported as is)** and reimport.