Пример разбора XML файла в Visual Studio 2015 на C++
Учебный пример для анализа XML файла. Буду рассматривать на примере визуального CLR приложения.
Постановка задачи
Надо написать приложение, где при клике на кнопку происходит считывание информации из XML файла, его анализ и вывод информации в текстовое поле.
Создание XML файла
Создайте текстовой файл с таким содержанием:
<?xml version="1.0" encoding="UTF-8" ?>
<points name="Example">
<point type="circle">
<x> 2 </x>
<y> 3 </y>
</point>
<point type="circle">
<x> 1 </x>
<y> 5 </y>
</point>
<point type="square">
<x> 12 </x>
<y> -3 </y>
</point>
</points>
И сохраните его где-нибудь как points.xml
.
Болванка приложения
Данная статья написана по мотивам официальной документации. Так что можете обратиться к ней для получения дополнительной информации.
Итак, создайте пустое приложение CLR с формой. Это можно сделать по статье, дойдя в ней до пункта «Интерфейс приложения».
Интерфейс приложения
Перетащите на форму кнопку и текстовое поле:
У текстового поля поменяйте параметр MultiLine
на true
. И увеличьте это текстовое поле:
Можно добавить полосу прокрутки:
Получение имени файла
Перетащите на форму компонент диалогового окна открытия файла:
Двойной клик по кнопке на форме:
При этом создается обработчик клика кнопки:
В нем припишите такой код:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
textBox1->Text = fileName;
}
После данного приложение при запуске и клике на кнопку вызовет диалоговое окно, где вы выбираете файл. После этого в текстовом поле появится имя файла:
Теперь вы научились получать имя файла через диалоговое окно. С настройками компонента разберитесь сами, если это вам нужно:
Открытие файла
На всякий случай покажу, как загрузить из текстового файла в переменную String
^ содержимое.
Подключите в MyForm.h
пространство имен для работы с вводом-выводом:
using namespace System::IO;
Теперь в клике кнопки пропишем вместо прежнего кода вот такой:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
try
{
StreamReader^ din = File::OpenText(fileName);
String^ str;
int count = 0; // Счетчик числа строчек в файле
while ((str = din->ReadLine()) != nullptr) // Считываем строчку из файла в str
{
count++;
// Выведем новую считанную строчку в textBox1
textBox1->Text = textBox1->Text + str + "\r\n";
}
}
catch (Exception^ e)
{
// Если не получилось считать файл, то обрабатываем ошибки
if (dynamic_cast<FileNotFoundException^>(e))
textBox1->Text = "File not found";
else
textBox1->Text = "Problem reading file ";
}
}
Или чуть более усовершенствованный код:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
String^ content;
try
{
StreamReader^ din = File::OpenText(fileName);
String^ str;
int count = 0; // Счетчик числа строчек в файле
while ((str = din->ReadLine()) != nullptr) // Считываем строчку из файла в str
{
count++;
// Выведем новую считанную строчку в content
content += str + "\r\n";
}
textBox1->Text = content;
}
catch (Exception^ e)
{
// Если не получилось считать файл, то обрабатываем ошибки
if (dynamic_cast<FileNotFoundException^>(e))
textBox1->Text = "File not found";
else
textBox1->Text = "Problem reading file ";
}
}
В общем, при запуске приложения теперь в текстовом поле появится содержимое файла:
Это можно использовать для анализа текстовых файлов, их обработки и так далее.
Открытие и обработка именно XML файла
Но мы не будем работать напрямую с содержимым XML файла, а будем использовать специальные парсеры XML файлов.
Создайте на форме еще одну кнопку и двойным кликом создайте обработчик клика:
Подключите в MyForm.h
пространство имен для работы с XML:
using namespace System::Xml;
Пропишите там такой код:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
XmlTextReader reader(fileName);
}
Что мы тут сделали? Мы запустили диалоговое окно выбора файла, а когда он был выбран, то по выбранному файлу создали экземпляр XmlTextReader
.
Если XML файл был корректным, то теперь в reader
уже есть обработанные данные из XML, которые мы можем легко достать. Причем это сделать мы можем по-разному в зависимости от того, что нам нужно.
Вначале самое простое осуществим: выведем названия всех тэгов (открывающихся и закрывающихся), которые есть в нашем XML файле:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
XmlTextReader reader(fileName);
while (reader.Read())
{
textBox1->Text += reader.Name + "\r\n";
}
}
Хоть данный пример и бесполезен, но показывает, что наш файл обработан и с ним можно работать.
Попробуем вывести не только тэги, но и содержимое тэгов. При этом элементы будем разделять на открывающие тэги, содержимое тэгов, закрывающие тэги. И различать тэги будем через оператор switch:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
XmlTextReader reader(fileName);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType::Element: // The node is an element.
textBox1->Text += "<" + reader.Name + ">\r\n";
break;
case XmlNodeType::Text: //Display the text in each element.
textBox1->Text += "" + reader.Value + "\r\n";
break;
case XmlNodeType::EndElement: //Display the end of the element.
textBox1->Text += "</" + reader.Name + ">\r\n";
break;
}
}
}
Мы получили структуру нашего XML документа:
На всякий случай уточняю, что тот факт, что мы выводим в textBox1
еще и символы <
, </
, >
— это только для красоты, чтобы выводимый текст был похож на XML код.
Но обратите внимание, что атрибуты тэгов мы пока не считывали. Исправим это упущение. Итак, в вышеприведенном коде мы открывающий тэг обрабатывали в следующем коде:
case XmlNodeType::Element: // The node is an element.
textBox1->Text += "<" + reader.Name + ">\r\n";
break;
Теперь заменим его на другой, где мы еще также будем пробегать по атрибутам тэгов:
case XmlNodeType::Element: // The node is an element.
textBox1->Text += "<" + reader.Name + " ";
while (reader.MoveToNextAttribute()) // Read the attributes.
textBox1->Text += reader.Name + " = \"" + reader.Value + "\" ";
textBox1->Text += ">\r\n";
То есть получим код кнопки:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
XmlTextReader reader(fileName);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType::Element: // The node is an element.
textBox1->Text += "<" + reader.Name + " ";
while (reader.MoveToNextAttribute()) // Read the attributes.
textBox1->Text += reader.Name + " = \"" + reader.Value + "\" ";
textBox1->Text += ">\r\n";
break;
case XmlNodeType::Text: //Display the text in each element.
textBox1->Text += "" + reader.Value + "\r\n";
break;
case XmlNodeType::EndElement: //Display the end of the element.
textBox1->Text += "</" + reader.Name + ">\r\n";
break;
}
}
}
Теперь отображаются и атрибуты. Вот таким способом вы можете пробегать по содержимому XML файла, анализировать те или иные тэги, считывать содержимое атрибутов, текста и так далее.
Пример разбора points.xml
До этого мы рассматривали разбор любого XML файла и пытались придать внешний вид выводу в textBox1
как у обычного XML файла. И мы предполагали, что ничего не знаем, а что конкретно хранится в файле.
Теперь же попробуем вывести информацию о точках из нашего XML файла points.xml
зная, что за структура XML файла у нас. А у нас есть тэг points
, внутри которого есть множество тэгов точек point
, каждая из которых имеет в себе значения координат x
и y
. В общем, у нас на самом деле в XML файле хранится информация почти в табличном виде.
Вот и считаем это:
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String^ fileName = openFileDialog1->FileName;
XmlTextReader reader(fileName);
// Дойдем до тэга <points>
while (reader.ReadToFollowing("points"))
{
textBox1->Text += "Дошли до тэга <" + reader.Name + "> \r\n";
int pointCount = 0; // Вдруг нам будет нужен счетчик точек. Например, для массива
// Теперь в тэге <points> найдем все точки в виде тэгов <point>
if (reader.ReadToDescendant("point"))
{
// Все тэги <point> находим в цикле
do
{
pointCount++;// Увеличиваем счетчик числа найденных точек
int x, y;
String^ Type;
// Считываем атрибут
Type = reader.GetAttribute("type");
// Внутри точки есть тэги <x> и <y>.
// Вытащим все тэги в отдельное дерево
XmlReader^ inner = reader.ReadSubtree();
// И пробежимся по всем внутренностям данного поддерева точки
while (inner->Read())
{
// Если текущий элемент - это открывающий тэг <x>,
// то следующий элемент - это текст внутри тэга <x></x>
if ((inner->Name == "x")&&(inner->NodeType == XmlNodeType::Element))
{
// Поэтому считываем еще один элемент и этот элемент то, что нам нужно
inner->Read();
x = Convert::ToInt32(inner->Value);
}
// Если текущий элемент - это открывающий тэг <y>,
// то следующий элемент - это текст внутри тэга <y></y>
if ((inner->Name == "y") && (inner->NodeType == XmlNodeType::Element))
{
// Поэтому считываем еще один элемент и этот элемент то, что нам нужно
inner->Read();
y = Convert::ToInt32(inner->Value);
}
}
// Выведем считанную информацию
textBox1->Text += "Точка №" + pointCount.ToString() + "\r\n";
textBox1->Text += "Тип = " + Type + "\r\n";
textBox1->Text += "x = " + x.ToString() + "\r\n";
textBox1->Text += "y = " + y.ToString() + "\r\n";
} while (reader.ReadToNextSibling("point"));
}
}
}
Тут я использовал новые методы, такие как:
ReadToFollowing
— добраться до элемента с таким-то именем.ReadToDescendant
— внутри элемента найти потомка с таким-то именем.GetAttribute
— считать значение атрибута с таким-то именем.ReadSubtree
— считать поддерево.ReadToNextSibling
— перейти к следующему элементу с таким же именем (Sibling — родной брат).
Напоследок
Выше я рассмотрел случай, когда все вычисления выполнялись внутри метода кнопки на главной форме. А конкретно данная статья в первую очередь предназначена тем, кого я попросил считывание из файла реализовать внутри отдельного класса. А из класса (в том виде, в каком я хочу увидеть) доступа к компонентам формы нет.
Как желательно реализовать логику приложения:
- Класс в качестве параметра получает имя файла в виде строчки.
- Внутри класса ничего никуда не выводится, но методы возвращают строчки с текстом, который нужно вывести.
- Диалоговое окно вызывается внутри кнопки формы.
Предвижу, что может возникнуть определенная путаница, поэтому посмотрите эту статью.
Тэги:
- C++
- Visual Studio
- Работа с файлами
- XML
Категории:
- blog
- it
- programming
Учебный пример для анализа XML файла. Буду рассматривать на примере визуального CLR приложения.
Учебный пример для анализа XML файла. Буду рассматривать на примере визуального CLR приложения.