C++ (Qt)int main(int argc, char *argv[]) { const QSettings::Format XmlFormat = QSettings::registerFormat("xml", readXmlFile, writeXmlFile); QSettings settings(XmlFormat, QSettings::UserSettings, "MySoft", "Star Runner"); ... }
#include <QString>#include <QSettings>class QDomDocument;class QDomElement;class QIODevice;class CXmlSettings{ QSettings * m_pSettings;public: CXmlSettings( QString fname = "" ); ~CXmlSettings(); inline QSettings& settings() const { return *m_pSettings; }; private: static bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map); static bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map); static void processWriteKey( QDomDocument& doc, QDomElement& domElement, QString key, const QVariant& value ); static void processReadKey( QString key, QSettings::SettingsMap &map, QDomElement& domElement );};
#include "XmlSettings.h"#include "FileUtils.h"#include <QDebug>CXmlSettings::CXmlSettings( QString fname ){ if ( fname == "" ) fname = dataPath() + "../Settings/" + appBaseName() + ".xml"; static const QSettings::Format XmlFormat = QSettings::registerFormat("xml", readXmlFile, writeXmlFile); m_pSettings = new QSettings( fname, XmlFormat );};CXmlSettings::~CXmlSettings(){ delete m_pSettings;};bool CXmlSettings::readXmlFile(QIODevice &device, QSettings::SettingsMap &map){ qDebug() << " -----readXmlSettings----- "; QDomDocument doc(""); if ( !doc.setContent( &device ) ) return false; QDomElement root = doc.documentElement(); processReadKey( "", map, root ); return true;};bool CXmlSettings::writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map){ qDebug() << " -----writeXmlSettings----- "; QDomDocument doc(""); QDomElement root = doc.createElement("Main"); doc.appendChild(root); QMapIterator<QString, QVariant> i(map); while ( i.hasNext() ) { i.next(); QString sKey = i.key(); QVariant value = i.value(); processWriteKey( doc, root, sKey, i.value() ); }; QDomNode xmlNode = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"\""); doc.insertBefore(xmlNode, doc.firstChild()); QTextStream out( &device ); doc.save(out, 4); return true;};void CXmlSettings::processWriteKey( QDomDocument& doc, QDomElement& domElement, QString key, const QVariant& value ){ int slashPos = key.indexOf( '/' ); // переданный ключ является параметром if ( slashPos < 0 ) { // не пишем в конфиг параметр size (является ограничением - нельзя исп. пар-тр с таким именем) if ( key == "size" ) return; domElement.setAttribute( key, value.toString() ); return; }; // получение имени группы соответствующей xml ноде QString groupName = key.left( slashPos ); // если в качестве имени использован числовой параметр - это табличная строка, преобразуем ее в row_? if ( groupName.toInt() ) { groupName = "row_" + groupName; domElement.toElement().setAttribute("table", "1"); }; // поиск/создание ноды соответствующей ключу QDomElement groupElement; QDomNodeList findedNodes = domElement.elementsByTagName( groupName ); if ( !findedNodes.count() ) // Заданный элемент-нода не найден - создаем его { groupElement = doc.createElement( groupName ); domElement.appendChild( groupElement ); } else { Q_ASSERT( findedNodes.count() == 1 ); // в конфигах не должно быть несколько элементов с одинаковым именем groupElement = findedNodes.item(0).toElement(); }; // готовим обрезанную часть ключа key = key.right( key.size() - slashPos - 1 ); // продолжение обработки (создание/поиск групп) - пока не найдется параметр processWriteKey( doc, groupElement, key, value );};void CXmlSettings::processReadKey( QString key, QSettings::SettingsMap &map, QDomElement& domElement ){ QDomNamedNodeMap namedNodeMap = domElement.attributes(); // Добавление всех атрибутов элемента в качестве значений for (int i = 0; i < namedNodeMap.count(); ++i) { QString name = namedNodeMap.item( i ).toAttr().name(); QString value = namedNodeMap.item( i ).toAttr().value(); map.insert( key + name, value ); }; QDomNodeList nlChild = domElement.childNodes(); // если узел является таблицей - то все дети строки bool isTable = domElement.attribute("table", "0").toInt(); // создаем доп. элемент size равный числу детей (необходим для QSettings - beginArray) if ( isTable ) map.insert( key + "size", nlChild.count() ); // проход по всем детям for (int i = 0; i < nlChild.count(); ++i) { QString childName = nlChild.item(i).toElement().tagName(); if ( childName.contains("row_") ) childName = childName.right( childName.size() - 4 ); QString subKey = key + childName + "/"; QDomElement subElement = nlChild.item(i).toElement(); processReadKey( subKey, map, subElement ); };};
<?xml version="1.0" encoding=""?><Main root_val_1="1" root_val_2="2" > <FirstChild paramIP="192.168.1.1" > <FirstChildTable table="1" > <row_1 pluginName="XXX" /> <row_2 pluginName="XXX_2" /> </FirstChildTable> </FirstChild> <SecondChild> <SomeParamsGroup Enabled="1" Visible="1" /> </SecondChild></Main>