/** * @RDE_HEADER@ * Parse building xml file and create MainStructureElementCreateRequest for the data * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2017-02-02 */ #include "parse_building_xml.h" #include #include #include #include #include #include #include //------------------------------------------------------------------------------------------------------------- namespace InfrastructureManagement { class XmlImportException : public std::exception { public: explicit XmlImportException(const QString &msg) noexcept : m_msg(msg.toUtf8().data()) {} ~XmlImportException() = default; virtual const char *what() const noexcept { return m_msg.c_str(); } private: const std::string m_msg; }; //------------------------------------------------------------------------------------------------------------- template static inline T positionFromElement(const QDomElement &elem) { return T(elem.attribute(QStringLiteral("X")).toDouble(), elem.attribute(QStringLiteral("Y")).toDouble(), elem.attribute(QStringLiteral("Z")).toDouble()); } //------------------------------------------------------------------------------------------------------------- ParseBuildingXml::ParseBuildingXml(const QString &xmlFilename, const QString &vulnerabilityFilename, const QString &egcuToRoomFilename, const QString &soundAreaFilename, const Core::GeoPosition &geoPosition, double rotationAngleDegree) : m_xmlFilename(xmlFilename) , m_vulnerabilityFilename(vulnerabilityFilename) , m_egcuToRoomFilename(egcuToRoomFilename) , m_soundAreaFilename(soundAreaFilename) , m_geoPosition(geoPosition) , m_rotationAngleDegree(rotationAngleDegree) , m_logger(getLogger("ParseBuildingXml")) { DEBUG_LOG(m_logger) << "m_soundAreaFilename=" << m_soundAreaFilename; } QJsonObject ParseBuildingXml::egcusToJson() const { DEBUG_LOG(m_logger) << "egcusToJson"; if (m_egcus.isEmpty()) return QJsonObject(); QJsonObject egcusToRooms; QJsonArray egcus; QJsonArray rooms; for (const auto &egcu : m_egcus) { rooms = {}; for (const int room : egcu.rooms) rooms += room; QJsonObject json; json[QStringLiteral("mountpointEgcu")] = egcu.mountpointEgcu; json[QStringLiteral("rooms")] = rooms; egcus += json; } egcusToRooms[QStringLiteral("egcusToRooms")] = egcus; return egcusToRooms; } QJsonObject ParseBuildingXml::soundAreaToJson() const { DEBUG_LOG(m_logger) << "soundAreaToJson"; QJsonObject soundArea; QJsonObject json; QJsonObject jsonEgcu; QJsonArray arrayGeometry; for (const auto &point : m_soundArea.geometry) { json[QStringLiteral("lat")] = point.lat(); json[QStringLiteral("lon")] = point.lon(); arrayGeometry.append(json); } QJsonArray arrayEgcus; for (const auto &id : m_soundArea.egcuMountpoints) { jsonEgcu[QStringLiteral("id")] = id; arrayEgcus.append(jsonEgcu); } soundArea[QStringLiteral("id")] = m_soundArea.id; soundArea[QStringLiteral("geometry")] = arrayGeometry; soundArea[QStringLiteral("mainEgcuMountpoint")] = m_soundArea.mainEgcuMountpoint; soundArea[QStringLiteral("egcuMountpoints")] = arrayEgcus; return soundArea; } //------------------------------------------------------------------------------------------------------------- bool ParseBuildingXml::parseXml() { DEBUG_LOG(m_logger) << "parseXml"; m_request = MainStructureElementModifyRequest(); m_request.properties("{}"); m_lastError.clear(); bool bRet = true; parseXmlInternal(); // try // { // parseXmlInternal(); // if (!m_vulnerabilityFilename.isEmpty()) // { // QDomDocument doc = openXml(m_vulnerabilityFilename); // if (!doc.isNull()) // { // const QByteArray compressed = qCompress(doc.toByteArray(), 9); // m_request.vulnerabilityData(LtsUtils::convert>(compressed)); // } // } // } // catch (const std::exception &ex) // { // m_lastError = QString::fromUtf8(ex.what()); // WARNING_LOG(m_logger) << "Error importing building: " << ex.what(); // m_request = MainStructureElementModifyRequest(); // return false; // } QJsonObject properties; parseXmlEgcus(); QJsonObject egcus = egcusToJson(); properties[QStringLiteral("egcusToRooms")] = egcus[QStringLiteral("egcusToRooms")]; DEBUG_LOG(m_logger) << "parseXml vor isEmpty"; if (!m_soundAreaFilename.isEmpty()) { DEBUG_LOG(m_logger) << "parseXml vor parseXmlSoundArea"; parseXmlSoundArea(); properties[QStringLiteral("soundArea")] = soundAreaToJson(); } m_request.properties(QJsonDocument(properties).toJson(QJsonDocument::Compact).toStdString()); DEBUG_LOG(m_logger) << "Finished import for file " << m_xmlFilename; return bRet; } //------------------------------------------------------------------------------------------------------------- ParseBuildingXml::Egcu ParseBuildingXml::parseEgcu(const QDomElement &domEgcu) { ParseBuildingXml::Egcu ret; INFO_LOG(m_logger) << "parseEgcu Egcu: = " << domEgcu.tagName(); QDomElement mountpoint = domEgcu.firstChildElement(QStringLiteral("Mountpoint")); INFO_LOG(m_logger) << "Mountpoint=" << mountpoint.tagName(); QDomElement mountpointSubId = mountpoint.firstChildElement(QStringLiteral("SubId")); INFO_LOG(m_logger) << "Mountpoint=" << mountpointSubId.tagName() << " SubId = " << mountpointSubId.attribute(QStringLiteral("SubId")) << " text= " << mountpointSubId.text(); ret.mountpointEgcu = mountpointSubId.text().toInt(); QDomElement rooms = domEgcu.firstChildElement(QStringLiteral("Rooms")); INFO_LOG(m_logger) << "Rooms=" << rooms.tagName() << " SubId = " << rooms.attribute(QStringLiteral("SubId")) << " text = " << rooms.text(); QDomElement room = rooms.firstChildElement(QStringLiteral("SubId")); for (; !room.isNull(); room = room.nextSiblingElement(room.tagName())) { INFO_LOG(m_logger) << "Room=" << room.tagName() << " SubId = " << room.attribute(QStringLiteral("SubId")) << " text = " << room.text(); ret.rooms.append(room.text().toInt()); } return ret; } bool ParseBuildingXml::parseXmlEgcus() { m_lastError.clear(); bool bRet = true; try { //parseXmlInternal(); INFO_LOG(m_logger) << "parseXmlEgcus " << m_egcuToRoomFilename; if (!m_egcuToRoomFilename.isEmpty()) { INFO_LOG(m_logger) << "openXml"; QDomDocument doc = openXml(m_egcuToRoomFilename); if (!doc.isNull()) { // Evaluate xml file and modify properties in m_request QDomElement root = doc.documentElement(); INFO_LOG(m_logger) << "root.tagName()=" << root.tagName(); if (root.tagName() != QStringLiteral("EgcusToRooms")) { WARNING_LOG(m_logger) << "The file is not EgcusToRooms"; return false; } QDomElement domEgcu = root.firstChildElement(QStringLiteral("Egcu")); if (domEgcu.isNull()) INFO_LOG(m_logger) << "Keine EGCU's"; for (; !domEgcu.isNull(); domEgcu = domEgcu.nextSiblingElement(domEgcu.tagName())) { INFO_LOG(m_logger) << "parseEgcus=" << domEgcu.tagName() << " text=" << domEgcu.text() << " Name=" << domEgcu.attribute(QStringLiteral("Name")); const Egcu egcu = parseEgcu(domEgcu); m_egcus.append(egcu); } } } } catch (const std::exception &ex) { m_lastError = QString::fromUtf8(ex.what()); WARNING_LOG(m_logger) << "Error importing building: wrong XML-File EgcuToRooms: " << ex.what(); bRet = false; } return bRet; } //------------------------------------------------------------------------------------------------------------- bool ParseBuildingXml::parseXmlSoundArea() { Core::GeoPosition geoPosition; m_lastError.clear(); bool bRet = true; try { //parseXmlInternal(); INFO_LOG(m_logger) << "parseXmlSoundArea " << m_soundAreaFilename; if (!m_soundAreaFilename.isEmpty()) { INFO_LOG(m_logger) << "openXml"; QDomDocument doc = openXml(m_soundAreaFilename); if (!doc.isNull()) { // Evaluate xml file and modify properties in m_request QDomElement root = doc.documentElement(); INFO_LOG(m_logger) << "root.tagName()=" << root.tagName(); if (root.tagName() != QStringLiteral("SoundArea")) { WARNING_LOG(m_logger) << "The file is not SoundArea"; return false; } INFO_LOG(m_logger) << "parseSoundArea SoundArea: = " << root.tagName(); // Id m_soundArea.id = root.firstChildElement(QStringLiteral("Id")).text().toInt(); INFO_LOG(m_logger) << "Id=" << m_soundArea.id; // Geometry QDomElement geometry = root.firstChildElement(QStringLiteral("Geometry")); QDomElement point = geometry.firstChildElement(QStringLiteral("Point")); for (; !point.isNull(); point = point.nextSiblingElement(point.tagName())) { INFO_LOG(m_logger) << "Point=" << point.tagName() << " lat = " << point.firstChildElement(QStringLiteral("lat")).text().toDouble() << " lon = " << point.firstChildElement(QStringLiteral("lon")).text().toDouble(); geoPosition.lat(point.firstChildElement(QStringLiteral("lat")).text().toDouble()); geoPosition.lon(point.firstChildElement(QStringLiteral("lon")).text().toDouble()); m_soundArea.geometry.push_back(geoPosition); } // MainEgcuMountpoint m_soundArea.mainEgcuMountpoint = root.firstChildElement(QStringLiteral("MainEgcuMountpoint")).text().toInt(); DEBUG_LOG(m_logger) << "MainEgcuMountpoint Id=" << m_soundArea.mainEgcuMountpoint; // MountpointsEgcu QDomElement egcuMountpoints = root.firstChildElement(QStringLiteral("EgcuMountpoints")); QDomElement id = egcuMountpoints.firstChildElement(QStringLiteral("Id")); for (; !id.isNull(); id = id.nextSiblingElement(id.tagName())) { int mountpointEgcu = id.text().toInt(); DEBUG_LOG(m_logger) << "mountpointEgcu=" << mountpointEgcu; m_soundArea.egcuMountpoints.push_back(mountpointEgcu); } } } } catch (const std::exception &ex) { m_lastError = QString::fromUtf8(ex.what()); WARNING_LOG(m_logger) << "Error importing building: wrong XML-File EgcuToRooms: " << ex.what(); bRet = false; } return bRet; } //------------------------------------------------------------------------------------------------------------- QDomDocument ParseBuildingXml::openXml(const QString &fileName) const { // check filename is empty if (fileName.isEmpty()) throw XmlImportException(tr("Empty filename!")); // check if metaFileName is a valid xml file QFile f(fileName); if (f.size() == 0) return QDomDocument(); if (!f.open(QIODevice::ReadOnly)) throw XmlImportException(tr("Error opening file %1: %2").arg(fileName, f.errorString())); // read Xml file QDomDocument metaDoc; int errLine = 0, errColumn = 0; QString err; if (!metaDoc.setContent(&f, &err, &errLine, &errColumn)) throw XmlImportException(tr("Error parsing file content: %1 at %2.%3").arg(err).arg(errLine).arg(errColumn)); // close metaFile f.close(); return metaDoc; } //------------------------------------------------------------------------------------------------------------- QVector ParseBuildingXml::parseMetaXml(const QString &metaXml) const { QVector ret; const QDomDocument metaDoc = openXml(metaXml); if (metaDoc.isNull()) return ret; // parse metaDoc for building elements MetaData/Tag/Group/Feature+Orientation+Position+File const QDomElement metaElem = getChildElement(metaDoc, QStringLiteral("MetaData")); const QDomElement tagElem = getChildElement(metaElem, QStringLiteral("Tag")); const QDomElement groupElem = getChildElement(tagElem, QStringLiteral("Group")); QDomElement modelElem = getChildElement(groupElem, QStringLiteral("Model")); for (; !modelElem.isNull(); modelElem = modelElem.nextSiblingElement(modelElem.tagName())) { const QDomElement orientationElem = getChildElement(modelElem, QStringLiteral("Orientation")); const QDomElement posElem = getChildElement(modelElem, QStringLiteral("Position")); const QDomElement streifElem = getChildElement(modelElem, QStringLiteral("STREIF")); // read building file name, name, angle, position ParseBuildingXml::BuildingMetaInfo info; info.filename = streifElem.attribute(QLatin1String("Name")); if (info.filename.isEmpty()) { WARNING_LOG(m_logger) << "Empty filename (building)!"; continue; } info.rotationAngleDegree = orientationElem.attribute(QLatin1String("Angle")).toDouble(); // correct rotation? INFO_LOG(m_logger) << "Found Building angle: " << info.rotationAngleDegree; info.geoPosition = positionFromElement(posElem); INFO_LOG(m_logger) << "Found Building position: (" << info.geoPosition.lon() << ", (" << info.geoPosition.lat() << ", (" << info.geoPosition.z() << ")"; ret += info; } return ret; } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::parseXmlInternal() { const QDomDocument objDoc = openXml(m_xmlFilename); if (objDoc.isNull()) throw XmlImportException(tr("xml file %1 is empty").arg(m_xmlFilename)); const QDomElement rootElem = objDoc.documentElement(); // STREIF const QDomElement headerElem = getChildElement(rootElem, QStringLiteral("Header")); const QDomElement baseGroupElem = getChildElement(headerElem, QStringLiteral("Group")); DEBUG_LOG(m_logger) << "Start import for file " << m_xmlFilename; m_request.angle(m_rotationAngleDegree); m_request.geoPosition(m_geoPosition); m_request.modelId(getInteger(getChildElement(baseGroupElem, QStringLiteral("ModelId")), QStringLiteral("Id"))); m_request.name(getChildElement(baseGroupElem, QStringLiteral("Name")).text().toStdString()); m_request.description(m_request.name()); INFO_LOG(m_logger) << "Importing building with name: " << m_request.name(); InfrastructureManagement::StructureElement seBuilding; seBuilding.name(m_request.name()); seBuilding.displayName(m_request.name()); seBuilding.structureElementTypeId(InfrastructureManagement::StructureElementType::Building); seBuilding.mountingPointTypeId(InfrastructureManagement::MountingPointType::Unknown); seBuilding.properties("{}"); addElementToRequest(seBuilding, -1); InfrastructureManagement::StructureElement seMPBuilding; seMPBuilding.name(m_request.name()); seMPBuilding.displayName(m_request.name()); m_buildingName = QString::fromStdString(seBuilding.displayName()); seMPBuilding.structureElementTypeId(InfrastructureManagement::StructureElementType::MountingPoint); seMPBuilding.mountingPointTypeId(InfrastructureManagement::MountingPointType::BuildingControlUnit); seMPBuilding.properties("{}"); addElementToRequest(seMPBuilding, 0); //SWPA 2/22 - GUEZE-1459 - IO 2022.11.10 - do not import GV for new Guez Buildings #ifndef GUEZ_MODE InfrastructureManagement::StructureElement seGVBuilding; seGVBuilding.name(m_request.name()+std::string("_gv")); seGVBuilding.displayName(m_request.name()+std::string("_gv")); seGVBuilding.structureElementTypeId(InfrastructureManagement::StructureElementType::MountingPoint); seGVBuilding.mountingPointTypeId(InfrastructureManagement::MountingPointType::BuildingNetworkSwitch); seGVBuilding.properties("{}"); addElementToRequest(seGVBuilding, 0); #endif // all below building, not below building bcu mounting point const int parentIdx = 0; importFootprint(baseGroupElem); importExternalReferences(baseGroupElem, parentIdx); importFloors(baseGroupElem, parentIdx); } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::importFootprint(const QDomElement &parent) { QDomElement groupElem = parent.firstChildElement(QStringLiteral("Group")); std::vector fp; for (; !groupElem.isNull(); groupElem = groupElem.nextSiblingElement(groupElem.tagName())) { const QDomElement nameElement = getChildElement(groupElem, QStringLiteral("Name"), false); if (!nameElement.text().startsWith(QLatin1String("FOOTPRINT"), Qt::CaseInsensitive)) continue; const QDomElement polygonElem = getChildElement(groupElem, QStringLiteral("Polygon"), false); if (polygonElem.isNull()) continue; QDomElement vertexElem = polygonElem.firstChildElement(QStringLiteral("Vertex")); for (; !vertexElem.isNull(); vertexElem = vertexElem.nextSiblingElement(vertexElem.tagName())) { // TODO: xml hat keine Reihenfolge! Man kann es anhand der Namen sortieren const QDomElement coordElem = vertexElem.firstChildElement(QStringLiteral("Coord")); if (coordElem.isNull()) continue; FootprintElement fpElem; fpElem.relPosition() = positionFromElement(coordElem); fp.resize(fp.size() + 1, fpElem); } break; } if (fp.size() > 0) m_request.footprint(std::move(fp)); } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::importExternalReferences(const QDomElement &parent, int parentIdx) { QDomElement extRefElem = parent.firstChildElement(QStringLiteral("External_Reference")); for (; !extRefElem.isNull(); extRefElem = extRefElem.nextSiblingElement(extRefElem.tagName())) { const StructureElement se = getStructureElement(extRefElem); // we don't care about BCU Mounting positions inside xml file - we create our own if (se.mountingPointTypeId() == MountingPointType::BuildingControlUnit) { INFO_LOG(m_logger) << "Ignoring xml-internal BuildingControl mounting point - not needed"; continue; } if (se.mountingPointTypeId() == MountingPointType::Unknown) { INFO_LOG(m_logger) << "Ignoring unknown mounting point type with subId " << se.mountingPointId(); continue; } INFO_LOG(m_logger) << "importExternalReferences: " << se.displayName() << ", parentIdx = " << parentIdx; addElementToRequest(se, parentIdx); } } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::importFloors(const QDomElement &parent, int parentIdx) { QDomElement floorElem = parent.firstChildElement(QStringLiteral("Group")); for (; !floorElem.isNull(); floorElem = floorElem.nextSiblingElement(floorElem.tagName())) { const QDomElement nameElement = getChildElement(floorElem, QStringLiteral("Name"), false); if (!nameElement.text().startsWith(QLatin1String("floor_"), Qt::CaseInsensitive)) continue; INFO_LOG(m_logger) << "importFloors: " << nameElement.text() << ", parentIdx = " << parentIdx; StructureElement se; se.name(nameElement.text().simplified().toStdString()); se.displayName(se.name()); se.structureElementTypeId(InfrastructureManagement::StructureElementType::Floor); se.mountingPointTypeId(InfrastructureManagement::MountingPointType::Unknown); se.properties("{}"); // read base height from xml comment const QDomElement commentElement = getChildElement(floorElem, QStringLiteral("Comment"), false); DEBUG_LOG(m_logger) << "Comment = " << commentElement.text(); const QStringList comm = commentElement.text().split(QLatin1Char('=')); double baseHeight = 0.00; if (comm.at(0) == QStringLiteral("base_height")) baseHeight = comm.at(1).toDouble(); DEBUG_LOG(m_logger) << "base_height = " << baseHeight; se.relPosition().offsetZ(baseHeight); addElementToRequest(se, parentIdx); const int curIdx = m_request.elements().size() - 1; importRooms(floorElem, curIdx); } } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::importRooms(const QDomElement &parent, int parentIdx) { QDomElement roomElem = parent.firstChildElement(QStringLiteral("Switch")); for (; !roomElem.isNull(); roomElem = roomElem.nextSiblingElement(roomElem.tagName())) { const QDomElement nameElement = getChildElement(roomElem, QStringLiteral("Name"), false); if (!nameElement.text().startsWith(QLatin1String("SW_room_"), Qt::CaseInsensitive)) continue; const int subId = getInteger(getChildElement(roomElem, QStringLiteral("SubId")), QStringLiteral("ID")); StructureElement se; se.name(nameElement.text().simplified().toStdString()); QString roomName = QString::fromStdString(se.name()); // displayed room names are too long roomName.replace(QStringLiteral("SW_room"), QStringLiteral("R")); INFO_LOG(m_logger) << "importRooms: " << roomName << ", parentIdx = " << parentIdx; se.displayName(roomName.toStdString()); se.mountingPointId(subId); se.structureElementTypeId(InfrastructureManagement::StructureElementType::Room); se.mountingPointTypeId(InfrastructureManagement::MountingPointType::Unknown); se.properties("{}"); QDomElement subRoomElem = roomElem.firstChildElement(QStringLiteral("Group")); if (!subRoomElem.isNull()) { tryGetRoomBoundingBox(subRoomElem, se); addElementToRequest(se, parentIdx); const int curIdx = m_request.elements().size() - 1; importExternalReferences(subRoomElem, curIdx); DEBUG_LOG(m_logger) << "Room=" << se.name() << " Id=" << se.id() << " mountingPointId=" << se.mountingPointId(); } else { addElementToRequest(se, parentIdx); } } } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::tryGetRoomBoundingBox(const QDomElement &subRoomElem, StructureElement &se) { const QDomElement min = getChildElement(subRoomElem, QStringLiteral("BBox_Min")); const QDomElement max = getChildElement(subRoomElem, QStringLiteral("BBox_Max")); if (min.isNull() || max.isNull()) return; const auto minPos(positionFromElement(min)); const auto maxPos(positionFromElement(min)); se.relPosition(Core::RelativePosition((minPos.offsetX() + maxPos.offsetX()) / 2, (minPos.offsetY() + maxPos.offsetY()) / 2, (minPos.offsetZ() + maxPos.offsetZ()) / 2)); } //------------------------------------------------------------------------------------------------------------- void ParseBuildingXml::addElementToRequest(const StructureElement &se, int parentIdx) { const size_t size = m_request.elements().size(); m_request.elements().resize(size + 1, se); m_request.childParentRelations().resize(size + 1, parentIdx); } //------------------------------------------------------------------------------------------------------------- InfrastructureManagement::MountingPointType ParseBuildingXml::mptFromSubId(int subId) { enum ExternalReference { NONE = 0, REF_MOD = 11000, ZEG = 12000, CAMERA_OUT = 13000, CAMERA_IN = 14000, IPS_OUT = 15000, IPS_IN = 16000, Unknown1 = 17000, ANNOUNCEMENT_Unit = 26000, EGCU = 27000, Unknown2 = 28000 }; if (subId > Unknown2) return MountingPointType::Unknown; if (subId > EGCU) return MountingPointType::EffectGenerationControlUnit; if (subId > ANNOUNCEMENT_Unit) return MountingPointType::AnnouncementUnit; if (subId > Unknown1) return MountingPointType::Unknown; if (subId > IPS_IN) return MountingPointType::IndoorIPS; if (subId > IPS_OUT) return MountingPointType::OutdoorIPS; if (subId > CAMERA_IN) return MountingPointType::IndoorCamera; if (subId > CAMERA_OUT) return MountingPointType::OutdoorCamera; if (subId > ZEG) return MountingPointType::BuildingControlUnit; if (subId > REF_MOD) return MountingPointType::BuildingSensorModule; return MountingPointType::Unknown; } //------------------------------------------------------------------------------------------------------------- StructureElement ParseBuildingXml::getStructureElement(const QDomElement &element) const { const int subId = getInteger(getChildElement(element, QStringLiteral("SubId")), QStringLiteral("ID")); StructureElement se; se.relPosition(positionFromElement(getChildElement(element, QStringLiteral("Coord")))); se.orientation(positionFromElement(getChildElement(element, QStringLiteral("Dir")))); // xyz=hpr? se.mountingPointTypeId(mptFromSubId(subId)); se.structureElementTypeId(InfrastructureManagement::StructureElementType::MountingPoint); se.name(element.firstChildElement(QStringLiteral("Name")).text().simplified().toStdString()); QString displayName = m_buildingName; displayName.append(QLatin1String(" - ")); displayName.append(QString::fromStdString(se.name())); se.displayName(displayName.toStdString()); se.mountingPointId(subId); se.properties("{}"); return se; } //------------------------------------------------------------------------------------------------------------- template QDomElement ParseBuildingXml::getChildElement(const T &parent, const QString &childTag, bool bThrow) const { const QDomElement ret = parent.firstChildElement(childTag); if (ret.isNull() && bThrow) throw XmlImportException(tr("Invalid XML Structure - no '%1' tag (line %2:%3)") .arg(childTag).arg(parent.lineNumber()).arg(parent.columnNumber())); return ret; } //------------------------------------------------------------------------------------------------------------- int ParseBuildingXml::getInteger(const QDomElement &element, const QString &attribute) const { bool bOk = true; const int ret = element.attribute(attribute).toInt(&bOk); if (!bOk) throw XmlImportException(tr("Can not find attribute %1 in xml element %2 (line %3:%4)") .arg(attribute, element.tagName()).arg(element.lineNumber()).arg(element.columnNumber())); return ret; } } // namespace InfrastructureManagement