Консультация № 160537
15.02.2009, 17:04
0.00 руб.
0 9 2
Здравствуйту, уважаемые эксперты.
Мне необходимо работать с XML документами на С++, но ни чего "дельного" я в интернете не нашел.
Требуется записывать и читать из XML файла структуру.
Напишите пожалуйста пример.
Заранее спасибо.


Приложение:
Документ такого типа надо записывать и считывать =(.
<xml>
<object numb=12345>
<par1>par1</par1>
<par2>par1</par2>
<par3>par1</par3>
</object>

Обсуждение

давно
Академик
20764
1861
15.02.2009, 18:05
общий
Есть библиотеки expat и xerces-c++.
Портированы ли они под windows - не знаю.
давно
Посетитель
7438
7205
16.02.2009, 04:50
общий
это ответ
Здравствуйте, California!
Может пойти путем, который предложен в MSDN?
При компиляции добавить в проект библиотеку urlmon.lib
Только надо слегка подправить XML-файл:
Код:
<?xml version="1.0" encoding="UTF-8"?>

<object numb="12345">
<par1>par10</par1>
<par2>par20</par2>
<par3>par30</par3>
</object>


Приложение:
#define UNICODE

#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <urlmon.h>
#include <hlink.h>
#include <dispex.h>
#include <mshtml.h>
#include <msxml.h>

#define ASSERT(x) if(!(x)) DebugBreak()
#define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
#define SAFERELEASE(p) if (p) {(p)->Release(); p = NULL;} else ;


int _cdecl main (int argc, char **argv)
{
PSTR pszErr = NULL;
IXMLDocument *pDoc = NULL;
IXMLElement *pElem = NULL;
IXMLElementCollection *pChildren = NULL;
BSTR pContent;
BSTR pProperty = L"numb";
VARIANT PropertyValue;
IStream *pStm = NULL;
IPersistStreamInit *pPSI = NULL;
CHAR buf[MAX_PATH];
CHAR *pszURL;

HRESULT hr;

//
// Check usage.
//
if (argc != 2)
{
fprintf (stderr, "Usage: %s URL\n", argv[0]);
fprintf (stderr, "Eg %s c:\\nt\\private\\inet\\xml\\test\\channel.cdf\n", argv[0]);
fprintf (stderr, "or %s http://ohserv/users/julianj/msnbc.cdf\n", argv[0]);
exit (1);
}

//
// HACK if passed in a file name; expand if it doesn't look like a URL.
//
if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, argv[1], 7, "http://", 7) == CSTR_EQUAL)
{
pszURL = argv[1];
}
else
{
pszURL = buf;
GetFullPathNameA(argv[1], MAX_PATH, pszURL, NULL);
}

hr = CoInitialize(NULL);
ASSERT(SUCCEEDED(hr));

//
// Create an empty XML document.
//
hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDocument, (void**)&pDoc);

CHECK_ERROR (pDoc, "CoCreateInstance Failed");

//
// Synchronously create a stream on a URL.
//
hr = URLOpenBlockingStreamA(0, pszURL, &pStm, 0,0);
CHECK_ERROR(SUCCEEDED(hr) && pStm, "Couldn't open stream on URL")
//
// Get the IPersistStreamInit interface to the XML doc.
//
hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
CHECK_ERROR(SUCCEEDED(hr), "QI for IPersistStreamInit failed");

//
// Init the XML doc from the stream.
//
hr = pPSI->Load(pStm);
//CHECK_ERROR(SUCCEEDED(hr), "Couldn't load XML doc from stream");

if(SUCCEEDED(hr))
{
hr = pDoc->get_root(&pElem);
if(SUCCEEDED(hr))
{
hr = pElem->get_tagName(&pContent);
if(SUCCEEDED(hr))
{
SysFreeString(pContent); //pContent = "OBJECT"
}
hr = pElem->getAttribute(pProperty,&PropertyValue);
if(SUCCEEDED(hr))
{
VariantClear(&PropertyValue); //PropertyValue = "12345"
}
hr = pElem->get_text(&pContent);
if(SUCCEEDED(hr))
{
SysFreeString(pContent); //pContent = par10 par20 par30
}
}
}
else
{
// Print error information !
IXMLError *pXMLError = NULL ;
XML_ERROR xmle;

hr = pPSI->QueryInterface(IID_IXMLError, (void **)&pXMLError);
CHECK_ERROR(SUCCEEDED(hr), "Couldn't get IXMLError");

ASSERT(pXMLError);

hr = pXMLError->GetErrorInfo(&xmle);
SAFERELEASE(pXMLError);
CHECK_ERROR(SUCCEEDED(hr), "GetErrorInfo Failed");

printf("%s :", argv[0]);
wprintf(TEXT(" Error on line %d. Found %s while expecting %s\r\n"),
xmle._nLine,
xmle._pszFound,
xmle._pszExpected);

SysFreeString(xmle._pszFound);
SysFreeString(xmle._pszExpected);
SysFreeString(xmle._pchBuf);
}

done: // Clean up.
//
// Release any used interfaces.
//
SAFERELEASE(pPSI);
SAFERELEASE(pStm);
SAFERELEASE(pDoc);

if (pszErr)
fprintf (stderr, "%s, last error %d\n", pszErr, GetLastError());
return 0;
}
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
17042
808
16.02.2009, 13:22
общий
это ответ
Здравствуйте, California!
К сожалению, Вы не указали ни операционную систему, ни среду разработки, с помощью которых Вы намерены производить чтение / запись Xml-документа. Разберём это на примере чтения / записи с использованием DOM-дерева. Код кроссплатформенный, использует модуль XML библиотеки Qt 4.x, т.е. будет работать одинаково под Linux, Windows, MacOS и большинством коммерческих версий Unix. В проекте следует добавить QT += xml
В примере вначале произведём запись приведённой Вами структуры в файл с помощью функции WriteXml (принимает в качестве параметра название файла), а затем произведём синтаксический разбор документа с помощью функции ReadXml. Исходный текст в приложении постарался подробно закомментировать.
Удачи!

