Есть std::string например:
<rectangle left="100" top="100" width="200" height="200">
<rectangle left="100" top="100" width="200" height="200">
</rectangle>
<rectangle left="100" top="100" width="200" height="200">
</rectangle>
</rectangle>
нужно его распарсить в дерево объектов со списком свойств каждый. т.е. получить rectangle со всеми его свойствами внутри которого еще 2 rectangle со свойствами.
У меня парсить пока не получается. Используя find_first_of и find_last_of могу проверить главный rectangle а сделать сдвиг не получаеться.
P.S.: знаю что XML и мне не нужны библиотеки, меня интересует сам процесс парсинга, реализация.
Процесс парсинга, в простейшем случае, можно представить в виде трех этапов:
Разделение XML на список элементов (элементами являются теги и текстовые фрагменты).
Преобразование списка элементов в дерево узлов XML.
Выделение отдельных свойств (атрибутов) для каждого узла и разэкранирование спецсимволов.
Первый этап достаточно просто делается с помощью find_first_of и substr (ну, или регулярок, для их любителей). То, что внутри скобок - теги, то, что снаружи - текстовые фрагменты.
Второй этап осуществляется путем последовательного обхода списка элементов с сохранением всех открытых на данный момент тегов в коллекцию. По мере появления закрывающих тегов, теги достаются из коллекции и добавляются в дерево узлов. На данном этапе также осуществляется контроль корректности (если что-то отклоняется от правил структуры XML, парсер должен просто упасть).
Третий этап, аналогично первому, может использовать обычные методы обработки строк.
Вот пример кода для 1 и 2 этапов:
#include <stdio.h>
#include <stdlib.h>
#include <exception>
#include <iostream>
#include <string>
#include <list>
enum TokenType {
TT_TAG = 1,
TT_TEXT = 2
};
enum TagType {
TAG_OPEN = 1,
TAG_CLOSE = 2,
TAG_SELFCLOSING = 3
};
//Представляет элемент XML (тэг или текстовый фрагмент)
struct XmlToken {
std::string text;
TokenType type;
};
//Представляет узел в дереве XML
struct XmlNode {
std::string name; //имя тега
std::string properties; //свойства
std::string value; //значение узла
std::list<XmlNode*> children; //дочерние узлы
};
//Преобразует строку XML в последовательность элементов
std::list<XmlToken> XmlToTokens(const std::string& xml) {
std::list<XmlToken> tokens;
XmlNode result;
size_t pos=0;
size_t startindex, endindex;
std::string token_text;
XmlToken token;
while (true) {
startindex = xml.find_first_of('<', pos);
endindex = xml.find_first_of('>', startindex);
if (startindex == std::string::npos || endindex == std::string::npos) {
break;
}
if (startindex > pos) {
token.text = xml.substr(pos, startindex - pos);
token.type = TT_TEXT;
tokens.push_back(token);
}
token.text = xml.substr(startindex+1, endindex - (startindex+1));
token.type = TT_TAG;
tokens.push_back(token);
pos = endindex + 1;
if (pos >= xml.length())break;
}
return tokens;
}
//возвращает тип тега
TagType GetTagType(const XmlToken& token) {
if (token.type != TT_TAG || token.text.length()==0) return (TagType)0;
char first = token.text.at(0);
char last = token.text.at(token.text.length() - 1);
if (first == '/' && last != '/') return TAG_CLOSE;
if (first != '/' && last == '/') return TAG_SELFCLOSING;
if (first != '/' && last != '/') return TAG_OPEN;
else return (TagType)0;
}
//возвращает имя тега
std::string GetTagName(const XmlToken& token) {
std::string res;
if (token.type != TT_TAG || token.text.length() == 0) return res;
size_t pos = 0;
char first = token.text.at(0);
if (first == '/')pos = 1;
size_t index = token.text.find_first_of(" /", pos);
if (index == std::string::npos) index = token.text.length();
return token.text.substr(pos, index - pos);
}
//возвращает свойства тега
std::string GetTagProperties(const XmlToken& token) {
std::string res;
if (token.type != TT_TAG || token.text.length() == 0) return res;
size_t pos = 0;
size_t len = token.text.length();
char first = token.text.at(0);
if (first == '/')pos = 1;
char last = token.text.at(len-1);
if (last == '/')len--;
size_t index = token.text.find_first_of(" ", pos);
if (index == std::string::npos) index = len - 1;
return token.text.substr(index+1, len - (index + 1));
}
//возвращает текст элемента без пробелов
std::string GetTrimmedText(const XmlToken& token) {
std::string res;
if (token.type != TT_TEXT || token.text.length() == 0) return res;
for (size_t i = 0; i < token.text.length(); i++) {
char c = token.text.at(i);
if (iswspace(c) == 0 && c!='\n' && c!='\r') res += c;
}
return res;
}
//выводит дерево XML на экран
void PrintXml(const XmlNode& node, int depth = 0) {
for (int i = 0; i < depth;i++) putc('-', stdout);
printf("%s Properties: [%s]; Value: [%s]; Children: [%d]\n",
node.name.c_str(), node.properties.c_str(),node.value.c_str(),(int)node.children.size()
);
for (auto x : node.children) PrintXml(*x, depth + 1);
}
//**********************************
int main(int argc, char **argv)
{
try {
std::string xml = "<rectangle left=\"100\" top=\"100\" width=\"200\" height=\"200\">\
<rectangle left = \"100\" top = \"100\" width = \"200\" height = \"200\"></rectangle>\
<rectangle left = \"100\" top = \"100\" width = \"200\" height = \"200\"></rectangle>\
</rectangle>";
printf("\n****** Source XML: ****** \n");
puts(xml.c_str());
printf("*********************** \n");
//разбивка на элементы
std::list<XmlToken> tokens = XmlToTokens(xml);
printf("\n****** Tokens: ****** \n");
for (XmlToken& x : tokens) {
printf("%s\n", x.text.c_str());
}
printf("*********************** \n");
//создаем корневой узел
XmlNode root;
root.name = std::string("(XML root)");
root.properties = std::string("");
root.value = std::string("");
std::list<XmlNode*> currentpath; //текущий путь в иерархии XML
bool between_tags = false;
std::string tagname;
std::string trimmed;
TagType type;
XmlNode* node = &root;
XmlNode* new_node;
//строим дерево XML...
for (XmlToken& x : tokens) {
switch (x.type) {
case TT_TEXT: //текстовый фрагмент
trimmed = GetTrimmedText(x);
if (trimmed.length() == 0) { continue; }
if (!between_tags) {
printf("Parse error: Unexpected text outside of XML tags.\n");
throw std::exception();
}
new_node = currentpath.back();
if (new_node->children.size() > 0) {
printf("Parse error: Element cannot contain both text and child elements\n");
throw std::exception();
}
new_node->value = x.text; //устанавливаем значение узла
break;
case TT_TAG: //тег
type = GetTagType(x);
tagname = GetTagName(x);
if (tagname.length() == 0) {
printf("Parse error: Tag name empty\n");
throw std::exception();
}
switch (type) {
case TAG_OPEN: //открывающий тег
//создаем новый узел
new_node = new XmlNode();
new_node->name = tagname;
new_node->properties = GetTagProperties(x);
new_node->value = std::string("");
//добавляем узел в текущий путь
between_tags = true;
currentpath.push_back(new_node);
break;
case TAG_CLOSE: //закрывающий тег
if (currentpath.size() == 0) {
printf("Parse error: Unexpected closing tag\n");
throw std::exception();
}
new_node = currentpath.back();
if (tagname != new_node->name) {
printf("Parse error: Closing tag does not match opening tag.\n");
throw std::exception();
}
between_tags = false;
currentpath.pop_back();
//находим родительский узел
if (currentpath.size() > 0)
node = currentpath.back();
else
node = &root;
//добавляем дочерний узел
if (node->value.length() > 0) {
printf("Parse error: Element cannot contain both text and child elements\n");
throw std::exception();
}
node->children.push_back(new_node);
break;
case TAG_SELFCLOSING: //самозакрывающийся
//создаем новый узел
new_node = new XmlNode();
new_node->name = tagname;
new_node->properties = GetTagProperties(x);
new_node->value = std::string("");
//находим родительский узел
if (currentpath.size() > 0)
node = currentpath.back();
else
node = &root;
//добавляем дочерний узел
if (node->value.length() > 0) {
printf("Parse error: Element cannot contain both text and child elements\n");
throw std::exception();
}
node->children.push_back(new_node);
break;
}
break;
}//end switch
}//end for
if (currentpath.size() > 0) {
printf("Parse error: Not all tags are closed\n");
throw std::exception();
}
//выводим результат
printf("\n****** XML Tree: ****** \n");
PrintXml(root, 0);
printf("*********************** \n");
}
catch (std::exception) {
printf("Parsing failed!\n");
}
getchar();
return 0;
}
/* Вывод:
****** Source XML: ******
<rectangle left="100" top="100" width="200" height="200"><rectangle left = "100" top = "100" width = "200" height = "200"></rectangle><rectangle left = "100" top = "100" width = "200" height = "200"></rectangle></rectangle>
***********************
****** Tokens: ******
rectangle left="100" top="100" width="200" height="200"
rectangle left = "100" top = "100" width = "200" height = "200"
/rectangle
rectangle left = "100" top = "100" width = "200" height = "200"
/rectangle
/rectangle
***********************
****** XML Tree: ******
(XML root) Properties: []; Value: []; Children: [1]
-rectangle Properties: [left="100" top="100" width="200" height="200"]; Value: []; Children: [2]
--rectangle Properties: [left = "100" top = "100" width = "200" height = "200"]; Value: []; Children: [0]
--rectangle Properties: [left = "100" top = "100" width = "200" height = "200"]; Value: []; Children: [0]
***********************
*/
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Имеется map<string, int> и vector<string>
вот тут лежит мой проект (в src лежат исходники, а в mainProject файл notepad6d11 это собранная версия), проблема: верхняя панель (там где файл поле) не нажимается,...
В проекте создается экземпляр класса DatabaseManagerВ нем я создаю экземпляры класса Database в функции setupNewDatabase