Skip to content

Instantly share code, notes, and snippets.

@williammustaffa
Last active March 22, 2022 12:54
Show Gist options
  • Save williammustaffa/f6b7e02a43f468d622eb3d7ae08a5324 to your computer and use it in GitHub Desktop.
Save williammustaffa/f6b7e02a43f468d622eb3d7ae08a5324 to your computer and use it in GitHub Desktop.
Load XML file into game maker ds_map
/**
* Reads a XML file and converts its content into a ds_map
*
* Example output:
*
* <ds_map>{
* type: "root",
* content: "",
* nodes: <ds_list>[
* <ds_map>{
* type: "tagname",
* content: "",
* nodes: <ds_list>[...]
* },
* ...
* ]
* }
*
* @param {String} path xml path to read
* @returns {DS_MAP} ds_map representation of the xml
*/
function load_xml(path) {
var file = file_text_open_read(working_directory + path);
// Create rootnode
var ds_root = ds_map_create();
ds_map_set(ds_root, "type", "root");
ds_map_set(ds_root, "content", "");
ds_map_add_list(ds_root, "nodes", ds_list_create());
// Modes:
// 0 = Not reading tag definitions
// 1 = Reading tag type name
// 2 = Waiting for tag attribute
// 3 = Reading tag attribute name
// 4 = Waiting for attribute value start
// 5 = Reading tag attribute value
var str_temp = "";
var attr_temp = "";
var closure = false;
var mode = 0;
var ds_node = ds_root;
while (!file_text_eof(file)) {
var str_line = file_text_readln(file);
//show_message(str_line);
for (var pos = 1; pos < string_length(str_line); pos++) {
var char = string_char_at(str_line, pos);
// Replace text newline to GMS compliant new line
if (char == "\r" or char == "\n") {
char = "#";
}
switch(mode) {
// Reading content
case 0:
// If we find a new tag
if (char == "<") {
// Add node content
ds_map_set(ds_node, "content", ds_node[? "content"] + str_temp);
str_temp = "";
if (string_char_at(str_line, pos + 1) == "/") {
closure = true;
pos++;
}
if (!closure) {
// If it's not closing the tag we create it
var ds_new_node = ds_map_create();
ds_map_set(ds_new_node, "type", "undefined");
ds_map_set(ds_new_node, "content", "");
ds_map_set(ds_new_node, "parent", ds_node);
// Add linked lists
ds_map_add_list(ds_new_node, "nodes", ds_list_create());
// Add to parent nodes list
var ds_node_list = ds_node[? "nodes"];
ds_list_add(ds_node_list, ds_new_node);
// Link added list item to parent map for later cleanup
ds_list_mark_as_map(ds_node_list, ds_list_size(ds_node_list) - 1);
// Set current node as the new node as we are modifying it
ds_node = ds_new_node;
}
// Initiate tag name reading
mode = 1;
} else {
str_temp += char;
}
break;
// Reading tag name
case 1:
if (string_lettersdigits(char) != "") {
str_temp += char;
} else {
if (!closure) {
ds_map_set(ds_node, "type", str_temp);
}
str_temp = "";
mode = 2;
}
break;
// Waiting to start reading tag attributes
case 2:
if (string_lettersdigits(char) != "") {
mode = 3
} else {
// since we need to
break;
}
// Reading tag attribute name
case 3:
if (string_lettersdigits(char) != "") {
str_temp += char;
} else {
attr_temp = str_temp;
str_temp = "";
// If we find the equal sign, means we are going to read the tag value
// mode 4 which will wait for value
// mode 2 for waiting for next attribute
mode = char == "=" ? 4 : 2;
};
break;
// Wait to start reading tag attribute value
case 4:
if (char == "\"") {
mode = 5
} else {
mode = 2;
};
break;
// Reading attribute value
case 5:
if (char != "\"") {
str_temp += char;
} else {
ds_map_set(ds_node, attr_temp, str_temp);
attr_temp = "";
str_temp = "";
mode = 2;
}
break;
}
// If we are reading a tag and we find this character, it's a closure tag
if (mode != 0 and char == "/") closure = true;
if (char == ">") {
// if we are closing the tag we go to upper scope
if (closure) {
// If has no text then delete content
if (string_lettersdigits(ds_node[? "content"]) == "") {
ds_map_delete(ds_node, "content");
}
ds_node = ds_node[? "parent"];
closure = false;
}
// Reset tag
mode = 0;
}
}
}
return ds_root;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment