File indexing completed on 2024-04-21 04:52:32

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "xml.hpp"
0007 #include <QDebug>
0008 #include <QFile>
0009 #include <QSaveFile>
0010 
0011 // static
0012 bool Xml::docContentFromFile(QDomDocument &doc, const QString &fileName, bool namespaceProcessing)
0013 {
0014     QFile file(fileName);
0015     if (!file.open(QIODevice::ReadOnly)) {
0016         qWarning() << "Failed to open file" << file.fileName() << "for reading";
0017         return false;
0018     }
0019     if (!doc.setContent(&file, namespaceProcessing)) {
0020         qWarning() << "Failed to parse file" << file.fileName() << "to QDomDocument";
0021         file.close();
0022         return false;
0023     }
0024     file.close();
0025     return true;
0026 }
0027 
0028 bool Xml::docContentToFile(const QDomDocument &doc, const QString &fileName)
0029 {
0030     QSaveFile file(fileName);
0031     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
0032         qWarning() << "Cannot write to file" << file.fileName();
0033         return false;
0034     }
0035     file.write(doc.toString().toUtf8());
0036     if (!file.commit()) {
0037         qWarning() << "Error while writing to file" << file.fileName();
0038         return false;
0039     }
0040     return true;
0041 }
0042 
0043 QString Xml::getSubTagContent(const QDomElement &element, const QString &tagName)
0044 {
0045     QVector<QDomNode> nodeList = getDirectChildrenByTagName(element, tagName);
0046     if (!nodeList.isEmpty()) {
0047         if (nodeList.size() > 1) {
0048             QString str;
0049             QTextStream stream(&str);
0050             element.save(stream, 4);
0051             qDebug() << "Warning: " << str << "provides several " << tagName << ". We keep only first one.";
0052         }
0053         QString content = nodeList.at(0).toElement().text();
0054         return content;
0055     }
0056     return QString();
0057 }
0058 
0059 QVector<QDomNode> Xml::getDirectChildrenByTagName(const QDomElement &element, const QString &tagName)
0060 {
0061     auto children = element.childNodes();
0062     QVector<QDomNode> result;
0063     for (int i = 0; i < children.count(); ++i) {
0064         if (children.item(i).isNull() || !children.item(i).isElement()) {
0065             continue;
0066         }
0067         QDomElement child = children.item(i).toElement();
0068         if (child.tagName() == tagName) {
0069             result.push_back(child);
0070         }
0071     }
0072     return result;
0073 }
0074 
0075 QString Xml::getTagContentByAttribute(const QDomElement &element, const QString &tagName, const QString &attribute, const QString &value,
0076                                       const QString &defaultReturn, bool directChildren)
0077 {
0078     QDomNodeList nodes;
0079     if (directChildren) {
0080         nodes = element.childNodes();
0081     } else {
0082         nodes = element.elementsByTagName(tagName);
0083     }
0084     for (int i = 0; i < nodes.count(); ++i) {
0085         auto current = nodes.item(i);
0086         if (current.isNull() || !current.isElement()) {
0087             continue;
0088         }
0089         auto elem = current.toElement();
0090         if (elem.tagName() == tagName && elem.hasAttribute(attribute)) {
0091             if (elem.attribute(attribute) == value) {
0092                 return elem.text();
0093             }
0094         }
0095     }
0096     return defaultReturn;
0097 }
0098 
0099 void Xml::addXmlProperties(QDomElement &element, const std::unordered_map<QString, QString> &properties)
0100 {
0101     for (const auto &p : properties) {
0102         QDomElement prop = element.ownerDocument().createElement(QStringLiteral("property"));
0103         prop.setAttribute(QStringLiteral("name"), p.first);
0104         QDomText value = element.ownerDocument().createTextNode(p.second);
0105         prop.appendChild(value);
0106         element.appendChild(prop);
0107     }
0108 }
0109 
0110 void Xml::addXmlProperties(QDomElement &element, const QMap<QString, QString> &properties)
0111 {
0112     QMapIterator<QString, QString> i(properties);
0113     while (i.hasNext()) {
0114         i.next();
0115         QDomElement prop = element.ownerDocument().createElement(QStringLiteral("property"));
0116         prop.setAttribute(QStringLiteral("name"), i.key());
0117         QDomText value = element.ownerDocument().createTextNode(i.value());
0118         prop.appendChild(value);
0119         element.appendChild(prop);
0120     }
0121 }
0122 
0123 QString Xml::getXmlProperty(const QDomElement &element, const QString &propertyName, const QString &defaultReturn)
0124 {
0125     return Xml::getTagContentByAttribute(element, QStringLiteral("property"), QStringLiteral("name"), propertyName, defaultReturn, false);
0126 }
0127 
0128 QString Xml::getXmlParameter(const QDomElement &element, const QString &propertyName, const QString &defaultReturn)
0129 {
0130     return Xml::getTagContentByAttribute(element, QStringLiteral("parameter"), QStringLiteral("name"), propertyName, defaultReturn, false);
0131 }
0132 
0133 void Xml::setXmlProperty(QDomElement element, const QString &propertyName, const QString &value)
0134 {
0135     QDomNodeList params = element.elementsByTagName(QStringLiteral("property"));
0136     // Update property if it already exists
0137     bool found = false;
0138     for (int i = 0; i < params.count(); ++i) {
0139         QDomElement e = params.item(i).toElement();
0140         if (e.attribute(QStringLiteral("name")) == propertyName) {
0141             if (e.hasChildNodes()) {
0142                 e.firstChild().setNodeValue(value);
0143             } else {
0144                 QDomText resourceValue = element.ownerDocument().createTextNode(value);
0145                 e.appendChild(resourceValue);
0146             }
0147             found = true;
0148             break;
0149         }
0150     }
0151     if (!found) {
0152         // create property
0153         QMap<QString, QString> map;
0154         map.insert(propertyName, value);
0155         addXmlProperties(element, map);
0156     }
0157 }
0158 
0159 void Xml::setXmlParameter(const QDomElement &element, const QString &propertyName, const QString &value)
0160 {
0161     QDomNodeList params = element.elementsByTagName(QStringLiteral("parameter"));
0162     // Update property if it already exists
0163     for (int i = 0; i < params.count(); ++i) {
0164         QDomElement e = params.item(i).toElement();
0165         if (e.attribute(QStringLiteral("name")) == propertyName) {
0166             e.setAttribute(QStringLiteral("value"), value);
0167             break;
0168         }
0169     }
0170 }
0171 
0172 bool Xml::hasXmlParameter(const QDomElement &element, const QString &propertyName)
0173 {
0174     QDomNodeList params = element.elementsByTagName(QStringLiteral("parameter"));
0175     for (int i = 0; i < params.count(); ++i) {
0176         QDomElement e = params.item(i).toElement();
0177         if (e.attribute(QStringLiteral("name")) == propertyName) {
0178             return true;
0179         }
0180     }
0181     return false;
0182 }
0183 
0184 bool Xml::hasXmlProperty(const QDomElement &element, const QString &propertyName)
0185 {
0186     QDomNodeList params = element.elementsByTagName(QStringLiteral("property"));
0187     for (int i = 0; i < params.count(); ++i) {
0188         QDomElement e = params.item(i).toElement();
0189         if (e.attribute(QStringLiteral("name")) == propertyName) {
0190             return true;
0191         }
0192     }
0193     return false;
0194 }
0195 
0196 QMap<QString, QString> Xml::getXmlPropertyByWildcard(const QDomElement &element, const QString &propertyName)
0197 {
0198     QMap<QString, QString> props;
0199     QDomNodeList params = element.elementsByTagName(QStringLiteral("property"));
0200     for (int i = 0; i < params.count(); ++i) {
0201         QDomElement e = params.item(i).toElement();
0202         if (e.attribute(QStringLiteral("name")).startsWith(propertyName)) {
0203             props.insert(e.attribute(QStringLiteral("name")), e.text());
0204         }
0205     }
0206     return props;
0207 }
0208 
0209 void Xml::removeXmlProperty(QDomElement effect, const QString &name)
0210 {
0211     QDomNodeList params = effect.elementsByTagName(QStringLiteral("property"));
0212     for (int i = 0; i < params.count(); ++i) {
0213         QDomElement e = params.item(i).toElement();
0214         if (e.attribute(QStringLiteral("name")) == name) {
0215             effect.removeChild(params.item(i));
0216             break;
0217         }
0218     }
0219 }
0220 
0221 void Xml::renameXmlProperty(const QDomElement &effect, const QString &oldName, const QString &newName)
0222 {
0223     QDomNodeList params = effect.elementsByTagName(QStringLiteral("property"));
0224     // Update property if it already exists
0225     for (int i = 0; i < params.count(); ++i) {
0226         QDomElement e = params.item(i).toElement();
0227         if (e.attribute(QStringLiteral("name")) == oldName) {
0228             e.setAttribute(QStringLiteral("name"), newName);
0229             break;
0230         }
0231     }
0232 }
0233 
0234 void Xml::removeMetaProperties(QDomElement producer)
0235 {
0236     QDomNodeList params = producer.elementsByTagName(QStringLiteral("property"));
0237     for (int i = 0; i < params.count(); ++i) {
0238         QDomElement e = params.item(i).toElement();
0239         if (e.attribute(QStringLiteral("name")).startsWith(QLatin1String("meta"))) {
0240             producer.removeChild(params.item(i));
0241             --i;
0242         }
0243     }
0244 }