Приложение:
//---------------------------------------------------------
#include <iostream> // Стандартный ввод-вывод
using namespace std;
//---------------------------------------------------------
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode> // Доступ к элементам дерева DOM
#include <QFile> // Работа с файлом
#include <QTextStream> // Работа с текстовым потоком
//---------------------------------------------------------
void WriteXml(QString sFileName)
{
QDomDocument ObjectDocument; // Xml-документ
QDomElement Root = ObjectDocument.createElement("object"); // "Корень" документа (тег object)
Root.setAttribute("numb", "12345"); // Устанавливаем его атрибут и значение атрибута
QDomElement Par1Element = ObjectDocument.createElement("par1"); // Создаём параметр 1...
QDomText Par1Text = ObjectDocument.createTextNode("par10"); // ...и текст параметра.
QDomElement Par2Element = ObjectDocument.createElement("par2"); // И т.д.
QDomText Par2Text = ObjectDocument.createTextNode("par20");
QDomElement Par3Element = ObjectDocument.createElement("par3");
QDomText Par3Text = ObjectDocument.createTextNode("par30");

ObjectDocument.appendChild(Root); // Устанавливаем "корень" xml-документа

Root.appendChild(Par1Element); // Устанавливаем его параметры
Root.appendChild(Par2Element);
Root.appendChild(Par3Element);

Par1Element.appendChild(Par1Text); // Пишем в них текст
Par2Element.appendChild(Par2Text);
Par3Element.appendChild(Par3Text);

QFile InputFile(sFileName);
if(InputFile.open(QIODevice::WriteOnly)) // Если удалось открыть файл...
{
QTextStream TextStream(&InputFile);
// Создаём инструкции по обработке xml-документа
QDomNode ProcessingElement = ObjectDocument.createProcessingInstruction("xml", "version="1.0" encoding="utf-8"");
// и записываем их перед первым тегом документа
ObjectDocument.insertBefore(ProcessingElement, ObjectDocument.firstChild());
// Записываем документ в файл (передаём в поток записи).
ObjectDocument.save(TextStream, 4);
InputFile.close(); // Закрываем файл.
}
}
//---------------------------------------------------------
void ReadXml(QString sFileName)
{
QString sValue; // Строка для хранения значения атрибута узла object
QString sPar[3]; // Строки для хранения текста параметров

QDomDocument ObjectDocument; // Xml-документ

if(QFile::exists(sFileName)) // Если файл с таким именем существует, то...
{
QFile OutputFile(sFileName);
if(OutputFile.open(QIODevice::ReadOnly)) // открываем его для чтения...
{
if(!ObjectDocument.setContent(&OutputFile)) // и считываем.
{
OutputFile.close();
cout << "Невозможно прочитать файл!" << endl;
return;
}

QDomElement Root = ObjectDocument.documentElement(); // Устанавливаем "корень" (тег object)
QDomNode DomNode = Root.firstChild(); // Переходим на первый узел после корня
sValue = Root.attribute("numb"); // Читаем значение атрибута корня
QDomElement DomElement;
for(int i = 0; i != 3; i++) // Читаем все параметры,...
{
DomElement = DomNode.toElement(); // преобразуя узел в Dom-элемент
if(DomElement.tagName() == "par1")
{
QDomNode NodeText = DomElement.firstChild();
if(NodeText.nodeType() == QDomNode::TextNode) // Если узел - текстовый...
{
sPar[0] = NodeText.toText().data(); // Считываем текст и присваиваем строке.
}
}
else if(DomElement.tagName() == "par2")
{
QDomNode NodeText = DomElement.firstChild();
if(NodeText.nodeType() == QDomNode::TextNode)
{
sPar[1] = NodeText.toText().data();
}
}
if(DomElement.tagName() == "par3")
{
QDomNode NodeText = DomElement.firstChild();
if(NodeText.nodeType() == QDomNode::TextNode)
{
sPar[2] = NodeText.toText().data();
}
}
DomNode = DomNode.nextSibling(); // Переходим к следующему дочернему узлу корня.
}
}
}

cout << "Значение атрибута "numb" равно " << sValue.toStdString() << endl;
cout << "Первый параметр: " << sPar[0].toStdString() << endl;
cout << "Второй параметр: " << sPar[1].toStdString() << endl;
cout << "Третий параметр: " << sPar[2].toStdString() << endl;
}
//---------------------------------------------------------
int main()
{
WriteXml(QString("Object.xml"));
cout << "Документ записан успешно!" << endl;
ReadXml(QString("Object.xml"));
return 0;
}
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
Неизвестный
19.02.2009, 17:32
общий
а где скачать эту библиотеку пол висту что бы работала
давно
Академик
20764
1861
19.02.2009, 18:18
общий
Google показывает для них первые же ссылки нужные:
http://sourceforge.net/projects/expat/
http://xerces.apache.org/xerces-c/
Порт под windows есть для обоих
давно
Старший Модератор
17042
808
20.02.2009, 06:06
общий
Библиотека Qt работает под Windows, включая Vista. Качать здесь: http://www.qtsoftware.com/downloads
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
давно
Академик
20764
1861
20.02.2009, 08:46
общий
Ставить монстра Qt, потом разбираться с её собственными моделями работы и сборки только для разбора XML (и вообще не для графических задач) - это, по-моему, перебор. Разве что для задач интернационализации, и то лишь потому, что в windows штатные средства можно сказать отсутствуют.

К тому же в одном из его парсеров есть баги - нарывался год назад.
Неизвестный
20.02.2009, 20:09
общий
ну и что вы предлагаете, как уже было сказано, мне необходимо работать с простейшими структурами данных
давно
Академик
20764
1861
20.02.2009, 21:36
общий
Тогда объясните, чем вам не подошли два варианта, предложеных мной и один от Dr_Andrew.
Форма ответа