Go to the documentation of this file.00001 #include <QMap>
00002 #include <QList>
00003 #include <QStringList>
00004 #include <QXmlStreamReader>
00005 #include <QXmlStreamWriter>
00006 #include "utilities/xml_settings.h"
00007
00008 #include <ros/console.h>
00009
00010 namespace utilities
00011 {
00012 const QSettings::Format XmlSettings::format =
00013 QSettings::registerFormat("xml", XmlSettings::read, XmlSettings::write);
00014 const QString XmlSettings::GROUP_SEPARATOR = "/";
00015 const QString XmlSettings::ATTRIBUTE_SEPARATOR = "@";
00016
00017 bool XmlSettings::read(QIODevice& device, QSettings::SettingsMap& map)
00018 {
00019 QXmlStreamReader xml_reader(&device);
00020 QStringList groups;
00021 bool multiple_elements(false);
00022 while (!xml_reader.atEnd())
00023 {
00024 xml_reader.readNext();
00025 if (xml_reader.isStartElement())
00026 {
00027 groups.append(xml_reader.name().toString());
00028 multiple_elements = map.contains(groups.join(GROUP_SEPARATOR));
00029 QXmlStreamAttributes attributes(xml_reader.attributes());
00030 for (size_t i(0); i < attributes.count(); i++)
00031 {
00032 QString name(groups.join(GROUP_SEPARATOR) + "/" + ATTRIBUTE_SEPARATOR +
00033 attributes[i].name().toString());
00034 if (!multiple_elements)
00035 {
00036 map[name] = attributes[i].value().toString();
00037 }
00038 else
00039 {
00040 QString values;
00041 if (!map.contains(name))
00042 {
00043 for (size_t j(0); j < i; j++)
00044 {
00045 values += ",";
00046 }
00047 values = "[" + values + "]";
00048 }
00049 values = map[name].toString();
00050 int count(values.count());
00051 QStringRef values_ref(&values, values[0] == '[' ? 1 : 0,
00052 count - (values[count - 1] == ']' ? 2 : 0));
00053 map[name] = "[" + values_ref.toString() + "," +
00054 xml_reader.text().toString() + "]";
00055 }
00056 }
00057 }
00058 else if (xml_reader.isCharacters() && !xml_reader.isWhitespace())
00059 {
00060 if (!multiple_elements)
00061 {
00062 map[groups.join(GROUP_SEPARATOR)] = xml_reader.text().toString();
00063 }
00064 else
00065 {
00066 QString values(map[groups.join(GROUP_SEPARATOR)].toString());
00067 int count(values.count());
00068 QStringRef values_ref(&values, values[0] == '[' ? 1 : 0,
00069 count - (values[count - 1] == ']' ? 2 : 0));
00070 map[groups.join(GROUP_SEPARATOR)] = "[" + values_ref.toString() + "," +
00071 xml_reader.text().toString() + "]";
00072 }
00073 }
00074 else if (xml_reader.isEndElement())
00075 {
00076 groups.removeLast();
00077 }
00078 }
00079 ROS_WARN("[XmlSettings] reading ...");
00080 for (QSettings::SettingsMap::iterator it(map.begin()); it != map.end(); it++)
00081 {
00082 ROS_WARN_STREAM(it.key().toStdString() << ": " << it.value().toString().toStdString());
00083 }
00084 return !xml_reader.hasError();
00085 }
00086
00087 bool XmlSettings::write(QIODevice& device, const QSettings::SettingsMap& map)
00088 {
00089 ROS_WARN("[XmlSettings] writing ...");
00090 for (QSettings::SettingsMap::iterator it(map.begin()); it != map.end(); it++)
00091 {
00092 ROS_WARN_STREAM(it.key().toStdString() << ": " << it.value().toString().toStdString());
00093 }
00094 struct NestedMap;
00095 typedef QSharedPointer<NestedMap> NestedQSharedPointer;
00096 struct NestedMap : QMap<QString, NestedQSharedPointer>
00097 {
00098 };
00099 NestedQSharedPointer nested_map(new NestedMap());
00100 for (QSettings::SettingsMap::const_iterator it(map.begin()); it != map.end();
00101 ++it)
00102 {
00103 NestedQSharedPointer current_map(nested_map);
00104 QStringList groups(it.key().split(GROUP_SEPARATOR));
00105 for (QStringList::const_iterator jt(groups.begin()); jt != groups.end();
00106 ++jt)
00107 {
00108 NestedMap::iterator kt(current_map->find(*jt));
00109 if (kt == current_map->end())
00110 {
00111 kt = current_map->insert(*jt, NestedQSharedPointer(new NestedMap()));
00112 }
00113 current_map = kt.value();
00114 }
00115 }
00116 QXmlStreamWriter xml_writer(&device);
00117 xml_writer.setAutoFormatting(true);
00118 ROS_WARN_STREAM("[XmlSettings::write] writeStartDocument()");
00119 xml_writer.writeStartDocument();
00120 QStringList groups;
00121 QList<NestedQSharedPointer> nested_maps;
00122 QList<NestedMap::iterator> nested_map_iterators;
00123 nested_maps.append(nested_map);
00124 nested_map_iterators.append(nested_map->begin());
00125 QString tag;
00126 QString attribute;
00127 int value_index(0);
00128 while (!nested_maps.isEmpty())
00129 {
00130 ROS_WARN_STREAM("[XmlSettings::write] groups: " << groups.join("/").toStdString());
00131 NestedQSharedPointer current_map(nested_maps.last());
00132 NestedMap::iterator it(nested_map_iterators.last());
00133 if (it != current_map->end())
00134 {
00135 tag = it.key();
00136 if (it.key().startsWith(ATTRIBUTE_SEPARATOR))
00137 {
00138 attribute = it.key().right(it.key().count() - 1);
00139 }
00140 else
00141 {
00142 ROS_WARN_STREAM("[XmlSettings::write] writeStartElement(" << it.key().toStdString() << ")");
00143 xml_writer.writeStartElement(it.key());
00144 }
00145 groups.append(it.key());
00146 nested_maps.append(it.value());
00147 nested_map_iterators.append(it.value()->begin());
00148 }
00149 else
00150 {
00151 if (current_map->isEmpty())
00152 {
00153 QString value(map[groups.join(GROUP_SEPARATOR)].toString());
00154 if (!attribute.isEmpty())
00155 {
00156 ROS_WARN_STREAM("[XmlSettings::write] writeAttribute(" << attribute.toStdString()
00157 << "," << map[groups.join(GROUP_SEPARATOR)].toString().toStdString() << ")");
00158 xml_writer.writeAttribute(
00159 attribute, map[groups.join(GROUP_SEPARATOR)].toString());
00160 if (groups.isEmpty())
00161 {
00162 nested_maps.removeLast();
00163 nested_map_iterators.removeLast();
00164 if (!nested_maps.isEmpty())
00165 {
00166 ++nested_map_iterators.last();
00167 }
00168 continue;
00169 }
00170 groups.removeLast();
00171 value = map[groups.join(GROUP_SEPARATOR)].toString();
00172 groups.append("@" + attribute);
00173 }
00174 if (value.startsWith("[") && value.endsWith("]"))
00175 {
00176 QStringRef value_ref(&value, 1, value.count() - 2);
00177 QStringList values(value_ref.toString().split(","));
00178 value = values[value_index];
00179 value_index = value_index == values.count() - 1 ? 0 : value_index + 1;
00180 }
00181 if (!value.isEmpty())
00182 {
00183 ROS_WARN_STREAM("[XmlSettings::write] writeCharacters(" << value.toStdString() << ")");
00184 xml_writer.writeCharacters(value);
00185 }
00186 if (value_index > 0)
00187 {
00188 ROS_WARN_STREAM("[XmlSettings::write] writeEndElement()");
00189 xml_writer.writeEndElement();
00190 ROS_WARN_STREAM("[XmlSettings::write] writeStartElement(" << tag.toStdString() << ")");
00191 xml_writer.writeStartElement(tag);
00192 continue;
00193 }
00194 }
00195 if (!attribute.isEmpty())
00196 {
00197 if (!groups.isEmpty())
00198 {
00199 groups.removeLast();
00200 }
00201 nested_maps.removeLast();
00202 nested_map_iterators.removeLast();
00203 if (!nested_maps.isEmpty())
00204 {
00205 ++nested_map_iterators.last();
00206 }
00207 attribute.clear();
00208 }
00209 ROS_WARN_STREAM("[XmlSettings::write] writeEndElement()");
00210 xml_writer.writeEndElement();
00211 if (!groups.isEmpty())
00212 {
00213 groups.removeLast();
00214 }
00215 nested_maps.removeLast();
00216 nested_map_iterators.removeLast();
00217 if (!nested_maps.isEmpty())
00218 {
00219 ++nested_map_iterators.last();
00220 }
00221 }
00222 }
00223 ROS_WARN_STREAM("[XmlSettings::write] writeEndDocument()");
00224 xml_writer.writeEndDocument();
00225 return true;
00226 }
00227 }