/
Zamar_Terrier
/
TigorEngineWeb
Обзор
Документация
Войти
/
Zamar_Terrier
/
TigorEngineWeb
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/xml_parser.c
337 строк
11 KB
Zamar_Terrier
add json and xml parsers
12 мар 2026, 17:40
12 мар 2026, 17:40
becab97
Код
Авторство
О чём код?
#include "xml_parser.h" #include <ctype.h> #include <stdio.h> #include <string.h> // Вспомогательная функция для пропуска пробелов static void skip_whitespace(const char **str) { while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\r') (*str)++; } // Вспомогательная функция для копирования имени или значения static char* extract_string(const char* start, const char* end) { if (start >= end) return NULL; int len = end - start; char* str = (char*)calloc(len + 1, sizeof(char)); strncpy(str, start, len); str[len] = '\0'; return str; } // Парсинг атрибутов static void parse_attributes(const char** str, xml_node_t* node) { const char* pos = *str; while (*pos != '>' && *pos != '/' && *pos != '\0') { skip_whitespace(&pos); const char* name_start = pos; while (*pos != '=' && *pos != ' ' && *pos != '>' && *pos != '\t' && *pos != '\n' && *pos != '\r' && *pos != '\0') pos++; if (pos == name_start) break; const char* name_end = pos; skip_whitespace(&pos); if (*pos != '=') break; pos++; skip_whitespace(&pos); char quote = *pos; if (quote != '"' && quote != '"') break; pos++; const char* value_start = pos; while (*pos != quote && *pos != '\0') pos++; const char* value_end = pos; if (*pos == quote) pos++; char* name = extract_string(name_start, name_end); char* value = extract_string(value_start, value_end); if (name && value) { xml_add_attribute(node, name, value); free(name); free(value); } skip_whitespace(&pos); } *str = pos; } xml_node_t* xml_create_node(const char* name) { xml_node_t* node = (xml_node_t*)calloc(1, sizeof(xml_node_t)); if (name) { node->name = (char*)calloc(strlen(name) + 1, sizeof(char)); strcpy(node->name, name); } node->value = NULL; node->parent = NULL; node->children = NULL; node->next = NULL; node->attributes = NULL; node->attr_count = 0; node->child_count = 0; return node; } void xml_free_node(xml_node_t* node) { if (!node) return; if (node->name) free(node->name); if (node->value) free(node->value); if (node->attributes) { for (int i = 0; i < node->attr_count; i++) { free(node->attributes[i].name); free(node->attributes[i].value); } free(node->attributes); } xml_node_t* child = node->children; while (child) { xml_node_t* next = child->next; xml_free_node(child); child = next; } free(node); } int xml_add_attribute(xml_node_t* node, const char* name, const char* value) { if (!node || !name || !value) return 0; node->attributes = (xml_attribute_t*)realloc(node->attributes, (node->attr_count + 1) * sizeof(xml_attribute_t)); if (!node->attributes) return 0; node->attributes[node->attr_count].name = (char*)calloc(strlen(name) + 1, sizeof(char)); node->attributes[node->attr_count].value = (char*)calloc(strlen(value) + 1, sizeof(char)); if (!node->attributes[node->attr_count].name || !node->attributes[node->attr_count].value) return 0; strcpy(node->attributes[node->attr_count].name, name); strcpy(node->attributes[node->attr_count].value, value); node->attr_count++; return 1; } char* xml_get_attribute(xml_node_t* node, const char* name) { if (!node || !name) return NULL; for (int i = 0; i < node->attr_count; i++) { if (strcmp(node->attributes[i].name, name) == 0) { return node->attributes[i].value; } } return NULL; } int xml_add_child(xml_node_t* parent, xml_node_t* child) { if (!parent || !child) return 0; child->parent = parent; child->next = NULL; if (!parent->children) { parent->children = child; } else { xml_node_t* last = parent->children; while (last->next) { last = last->next; } last->next = child; } parent->child_count++; return 1; } xml_node_t* xml_find_node(xml_node_t* root, const char* name) { if (!root || !name) return NULL; if (root->name && strcmp(root->name, name) == 0) return root; xml_node_t* child = root->children; while (child) { xml_node_t* found = xml_find_node(child, name); if (found) return found; child = child->next; } return NULL; } xml_node_t* root = NULL; xml_node_t* xml_parse(const char **str_point, xml_node_t* parent) { if (!str_point || !(*str_point)) return NULL; if (!parent) root = NULL; xml_node_t* node = NULL; xml_node_t* current_parent = parent; int back_parent = 0; bool exit = false; while (**str_point != '\0') { back_parent = 0; if (**str_point == '<') { (*str_point)++; } if (**str_point == '/') { // Закрывающий тег (*str_point)++; const char* tag_start = (*str_point); if(node && !strncmp((*str_point), node->name, strlen(node->name))) exit = true; while (**str_point != '>' && **str_point != '\0') (*str_point)++; // Просто пропускаем if (**str_point == '>') (*str_point)++; if(exit) break; continue; } else if (**str_point == '!' || **str_point == '?') { // Комментарии или инструкции while (**str_point != '>' && **str_point != '\0') (*str_point)++; if (**str_point == '>') (*str_point)++; continue; } else { // Открывающий тег const char* tag_start = (*str_point); while (**str_point != ' ' && **str_point != '>' && **str_point != '/' && **str_point != '\0') (*str_point)++; const char* tag_end = (*str_point); node = xml_create_node(NULL); if (tag_start < tag_end) { node->name = extract_string(tag_start, tag_end); } skip_whitespace(str_point); if (**str_point != '>' && **str_point != '/' && **str_point != '\0') { parse_attributes(str_point, node); } if (!root) { root = node; current_parent = node; } while(**str_point != '\0'){ if (**str_point == '<') { // Самозакрывающийся тег (*str_point)++; if (**str_point != '\0' && **str_point == '/'){ if (**str_point == '>') (*str_point)++; exit = true; break; }else if(**str_point == '\0'){ exit = true; break; }else{ xml_node_t *next = xml_parse(str_point, node); if(next) xml_add_child(node, next); } }else if (**str_point == '>') { (*str_point)++; // Считываем значение узла, если оно текстовое const char* value_start = (*str_point); while (**str_point != '<' && **str_point != '\0') (*str_point)++; if (value_start < (*str_point)) { node->value = extract_string(value_start, (*str_point)); } }else if(**str_point == '/'){ (*str_point)++; if(**str_point == '>' || (node->name && !strncmp((*str_point), node->name, strlen(node->name))) || !strncmp((*str_point), "/", 1)){ exit = true; break; } }else if((*str_point)[-1] == '<'){ xml_node_t *next = xml_parse(str_point, node); if(next) xml_add_child(node, next); } (*str_point) ++; } } if(exit) break; (*str_point) ++; } return node; } void serialize_node(xml_node_t* n, char** pos, int* size) { if (!n) return; int len; len = snprintf(*pos, *size, "<%s", n->name ? n->name : ""); *pos += len; *size -= len; for (int i = 0; i < n->attr_count; i++) { len = snprintf(*pos, *size, " %s=\"%s\"", n->attributes[i].name, n->attributes[i].value); *pos += len; *size -= len; } if (n->value || n->children) { len = snprintf(*pos, *size, ">"); *pos += len; *size -= len; if (n->value) { len = snprintf(*pos, *size, "%s", n->value); *pos += len; *size -= len; } xml_node_t* child = n->children; while (child) { serialize_node(child, pos, size); child = child->next; } len = snprintf(*pos, *size, "</%s>", n->name ? n->name : ""); *pos += len; *size -= len; } else { len = snprintf(*pos, *size, " />"); *pos += len; *size -= len; } } char* xml_serialize(xml_node_t* node) { if (!node) return NULL; // Грубая оценка размера буфера char* buffer = (char*)calloc(10240, sizeof(char)); char* pos = buffer; int size = 10240; serialize_node(node, &pos, &size); *pos = '\0'; return buffer; } xml_node_t* xml_read_file(const char* filename) { FILE* file = fopen(filename, "r"); if (!file) return NULL; // Определение размера файла fseek(file, 0, SEEK_END); long length = ftell(file); fseek(file, 0, SEEK_SET); char* buffer = (char*)calloc(length + 1, sizeof(char)); fread(buffer, 1, length, file); buffer[length] = '\0'; fclose(file); xml_node_t* root = xml_parse((const char **)&buffer, NULL); free(buffer); return root; } int xml_write_file(xml_node_t* node, const char* filename) { if (!node || !filename) return 0; char* str = xml_serialize(node); if (!str) return 0; FILE* file = fopen(filename, "w"); if (!file) { free(str); return 0; } fprintf(file, "%s", str); fclose(file); free(str); return 1; }