<!-- Generated from applied-computing-au vic/unit3-4/sat/C06-2026/C06-Reference-Godot by port-reference-godot-to-wiki.py — do not hand-edit; re-run the port. --> # Data Sources — GDScript *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.* **Skill codes on this page** | Code | Level | Skill | |---|---|---| | C644 | 7–8 | uses appropriate data types, data structures and data sources — *"including plain text, delimited and XML files"* | | C645 | 7–8 | describes, in the internal documentation, why the selected data sources were used | | C657 | 9–10 | uses a range of data types, data structures and data sources | | C658 | 9–10 | explains, in the internal documentation, why the selected data types, data structures and data sources were used | **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. ## The three sources **Definitions.** - *Plain text (TXT) file:* a structured file that contains characters of readable data. - *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. - *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. **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)`. ## TXT in Godot ```gdscript # C644 — TXT source: write var file = FileAccess.open("user://balance.txt", FileAccess.WRITE) file.store_line(str(balance)) ``` ```gdscript # C644 — TXT source: read var file = FileAccess.open("user://balance.txt", FileAccess.READ) balance = float(file.get_line()) ``` ## CSV in Godot `FileAccess` speaks CSV natively — `get_csv_line()` and `store_csv_line()` handle the delimiter for you. ```gdscript # C644 — CSV source: read journeys.csv, one journey per row (zone,fare) var journeys: Array[Dictionary] = [] var file = FileAccess.open("user://journeys.csv", FileAccess.READ) file.get_csv_line() # skip the header row while not file.eof_reached(): var row: PackedStringArray = file.get_csv_line() if row.size() >= 2: journeys.append({"zone": int(row[0]), "fare": float(row[1])}) ``` ```gdscript # C644 — CSV source: write journeys.csv var file = FileAccess.open("user://journeys.csv", FileAccess.WRITE) file.store_csv_line(PackedStringArray(["zone", "fare"])) # header for journey in journeys: file.store_csv_line(PackedStringArray([str(journey["zone"]), str(journey["fare"])])) ``` **In tile-matching-game** (`deck.gd`) — the whole game is driven by one CSV read; each row becomes a record in an array: ```gdscript # tile-matching-game — deck.gd var file := FileAccess.open(path, FileAccess.READ) # C644 — CSV source var header := file.get_csv_line() # skip the pair,text,image header while not file.eof_reached(): var row := file.get_csv_line() if row.size() < 2: continue cards.append({"pair": row[0].strip_edges(), "text": row[1].strip_edges()}) ``` The real file (`decks/spanish.csv`): ```csv pair,text,image dog,perro, dog,dog, cat,gato, cat,cat, ``` 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. ## XML in Godot 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. ```xml <?xml version="1.0" encoding="UTF-8"?> <fares> <fare zone="1" cost="5.30"/> <fare zone="2" cost="8.00"/> </fares> ``` ```gdscript # C644 — XML source: read fares.xml into a Dictionary (zone → cost) var fares: Dictionary = {} var parser = XMLParser.new() parser.open("res://data/fares.xml") while parser.read() == OK: if parser.get_node_type() == XMLParser.NODE_ELEMENT \ and parser.get_node_name() == "fare": var zone: int = int(parser.get_named_attribute_value("zone")) fares[zone] = float(parser.get_named_attribute_value("cost")) ``` Here `<fares>` is the root element and each `<fare>` is a child element carrying its data in attributes. **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"): ```gdscript # club-ladder — season.gd while parser.read() == OK: # C644 — XML source if parser.get_node_type() != XMLParser.NODE_ELEMENT: continue match parser.get_node_name(): "season": season.title = _attribute(parser, "title", "Season") "team": var team_name := _attribute(parser, "name", "") if team_name == "": continue # a team with no name is not worth keeping season.teams.append(Team.new(team_name, int(_attribute(parser, "wins", "0")), int(_attribute(parser, "draws", "0")), int(_attribute(parser, "losses", "0")))) ``` And writing — the season builds the text line by line, escaping XML's five special characters first: ```gdscript # club-ladder — season.gd lines.append('<season title="%s">' % _escape(title)) # C644 — XML written by hand for team in teams: lines.append('\t<team name="%s" wins="%d" draws="%d" losses="%d"/>' % [_escape(team.team_name), team.wins, team.draws, team.losses]) lines.append("</season>") file.store_string("\n".join(lines) + "\n") ``` 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. ## C644 — Uses appropriate types, structures and sources 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: ```gdscript # C644 — CSV source → Array[Dictionary] structure → typed values ``` ## C645 — Why these data sources Level 7–8 asks you to **describe** the reason — a sentence or two per source, in internal documentation: ```gdscript # C645 — CSV for journeys: one journey per row with the same two fields; # a flat table that also opens in Excel for checking ``` **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. ## C657 and C658 — Range, and the full explanation **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). **C658** (9–10): **explains** why — reasons that weigh alternatives: ```gdscript # C658 — chose CSV for the journey log: flat table, one row per journey; # XML would wrap every value in tags for no gain. Kept the fare table in # XML: fares nest by zone then day type, and nesting is what XML does # that CSV cannot. TXT for the save file: one value needs no structure. ``` **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. The verb ladder (outlines → identifies → describes → explains) is in the [C06 home page](/sd/C06/C06-home). ## Check Your Understanding 1. Which sources earn C644–C658? >| ### Answer >| Only TXT, CSV and XML. JSON, SQLite and `.tres` earn nothing here. 2. What reads XML in Godot, and what is missing? >| ### Answer >| `XMLParser` reads it; there is no built-in writer — build the text yourself, escaping `&` first. 3. `res://` vs `user://`? >| ### Answer >| `res://` is the project's read-only data; `user://` is the writable save location. 4. You add `fares.csv` to your project and loading breaks in the exported build. First thing to check? >| ### Answer >| The Import setting — Godot treats `.csv` as a translation file by default. Set **Import As: Keep File (exported as is)** and reimport.
