12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310 |
- /****************************************************************************
- ** CopyRight(c) 2023, XXXX
- ** All rights reserved
- **
- ** 文件名称: calccrc.hpp
- ** 摘要: SCD CRC 计算算法
- **
- ** 当前版本: 1.0.0.0
- ** 作者:
- **
- ** 完成日期: 2023-3-18
- **
- ** 历史修改记录:
- ** 作者 描述 修改时间
- ****************************************************************************/
- #pragma once
- #include "pugixml.hpp"
- #include "sformat.h"
- #include <map>
- #include <string>
- #include <vector>
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <iomanip>
- #include <chrono>
- #include <ctime>
- using namespace std;
- using namespace pugi;
- class CCalCRC
- {
- public:
- enum eType {
- eGoose = 0,
- eSV
- };
- /**
- * @brief 计算IED CRC
- * @param pszSCDFile SCD文件路径
- * @return IEDCRC Map
- */
- static map<string, string> getIedCrc(const char* pszSCDFile)
- {
- map<string, string> mapCRC;
- xml_document m_scddoc;
- xml_parse_result parse_xml = m_scddoc.load_file(pszSCDFile, parse_full);
- if (parse_xml.status != status_ok)
- {
- //打开失败
- //cout << "打开SCD失败!" << endl;
- return mapCRC;
- }
- //SCD根节点
- xml_node root_scd = m_scddoc.document_element();
- vector<xml_node> vecIED = getChildElements(root_scd, "IED");
- for (xml_node node_ied : vecIED)
- {
- xml_document ccddoc;
- xml_node xml_pre_node = ccddoc.prepend_child(pugi::node_declaration);
- xml_pre_node.append_attribute("version") = "1.0";
- xml_pre_node.append_attribute("encoding") = "UTF-8";
- xml_node root_ccd = ccddoc.append_child("IED");
- //CCD中IED原始,设置name属性
- string iedName = node_ied.attribute("name").as_string();
- root_ccd.append_attribute("configVersion") = node_ied.attribute("configVersion").as_string();
- root_ccd.append_attribute("desc") = node_ied.attribute("desc").as_string();
- root_ccd.append_attribute("manufacturer") = node_ied.attribute("manufacturer").as_string();
- root_ccd.append_attribute("name") = node_ied.attribute("name").as_string();
- root_ccd.append_attribute("type") = node_ied.attribute("type").as_string();
-
- bool bIsEmpty = createPubAndSubNode(root_ccd, root_scd, node_ied);
- if (bIsEmpty)
- continue;
- //删除私有属性
- cutNodeDesc(root_ccd);
- //按格式保存临时文件
- string strTempFile = string(pszSCDFile) + ".ccdtmp.txt";
- ccddoc.save_file(strTempFile.data());
- string serial;
- //剔除冗余空字符
- ifstream in(strTempFile);
- string strline;
- while (getline(in, strline)) {
- trim(strline);
- strline = remove_spaces_except_in_quotes(strline);
- serial += strline;
- }
- in.close();
- remove(strTempFile.data());
- int crc = 0xffffffff;
- crc = crcbyTable(crc, serial);
- string crcValue = dec2hex(crc);
- for (size_t i = crcValue.size(); i < 8; i++)
- crcValue.insert(0, "0");
- //输出IED CRC
- //cout << iedName << " : " << crcValue << endl;
- mapCRC[iedName] = crcValue;
- }
- return mapCRC;
- }
- /**
- * @brief 计算单IED CRC
- * @param pszSCDFile SCD文件路径
- * @param pszIEDName IED名称
- * @return CRC值
- */
- static string getIedCrc(const char* pszSCDFile, const char* pszIEDName)
- {
- xml_document m_scddoc;
- xml_parse_result parse_xml = m_scddoc.load_file(pszSCDFile, parse_full);
- if (parse_xml.status != status_ok)
- {
- //打开失败
- //cout << "打开SCD失败!" << endl;
- return "";
- }
- //SCD根节点
- xml_node root_scd = m_scddoc.document_element();
- xpath_node_set set_IED = root_scd.select_nodes(SFormat("/SCL/IED[@name='{0}']", pszIEDName).data());
- //GOOSE或SV控制块存在时,则认为发布内容存在
- if (set_IED.empty())
- return "";
- xml_node node_ied = set_IED[0].node();
- xml_document ccddoc;
- xml_node xml_pre_node = ccddoc.prepend_child(pugi::node_declaration);
- xml_pre_node.append_attribute("version") = "1.0";
- xml_pre_node.append_attribute("encoding") = "UTF-8";
- xml_node root_ccd = ccddoc.append_child("IED");
- //CCD中IED原始,设置name属性
- root_ccd.append_attribute("configVersion") = node_ied.attribute("configVersion").as_string();
- root_ccd.append_attribute("desc") = node_ied.attribute("desc").as_string();
- root_ccd.append_attribute("manufacturer") = node_ied.attribute("manufacturer").as_string();
- root_ccd.append_attribute("name") = node_ied.attribute("name").as_string();
- root_ccd.append_attribute("type") = node_ied.attribute("type").as_string();
-
- bool bIsEmpty = createPubAndSubNode(root_ccd, root_scd, node_ied);
- if (bIsEmpty)
- return "";
- //删除私有属性
- cutNodeDesc(root_ccd);
- //按格式保存临时文件
- string strTempFile = string(pszSCDFile) + ".ccdtmp.txt";
- ccddoc.save_file(strTempFile.data());
- string serial;
- //剔除冗余空字符
- ifstream in(strTempFile);
- string strline;
- while (getline(in, strline)) {
- trim(strline);
- strline = remove_spaces_except_in_quotes(strline);
- serial += strline;
- }
- in.close();
- remove(strTempFile.data());
- int crc = 0xffffffff;
- crc = crcbyTable(crc, serial);
- string crcValue = dec2hex(crc);
- for (size_t i = crcValue.size(); i < 8; i++)
- crcValue.insert(0, "0");
- return crcValue;
- }
- /**
- * @brief 导出CCD
- * @param pszSCDFile SCD文件路径
- * @param pszIEDName IED名称
- * @param pszExportDir 导出CCD目录
- * @return CRC值
- */
- static void exportIedCCD(const char* pszSCDFile, const char* pszIEDName, const char* pszExportDir)
- {
- xml_document m_scddoc;
- xml_parse_result parse_xml = m_scddoc.load_file(pszSCDFile, parse_full);
- if (parse_xml.status != status_ok)
- {
- //打开失败
- //cout << "打开SCD失败!" << endl;
- return;
- }
- //SCD根节点
- xml_node root_scd = m_scddoc.document_element();
- xpath_node_set set_IED = root_scd.select_nodes(SFormat("/SCL/IED[@name='{0}']", pszIEDName).data());
- //GOOSE或SV控制块存在时,则认为发布内容存在
- if (set_IED.empty())
- return;
- xml_node node_ied = set_IED[0].node();
- xml_document ccddoc;
- xml_node xml_pre_node = ccddoc.prepend_child(pugi::node_declaration);
- xml_pre_node.append_attribute("version") = "1.0";
- xml_pre_node.append_attribute("encoding") = "UTF-8";
- xml_node root_ccd = ccddoc.append_child("IED");
- //CCD中IED原始,设置name属性
- string iedName = node_ied.attribute("name").as_string();
- root_ccd.append_attribute("configVersion") = node_ied.attribute("configVersion").as_string();
- root_ccd.append_attribute("desc") = node_ied.attribute("desc").as_string();
- root_ccd.append_attribute("manufacturer") = node_ied.attribute("manufacturer").as_string();
- root_ccd.append_attribute("name") = node_ied.attribute("name").as_string();
- root_ccd.append_attribute("type") = node_ied.attribute("type").as_string();
- bool bIsEmpty = createPubAndSubNode(root_ccd, root_scd, node_ied);
- if (bIsEmpty)
- return;
- xml_document ccddoctmp;
- xml_node xml_pre_nodetmp = ccddoctmp.prepend_child(pugi::node_declaration);
- xml_pre_nodetmp.append_attribute("version") = "1.0";
- xml_pre_nodetmp.append_attribute("encoding") = "UTF-8";
- xml_node root_ccdtmp = ccddoctmp.append_copy(root_ccd);
-
- //删除私有属性
- cutNodeDesc(root_ccdtmp);
- //按格式保存临时文件
- string strTempFile = string(pszSCDFile) + ".ccdtmp.txt";
- ccddoctmp.save_file(strTempFile.data());
- string serial;
- //剔除冗余空字符
- ifstream in(strTempFile);
- string strline;
- while (getline(in, strline)) {
- trim(strline);
- strline = remove_spaces_except_in_quotes(strline);
- serial += strline;
- }
- in.close();
- remove(strTempFile.data());
- int crc = 0xffffffff;
- crc = crcbyTable(crc, serial);
- string crcValue = dec2hex(crc);
- for (size_t i = crcValue.size(); i < 8; i++)
- crcValue.insert(0, "0");
- xml_node node_crc = root_ccd.append_child("CRC");
- node_crc.append_attribute("id") = crcValue.data();
- //获取当前时间
- std::time_t t = std::time(nullptr);
- char buffer[100];
- std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&t));
- string currenttime(buffer);
- node_crc.append_attribute("timestamp") = currenttime.data();
- //std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
- //std::time_t now_time = std::chrono::system_clock::to_time_t(now);
- //std::tm* now_tm = std::localtime(&now_time);
- //std::stringstream ss;
- //ss << std::put_time(now_tm, "%Y-%m-%d %H:%M:%S");
- //node_crc.append_attribute("timestamp") = ss.str().data();
- string strExportFile = pszExportDir;
- strExportFile = strExportFile + "/" + iedName + ".ccd";
- ccddoc.save_file(strExportFile.data());
- }
-
- /**
- * @brief 计算SCD CRC
- * @param mapCRC 各个IED的CRC值列表
- * @return CRC值
- */
- static string getScdCRC(map<string, string> mapCRC)
- {
- string SCDBuffer;
- for (auto it : mapCRC)
- SCDBuffer += it.second;
- int crc = 0xffffffff;
- crc = crcbyTable(crc, SCDBuffer);
- string crcValue = dec2hex(crc);
- for (size_t i = crcValue.size(); i < 8; i++)
- crcValue.insert(0, "0");
- return crcValue;
- }
- /**
- * @brief 计算字符串的CRC值
- * @param crc 初始值
- * @param data 字符串
- * @return CRC值
- */
- static unsigned int crcbyTable(unsigned int crc, string data) {
- unsigned int table[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
- size_t length = data.length();
- unsigned char ch;
- for (int i = 0; i < length; i++) {
- ch = data.at(i);
- crc = (crc >> 8) ^ table[(crc ^ ch) & 0xff];
- }
- crc = crc ^ 0xffffffff;
- return crc;
- }
-
- //将int转成16进制字符串
- static string dec2hex(int i)
- {
- stringstream ioss; //定义字符串流
- string s_temp; //存放转化后字符
- ioss << setiosflags(ios::uppercase) << hex << i; //以十六制(大写)形式输出
- ioss >> s_temp;
- return s_temp;
- }
- private:
- /**
- * @brief 创建 PubAndSubNode
- * @param root_ccd CCD根节点
- * @param root_scd SCD根节点
- * @param node_IED IED根节点
- * @return 是否存在内容
- */
- static bool createPubAndSubNode(xml_node root_ccd, xml_node root_scd, xml_node node_ied)
- {
- xml_node nodeGoosePub = root_ccd.append_child("GOOSEPUB");
- xml_node nodeGooseSub = root_ccd.append_child("GOOSESUB");
- xml_node nodeSvPub = root_ccd.append_child("SVPUB");
- xml_node nodeSvSub = root_ccd.append_child("SVSUB");
- bool emptyflag = createPublishNode(nodeGoosePub, nodeSvPub, root_scd, node_ied);
- emptyflag &= createSubscriptionNode(nodeGooseSub, nodeSvSub, root_scd, node_ied);
- //内容为空时删除
- if (nodeGoosePub.first_child().empty())
- root_ccd.remove_child(nodeGoosePub);
- if (nodeSvPub.first_child().empty())
- root_ccd.remove_child(nodeSvPub);
- if (nodeGooseSub.first_child().empty())
- root_ccd.remove_child(nodeGooseSub);
- if (nodeSvSub.first_child().empty())
- root_ccd.remove_child(nodeSvSub);
- return emptyflag;
- }
- /**
- * @brief 创建 GOOSEPUB和SVPUB
- * @param nodeGoosePub GOOSEPUB节点
- * @param nodeSvPub SVPUB节点
- * @param node_scd SCD根节点
- * @param node_ied IED根节点
- * @return 是否存在内容
- */
- static bool createPublishNode(xml_node nodeGoosePub, xml_node nodeSvPub, xml_node node_scd, xml_node node_ied)
- {
- bool emptyFlag = true;
- string iedName = node_ied.attribute("name").as_string();
- vector<xml_node> vecAcceptPoint = getChildElements(node_ied, "AccessPoint");
- //变量IED下访问的
- for (xml_node node_AcceptPoint : vecAcceptPoint)
- {
- xpath_node_set setControl_goose = node_AcceptPoint.select_nodes("./Server/LDevice/LN0/GSEControl");
- xpath_node_set setControl_sample = node_AcceptPoint.select_nodes("./Server/LDevice/LN0/SampledValueControl");
- //GOOSE或SV控制块存在时,则认为发布内容存在
- if (!setControl_goose.empty() || !setControl_sample.empty())
- emptyFlag = false;
- addControlForPub(nodeGoosePub, setControl_goose, eGoose, node_scd);
- addControlForPub(nodeSvPub, setControl_sample, eSV, node_scd);
- }
- return emptyFlag;
- }
- /**
- * @brief 创建 GOOSEPUB/SVPUB
- * @param nodePub_CCD GOOSEPUB或SVPUB节点
- * @param setControl GSE/SMV访问点
- * @param pubType GSE/SMV
- * @param node_scd SCD根节点
- * @return void
- */
- static void addControlForPub(xml_node nodePub_CCD, xpath_node_set setControl, eType pubType, xml_node node_scd)
- {
- string refnameAttr, instAttr, nameAttr, datSetAttr, iedName, apName;
- for (int jj = 0; jj < setControl.size(); jj++)
- {
- xml_node node_Control = setControl[jj].node();
- xml_node node_LN0 = node_Control.parent();
- xml_node node_LDvice = node_LN0.parent();
- xml_node node_Server = node_LDvice.parent();
- xml_node node_AccessPoint = node_Server.parent();
- xml_node node_IED = node_AccessPoint.parent();
- string nameAttr = node_Control.attribute("name").as_string();
- string datSetAttr = node_Control.attribute("datSet").as_string();
- string instAttr = node_LDvice.attribute("inst").as_string();
- string apName = node_AccessPoint.attribute("name").as_string();
- string iedName = node_IED.attribute("name").as_string();
- string strCBName;
- //计算控制块refernece
- if (pubType == eGoose)
- {
- strCBName = "GOCBref";
- refnameAttr = iedName + instAttr + "/LLN0$GO$" + nameAttr;
- }
- else if (pubType == eSV)
- {
- strCBName = "SMVCBref";
- refnameAttr = iedName + instAttr + "/LLN0$MS$" + nameAttr;
- }
- xml_node nodeCBref = nodePub_CCD.append_child(strCBName.data());
- nodeCBref.append_attribute("name") = refnameAttr.data();
- //添加GSEControl/SampledValueControl
- insertNodeSorted(nodeCBref, node_Control);
- //添加ConnectedAP
- addConnectedAPForPub(node_scd, nodeCBref, iedName, apName, nameAttr, instAttr, pubType);
- //添加数据集
- addFCDAForPub(node_scd, node_LN0, nodeCBref, datSetAttr, pubType);
- }
- }
- /**
- * @brief 创建 GOOSEPUB/SVPUB的ConnectedAP
- * @param node_scd scd根节点
- * @param nodeCBref GOCBref或SMVCBref
- * @param iedName apName nameAttrldinst 索引属性
- * @param pubType GOOSE/SV
- */
- static void addConnectedAPForPub(xml_node node_scd, xml_node nodeCBref, string iedName, string apName, string nameAttr, string ldinst, eType pubType)
- {
- string pathCAP;
- if (pubType == eGoose)
- {
- pathCAP = SFormat("/SCL/Communication/SubNetwork/ConnectedAP[@iedName='{0}' and @apName='{1}']/GSE[@cbName='{2}' and @ldInst='{3}']",
- iedName, apName, nameAttr, ldinst);
- }
- else if (pubType == eSV)
- {
- pathCAP = SFormat("/SCL/Communication/SubNetwork/ConnectedAP[@iedName='{0}' and @apName='{1}']/SMV[@cbName='{2}' and @ldInst='{3}']",
- iedName, apName, nameAttr, ldinst);
- }
- xpath_node_set setConnectedAP = node_scd.select_nodes(pathCAP.data());
- if (!setConnectedAP.empty())
- {
- //添加ConnectedAP
- xml_node node_ConnectedAP = setConnectedAP[0].parent();
- insertNodeSorted(nodeCBref, node_ConnectedAP);
- xml_node ConnectedAP = nodeCBref.child("ConnectedAP");
- ConnectedAP.remove_attribute("desc");
- //删除ConnectedAP中其他的控制块
- xpath_node_set GSE_SMVSet;
- if (pubType == eGoose)
- GSE_SMVSet = ConnectedAP.select_nodes(SFormat("GSE[@cbName!='{0}' or @ldInst!='{1}']", nameAttr, ldinst).data());
- else if (pubType == eSV)
- GSE_SMVSet = ConnectedAP.select_nodes(SFormat("SMV[@cbName!='{0}' or @ldInst!='{1}']", nameAttr, ldinst).data());
- for (int i = 0; i < GSE_SMVSet.size(); i++)
- removeChildNode(GSE_SMVSet[i].node());
- xpath_node_set AddressSet = ConnectedAP.select_nodes("./Address");
- for (int i = 0; i < AddressSet.size(); i++)
- removeChildNode(AddressSet[i].node());
- }
- }
- /**
- * @brief GOOSEPUB/SVPUB的dataset和FCDA
- * @param node_scd scd根节点
- * @param node_LN0 数据集归属LN0
- * @param nodeCBref GOCBref或SMVCBref
- * @param datSetAttr 数据集名称
- * @param pubType GOOSE/SV
- */
- static void addFCDAForPub(xml_node node_scd, xml_node node_LN0, xml_node nodeCBref, string datSetAttr, eType pubType)
- {
- string pathDataSet = SFormat("./DataSet[@name='{0}']", datSetAttr);
- xpath_node_set setDataSet = node_LN0.select_nodes(pathDataSet.data());
- if (setDataSet.empty())
- return;
- xml_node nodeDataTypeTemplate = node_scd.child("DataTypeTemplates");
- xml_node node_LDvice = node_LN0.parent();
- xml_node node_DataSet = setDataSet[0].node();
- vector<xml_node> vec_FCDA = getChildElements(node_DataSet, "FCDA");
- xml_node nodeDataSet = nodeCBref.append_child("DataSet");
- insertNodeAttr(node_DataSet, nodeDataSet);
- string prefix, lnInst, lnClass, doname, daName;
- for (xml_node node_FCDA : vec_FCDA)
- {
- prefix = node_FCDA.attribute("prefix").as_string();
- lnInst = node_FCDA.attribute("lnInst").as_string();
- lnClass = node_FCDA.attribute("lnClass").as_string();
- doname = node_FCDA.attribute("doName").as_string();
- daName = node_FCDA.attribute("daName").as_string();
- xml_node nodeFCDA = nodeDataSet.append_child("FCDA");
- vector<string> donamelist = stringSplit(doname, '.');
- if (donamelist.size() == 0)
- continue;
- //FCDA属性
- map<string, string> mapAttrs = getNodeAttributes(node_FCDA);
- if (daName != "")
- mapAttrs["bType"] = calc_bType(daName, doname, prefix, lnInst, lnClass, node_LDvice, nodeDataTypeTemplate);
- string pathDOI = SFormat("./LN0[not(@prefix) or @prefix='{0}'][@inst='{1}'][@lnClass='{2}']/DOI[@name='{3}']|./LN[not(@prefix) or @prefix='{0}'][@inst='{1}'][@lnClass='{2}']/DOI[@name='{3}']",
- prefix, lnInst, lnClass, donamelist.at(0));
- if (!prefix.empty())
- replace_all(pathDOI, "not(@prefix) or ", "");
- if ("" == lnInst)
- replace_all(pathDOI, "[@lnInst='']", "");
- if (daName.empty()) //正常SV
- {
- xpath_node_set set_DOI = node_LDvice.select_nodes(pathDOI.data());
- if (set_DOI.size() > 0) {
- mapAttrs["desc"] = set_DOI[0].node().attribute("desc").as_string();
- insertNodeSorted(nodeFCDA, set_DOI[0].node());
- }
- }
- else//正常GOOSE
- {
- xpath_node_set set_DOI = node_LDvice.select_nodes(pathDOI.data());
- if (set_DOI.size() > 0) {
- xml_node node_DOI = set_DOI[0].node();
- mapAttrs["desc"] = node_DOI.attribute("desc").as_string();
- //考虑doname中有.的情况
- string pathDAI = string(".");
- for (int i = 1; i < donamelist.size(); i++)
- {
- string xpath = SFormat("/SDI[@name='{0}']", donamelist.at(i));
- pathDAI += xpath;
- }
- vector<string> danamelist = stringSplit(daName, '.');
- for (int i = 0; i < danamelist.size(); i++)
- {
- if (i == danamelist.size() - 1)
- pathDAI += SFormat("/DAI[@name='{0}']", danamelist.at(i));
- else
- pathDAI += SFormat("/SDI[@name='{0}']", danamelist.at(i));
- }
- xpath_node_set set_DAI = node_DOI.select_nodes(pathDAI.data());
- if (set_DAI.size() > 0)
- {
- xml_node node_DAI = set_DAI[0].node();
- string daidesc = node_DAI.attribute("desc").as_string();
- if (!daidesc.empty())
- mapAttrs["desc"] = daidesc;
- insertNodeSorted(nodeFCDA, node_DAI);
- }
- }
- }
- for (auto& it : mapAttrs)
- {
- if (it.first.data() == "dU" || it.first.data() == "desc")
- continue;
- nodeFCDA.append_attribute(it.first.data()) = it.second.data();
- }
- }
- }
- /**
- * @brief 创建 GOOSESUB和SVSUB
- * @param nodeGooseSub GOOSESUB节点
- * @param nodeSvSub SVSUB节点
- * @param node_scd SCD根节点
- * @param node_ied IED根节点
- * @return 是否存在内容
- */
- static bool createSubscriptionNode(xml_node nodeGooseSub, xml_node nodeSvSub, xml_node node_scd, xml_node node_ied)
- {
- xml_node nodeDataTypeTemplate = node_scd.child("DataTypeTemplates");
- //遍历虚回路
- string path_ExtRef = "./AccessPoint/Server/LDevice/*[self::LN0 or self::LN]/Inputs/ExtRef[@intAddr!='']";
- xpath_node_set set_ExtRef = node_ied.select_nodes(path_ExtRef.data());
- if (set_ExtRef.empty())
- return true;
- multimap<string, xml_node> mapInputs;
- //记录已添加控制块标识
- vector<string> GOCBrefName_GOOSE, GOCBrefName_SV;
- string refnameAttr;
- for (int d = 0; d < set_ExtRef.size(); d++)
- {
- xml_node node_ExtRef = set_ExtRef[d].node();
- string key = string(node_ExtRef.attribute("prefix").as_string()) +
- node_ExtRef.attribute("ldInst").as_string() +
- node_ExtRef.attribute("iedName").as_string() +
- node_ExtRef.attribute("lnClass").as_string() +
- node_ExtRef.attribute("lnInst").as_string() +
- node_ExtRef.attribute("doName").as_string() +
- node_ExtRef.attribute("daName").as_string();
- mapInputs.insert(make_pair(key, node_ExtRef));
- }
- //遍历关联记录
- for (int d = 0; d < set_ExtRef.size(); d++)
- {
- xml_node node_ExtRef = set_ExtRef[d].node();
- string iedNameAttr = node_ExtRef.attribute("iedName").as_string();
- string ldInstAttr = node_ExtRef.attribute("ldInst").as_string();
- string prefixAttr = node_ExtRef.attribute("prefix").as_string();
- string lnInstAttr = node_ExtRef.attribute("lnInst").as_string();
- string lnClassAttr = node_ExtRef.attribute("lnClass").as_string();
- string doNameAttr = node_ExtRef.attribute("doName").as_string();
- string daNameAttr = node_ExtRef.attribute("daName").as_string();
- string key = iedNameAttr + ldInstAttr;
- //查找关联的IED
- string path_PubLDevice = SFormat("/SCL/IED[@name='{0}']/AccessPoint/Server/LDevice[@inst='{1}']", iedNameAttr, ldInstAttr);
- xpath_node_set set_PubLDevice = node_scd.select_nodes(path_PubLDevice.data());
- if (set_PubLDevice.empty())
- continue;
- //查找该关联IED下的FCDA信息
- xml_node node_PubLDevice = set_PubLDevice[0].node();
- string path_dataset;
- path_dataset = SFormat("../LDevice/LN0/DataSet/FCDA[@ldInst='{0}'][@prefix='{1}'][@lnClass='{2}'][@lnInst='{3}'][@doName='{4}'][@daName='{5}']",
- ldInstAttr, prefixAttr, lnClassAttr, lnInstAttr, doNameAttr, daNameAttr);
- if ("" == prefixAttr)
- replace_all(path_dataset, "[@prefix='']", "[not(@prefix) or @prefix='']");
- if ("" == lnInstAttr)
- replace_all(path_dataset, "[@lnInst='']", "[not(@lnInst) or @lnInst='']");
- if ("" == daNameAttr)
- replace_all(path_dataset, "[@daName='']", "");
- xpath_node_set set_Pubfcda = node_PubLDevice.select_nodes(path_dataset.data());
- //添加control
- addControlForSub(set_Pubfcda, nodeGooseSub, node_ied, eGoose, node_PubLDevice, GOCBrefName_GOOSE, mapInputs);
- addControlForSub(set_Pubfcda, nodeSvSub, node_ied, eSV, node_PubLDevice, GOCBrefName_SV, mapInputs);
- }
- return false;
- }
- /**
- * @brief 创建 GOOSESUB/SVSUB
- * @param set_Pubfcda 发布端数据集成员列表
- * @param nodeSub GOOSESUB或SVSUB
- * @param node_SubIED 订阅IED,即需要导出的IED
- * @param pubType GOOSE/SV
- * @param node_PubLDevice 发布端逻辑设备
- * @param GOCBrefName 已添加控制块标识
- * @param mapInputs ExtRef记录Map
- */
- static void addControlForSub(xpath_node_set set_Pubfcda, xml_node nodeSub, xml_node node_SubIED,
- eType pubType, xml_node node_PubLDevice, vector<string>& GOCBrefName, const multimap<string, xml_node>& mapInputs)
- {
- if (set_Pubfcda.empty())
- return;
- //根据该记录的数据块的名称,查找对应的控制块
- vector<xml_node> set_PubControlALL;
- vector<string> datasetNameAttrList;
- vector<string> datasetList;
- string strCtrlName = pubType == eGoose ? "GSEControl" : "SampledValueControl";
- //解析控制块信息
- for (int d = 0; d < set_Pubfcda.size(); d++)
- {
- xml_node node_Pubfcda = set_Pubfcda[d].node();
- string datasetNameAttr = node_Pubfcda.parent().attribute("name").as_string();
- if (count(datasetList.begin(), datasetList.end(), datasetNameAttr))
- continue;
- datasetList.push_back(datasetNameAttr);
- string pathControl = SFormat("./LN0/{0}[@datSet='{1}']", strCtrlName, datasetNameAttr);
- xpath_node_set set_PubControl = node_PubLDevice.select_nodes(pathControl.data());
- if (set_PubControl.empty())
- {
- pathControl = SFormat("../LDevice/{0}", pathControl);
- set_PubControl = node_PubLDevice.select_nodes(pathControl.data());
- }
- if (set_PubControl.empty())
- continue;
- xml_node node_PubControl = set_PubControl[0].node();
- if (!count(set_PubControlALL.begin(), set_PubControlALL.end(), node_PubControl))
- {
- set_PubControlALL.push_back(node_PubControl);
- datasetNameAttrList.push_back(datasetNameAttr);
- }
- }
- if (set_PubControlALL.empty())
- return;
- for (int i = 0; i < set_PubControlALL.size(); i++)
- {
- xml_node node_PubControl = set_PubControlALL.at(i);
- string datasetNameAttr = datasetNameAttrList.at(i);
- xml_node node_LN0 = node_PubControl.parent();
- node_PubLDevice = node_LN0.parent();
- xml_node node_Server = node_PubLDevice.parent();
- xml_node node_AccessPoint = node_Server.parent();
- xml_node node_IED = node_AccessPoint.parent();
- xml_node nodeRoot = node_IED.parent();
- string nameAttr = node_PubControl.attribute("name").as_string();
- string ldInstAttr = node_PubLDevice.attribute("inst").as_string();
- string iedNameAttr = node_IED.attribute("name").as_string();
- string refnameAttr = "";
- if (pubType == eSV)
- refnameAttr = iedNameAttr + ldInstAttr + "/LLN0$MS$" + nameAttr;
- else
- refnameAttr = iedNameAttr + ldInstAttr + "/LLN0$GO$" + nameAttr;
- //添加过则不再添加
- if (count(GOCBrefName.begin(), GOCBrefName.end(), refnameAttr))
- return;
- GOCBrefName.push_back(refnameAttr);
- //添加节点
- string strBrefName = pubType == eGoose ? "GOCBref" : "SMVCBref";
- xml_node nodeCBref = nodeSub.append_child(strBrefName.data());
- nodeCBref.append_attribute("name") = refnameAttr.data();
- insertNodeSorted(nodeCBref, node_PubControl);
- //去除Private属性
- xml_node GSEControl = nodeCBref.child(strCtrlName.data());
- xml_node privatenode = nodeCBref.child("Private");
- if (!privatenode.empty())
- GSEControl.remove_child(privatenode);
- //添加ConnectedAP
- addConnectedAPForSub(nodeRoot, nodeCBref, iedNameAttr, nameAttr, ldInstAttr, pubType);
- //添加DataSet和对应的每一条FCDA记录
- addFCDAForSub(nodeRoot, node_PubLDevice, node_SubIED, nodeCBref, datasetNameAttr, mapInputs, pubType);
- }
- }
- /**
- * @brief 创建 GOOSESUB/SVSUB的ConnectedAP
- * @param node_scd scd根节点
- * @param nodeCBref GOCBref或SMVCBref
- * @param iedName apName nameAttrldinst 索引属性
- * @param pubType GOOSE/SV
- */
- static void addConnectedAPForSub(xml_node node_scd, xml_node nodeCBref, string iedName,
- string cbName, string ldInstAttr, eType pubType)
- {
- //与发布相比,仅保留GSE/SMV子元素
- string strCtrlName = pubType == eGoose ? "GSE" : "SMV";
- string path_PubGS = SFormat("/SCL/Communication/SubNetwork/ConnectedAP[@iedName='{0}']/{1}[@cbName='{2}' and @ldInst='{3}']",
- iedName, strCtrlName, cbName, ldInstAttr);
- xpath_node_set set_PubGS = node_scd.select_nodes(path_PubGS.data());
- if (!set_PubGS.empty())
- {
- xml_node PubConnectedAP = nodeCBref.append_child("ConnectedAP");
- xml_node node_PubConnectedCtl = set_PubGS[0].node();
- insertNodeAttr(set_PubGS[0].node().parent(), PubConnectedAP);
- insertNodeSorted(PubConnectedAP, node_PubConnectedCtl);
- }
- }
- /**
- * @brief GOOSESUB/SVSUB的FCDA
- * @param node_scd scd根节点
- * @param node_PubLDevice 发布的LDevice节点
- * @param node_SubIED 订阅的IED节点
- * @param nodeCBref GOCBref或SMVCBref
- * @param datasetNameAttr 数据集名称
- * @param mapInputs ExtRef记录Map
- * @param pubType GOOSE/SV
- */
- static void addFCDAForSub(xml_node node_scd, xml_node node_PubLDevice, xml_node node_SubIED, xml_node nodeCBref, string datasetNameAttr,
- const multimap<string, xml_node>& hashInputs, eType pubType)
- {
- //添加DataSet
- string path_fcda = SFormat("./LN0/DataSet[@name='{0}']", datasetNameAttr);
- xpath_node_set node_PubDataSets = node_PubLDevice.select_nodes(path_fcda.data());
- if (node_PubDataSets.empty())
- return;
- xml_node node_PubDataSet = node_PubDataSets[0].node();
- xml_node nodeDataSet = nodeCBref.append_child("DataSet");
- insertNodeAttr(node_PubDataSet, nodeDataSet);
- //记录IED信息
- xml_node nodeDataTypeTemplate = node_scd.child("DataTypeTemplates");
- xml_node node_Server = node_PubLDevice.parent();
- xml_node node_AccessPoint = node_Server.parent();
- xml_node node_IED = node_AccessPoint.parent();
- string iedNameAttr = node_IED.attribute("name").as_string();
- //添加每一条FCDA
- vector<xml_node> vec_PubFCDA = getChildElements(node_PubDataSet, "FCDA");
- for (xml_node node_PubFCDA : vec_PubFCDA)
- {
- string prefix = node_PubFCDA.attribute("prefix").as_string();
- string ldInst = node_PubFCDA.attribute("ldInst").as_string();
- string lnInst = node_PubFCDA.attribute("lnInst").as_string();
- string lnClass = node_PubFCDA.attribute("lnClass").as_string();
- string doname = node_PubFCDA.attribute("doName").as_string();
- string daName = node_PubFCDA.attribute("daName").as_string();
- xml_node nodeFCDA = nodeDataSet.append_child("FCDA");
- //计算FCDA的bType
- string stype;
- map<string, string> mapAttrs = getNodeAttributes(node_PubFCDA);
- if (!daName.empty())
- mapAttrs["bType"] = calc_bType(daName, doname, prefix, lnInst, lnClass, node_PubLDevice, nodeDataTypeTemplate);
- vector<string> donamelist = stringSplit(doname, '.');
- if (!donamelist.empty())
- {
- string pathDOI = SFormat("./LN0[not(@prefix) or @prefix='{0}'][@inst='{1}'][@lnClass='{2}']/DOI[@name='{3}']|./LN[not(@prefix) or @prefix='{0}'][@inst='{1}'][@lnClass='{2}']/DOI[@name='{3}']",
- prefix, lnInst, lnClass, donamelist.at(0));
- if (!prefix.empty())
- replace_all(pathDOI, "not(@prefix) or ", "");
- if ("" == lnInst)
- replace_all(pathDOI, "[@lnInst='']", "");
- xpath_node_set set_DOI = node_PubLDevice.select_nodes(pathDOI.data());
- if (set_DOI.size() > 0) {
- xml_node node_DOI = set_DOI[0].node();
- mapAttrs["desc"] = node_DOI.attribute("desc").as_string();
- string pathDAI = string(".");
- for (int i = 1; i < donamelist.size(); i++)
- {
- string xpath = SFormat("/SDI[@name='{0}']", donamelist.at(i));
- pathDAI += xpath;
- }
- vector<string> danamelist = stringSplit(daName, '.');
- for (int i = 0; i < danamelist.size(); i++)
- {
- if (i == danamelist.size() - 1)
- pathDAI += SFormat("/DAI[@name='{0}']", danamelist.at(i));
- else
- pathDAI += SFormat("/SDI[@name='{0}']", danamelist.at(i));
- }
- xpath_node_set set_DAI = node_DOI.select_nodes(pathDAI.data());
- if (set_DAI.size() > 0)
- {
- xml_node node_DAI = set_DAI[0].node();
- string daidesc = node_DAI.attribute("desc").as_string();
- if (!daidesc.empty())
- mapAttrs["desc"] = daidesc;
- }
- }
- }
-
- for (auto& it : mapAttrs)
- {
- if (it.first.data() == "dU" || it.first.data() == "desc")
- continue;
- nodeFCDA.append_attribute(it.first.data()) = it.second.data();
- }
- //每一条FCDA记录在订阅装置中
- string mapKey = prefix + ldInst + iedNameAttr + lnClass + lnInst + doname + daName;
- auto node_hash_ExtRefSet = hashInputs.equal_range(mapKey);
- for (auto k = node_hash_ExtRefSet.first; k != node_hash_ExtRefSet.second; k++)
- {
- xml_node node_hash_ExtRef = k->second;
- string intAddrAttr = node_hash_ExtRef.attribute("intAddr").as_string();
- vector<string> lstTemp = stringSplit(intAddrAttr, '.');
- if (lstTemp.size() < 2)
- {
- if (!nodeFCDA.child("intAddr").empty())
- {
- xml_node node_intAddr = nodeFCDA.append_child("intAddr");
- node_intAddr.append_attribute("desc") = "";
- node_intAddr.append_attribute("name") = "";
- }
- continue;
- }
- string strLD_LN = lstTemp.at(0);
- if (strLD_LN.find(':') != string::npos)
- {
- strLD_LN = stringSplit(strLD_LN, ':').at(1);
- }
- string LDevice_name = stringSplit(strLD_LN, '/').at(0);
- string LN_prefix_lnClass_inst = stringSplit(strLD_LN, '/').at(1);;
- string DOI_name = lstTemp.at(1);
- vector<string> daList;
- for (int j = 2; j < lstTemp.size(); j++)
- daList.push_back(lstTemp.at(j));
- xml_node node_intAddr = nodeFCDA.append_child("intAddr");
- string pathLDevice = SFormat("./AccessPoint/Server/LDevice[@inst='{0}']", LDevice_name);
- xpath_node_set set_LDevice = node_SubIED.select_nodes(pathLDevice.data());
- if (set_LDevice.empty())
- continue;
- vector<xml_node> vec_LN = getChildElements(set_LDevice[0].node(), "LN");
- xml_node vec_LN0 = set_LDevice[0].node().child("LN0");
- vec_LN.push_back(vec_LN0);
- //ln0合并
- for (xml_node node_LN : vec_LN)
- {
- string LN_pll = string(node_LN.attribute("prefix").as_string()) +
- node_LN.attribute("lnClass").as_string() +
- node_LN.attribute("inst").as_string();
- if (LN_pll == LN_prefix_lnClass_inst)
- {
- string pathDOI = SFormat("./DOI[@name='{0}']", DOI_name);
- xpath_node_set set_DOI = node_LN.select_nodes(pathDOI.data());
- if (set_DOI.size() > 0)
- {
- xml_node node_DOI = set_DOI[0].node();
- if (daList.empty()) //SV
- {
- node_intAddr.append_attribute("desc") = node_DOI.attribute("desc").as_string();
- node_intAddr.append_attribute("name") = intAddrAttr.data();
- insertNodeSorted(node_intAddr, set_DOI[0].node());
- }
- else //GOOSE
- {
- string pathDAI = string(".");
- for (int i = 0; i < daList.size(); i++)
- {
- string xpath = SFormat("/SDI[@name='{0}']", daList.at(i));
- if (i == daList.size() - 1)
- xpath = SFormat("/DAI[@name='{0}']", daList.at(i));
- pathDAI += xpath;
- }
- xpath_node_set set_DAI = node_DOI.select_nodes(pathDAI.data());
- if (set_DAI.size() > 0)
- {
- xml_node node_DAI = set_DAI[0].node();
- string strDaiDesc = node_DAI.attribute("desc").as_string();
- if(!strDaiDesc.empty())
- node_intAddr.append_attribute("desc") = strDaiDesc.data();
- else
- node_intAddr.append_attribute("desc") = node_DOI.attribute("desc").as_string();
- node_intAddr.append_attribute("name") = intAddrAttr.data();
- insertNodeSorted(node_intAddr, node_DAI);
- }
- else
- {
- node_intAddr.append_attribute("desc") = node_DOI.attribute("desc").as_string();
- node_intAddr.append_attribute("name") = intAddrAttr.data();
- }
- }
- }
- }
- }
- }
- if (hashInputs.count(mapKey) == 0)
- {
- xml_node node_intAddr = nodeFCDA.append_child("intAddr");
- node_intAddr.append_attribute("desc") = "";
- node_intAddr.append_attribute("name") = "NULL";
- continue;
- }
- }
- }
- //计算FCDA节点的 bType 属性
- static string calc_bType(string daName, string doname, string prefix, string lnInst, string lnClass,
- xml_node nodeLDevice, xml_node nodeDataTypeTemplate)
- {
- string bType = "BOOLEAN";
- string typeAttr = "";
- /*if (daName == "q") {
- bType = "Quality";
- }
- else if (daName == "t") {
- bType = "Timestamp";
- }
- else if (endWith(daName, ".f")) {
- bType = "FLOAT32";
- }
- else */ {
- if (!doname.empty()) {
- string lnType = "";
- string pathLN;
- pathLN = SFormat("./LN0[not(@prefix) or @prefix='{0}'][@inst='{1}'][@lnClass='{2}']|./LN[not(@prefix) or @prefix='{0}'][@inst='{1}'][@lnClass='{2}']",
- prefix, lnInst, lnClass);
- if (!prefix.empty())
- replace_all(pathLN, "not(@prefix) or ", "");
- if ("" == lnInst)
- replace_all(pathLN, "[@lnInst='']", "");
- xpath_node_set set_LN = nodeLDevice.select_nodes(pathLN.data());
- if (set_LN.size() > 0) {
- xml_node nodeLN = set_LN[0].node();
- lnType = nodeLN.attribute("lnType").as_string();
- if (doname.find('.') == string::npos) {
- string pathDTTDO = SFormat("./LNodeType[@id='{0}']/DO[@name='{1}']", lnType, doname);
- xpath_node_set setDTTDO = nodeDataTypeTemplate.select_nodes(pathDTTDO.data());
- if (setDTTDO.size() > 0) {
- typeAttr = setDTTDO[0].node().attribute("type").as_string();
- }
- }
- else {
- vector<string> DOList = stringSplit(doname, '.');
- string pathDTTDO = SFormat("./LNodeType[@id='{0}']/DO[@name='{1}']", lnType, DOList.at(0));
- xpath_node_set setDTTDO = nodeDataTypeTemplate.select_nodes(pathDTTDO.data());
- if (setDTTDO.size() > 0) {
- typeAttr = setDTTDO[0].node().attribute("type").as_string();
- for (int kk = 1; kk < DOList.size(); kk++) {
- string pathDTTSDO = SFormat("./DOType[@id='{0}']/SDO[@name='{1}']", typeAttr, DOList.at(kk));
- xpath_node_set setDTTSDO = nodeDataTypeTemplate.select_nodes(pathDTTSDO.data());
- if (setDTTSDO.empty()) {
- break;
- }
- typeAttr = setDTTSDO[0].node().attribute("type").as_string();
- }
- }
- }
- if (daName.find('.') == string::npos) {
- string pathDTTDA = SFormat("./DOType[@id='{0}']/DA[@name='{1}']", typeAttr, daName);
- xpath_node_set setDTTDA = nodeDataTypeTemplate.select_nodes(pathDTTDA.data());
- if (setDTTDA.size() > 0) {
- bType = setDTTDA[0].node().attribute("bType").as_string();
- }
- }
- else {
- vector<string> DAList = stringSplit(daName, '.');
- string pathDTTDA = SFormat("./DOType[@id='{0}']/DA[@name='{1}']", typeAttr, DAList.at(0));
- xpath_node_set setDTTDA = nodeDataTypeTemplate.select_nodes(pathDTTDA.data());
- if (setDTTDA.size() > 0) {
- typeAttr = setDTTDA[0].node().attribute("type").as_string();
- for (int kk = 1; kk < DAList.size(); kk++) {
- string pathDTTBDA = SFormat("./DAType[@id='{0}']/BDA[@name='{1}']", typeAttr, DAList.at(kk));
- xpath_node_set setDTTBDA = nodeDataTypeTemplate.select_nodes(pathDTTBDA.data());
- if (setDTTBDA.empty()) {
- break;
- }
- if (kk == DAList.size() - 1) {
- bType = setDTTBDA[0].node().attribute("bType").as_string();
- }
- else {
- typeAttr = setDTTBDA[0].node().attribute("type").as_string();
- }
- }
- }
- }
- }
- }
- }
- return bType;
- }
- static void cutNodeDesc(xml_node node_ied)
- {
- if (node_ied.empty())
- return;
-
- string strIedName = node_ied.attribute("name").as_string();
- node_ied.remove_attributes();
- node_ied.append_attribute("name") = strIedName.data();
- xpath_node_set pubfcdanodeset = node_ied.select_nodes("./GOOSEPUB/GOCBref/DataSet/FCDA|./SVPUB/SMVCBref/DataSet/FCDA");
- xpath_node_set subfcdanodeset = node_ied.select_nodes("./GOOSESUB/GOCBref/DataSet/FCDA|./SVSUB/SMVCBref/DataSet/FCDA");
- for (int i = 0; i < pubfcdanodeset.size(); i++)
- pubfcdanodeset[i].node().remove_attribute("desc");
- for (int i = 0; i < subfcdanodeset.size(); i++)
- {
- xml_node node_fcda = subfcdanodeset[i].node();
- string strBtype = node_fcda.attribute("bType").as_string();
- subfcdanodeset[i].node().remove_attributes();
- if (!strBtype.empty())
- node_fcda.append_attribute("bType") = strBtype.data();
- xpath_node_set intaddrset = node_fcda.select_nodes("./intAddr");
- for (int j = 0; j < intaddrset.size(); j++)
- intaddrset[j].node().remove_attribute("desc");
- }
- }
- ///后续函数为部分基础处理函数,可忽略
- private:
- //按顺序插入节点
- static void insertNodeSorted(xml_node parent, xml_node current)
- {
- if (parent.empty() || current.empty()) {
- return;
- }
- if (node_element != current.type()) {
- return;
- }
- //跳过dU
- string nameAttr = current.attribute("name").as_string();
- if (nameAttr == "dU") {
- return;
- }
- xml_node nodeNew = parent.append_child(current.name());
- insertNodeAttr(current, nodeNew);
- string textCurr = current.text().as_string();
- if (!textCurr.empty()) {
- nodeNew.text().set(textCurr.data());
- }
- xml_node nodeChild = current.first_child();
- xml_node nodeChildL = current.last_child();
- while (!nodeChild.empty()) {
- if (nodeChild.type() == pugi::node_element) {
- insertNodeSorted(nodeNew, nodeChild);
- }
- if (nodeChild == nodeChildL) {
- break;
- }
- else {
- nodeChild = nodeChild.next_sibling();
- }
- }
- }
- //插入节点属性
- static void insertNodeAttr(xml_node current, xml_node nodeNew)
- {
- map<string, string> mapAttrs = getNodeAttributes(current);
- //map 会根据key值自动排序
- for (auto& attr : mapAttrs)
- {
- if (attr.first == "desc" || attr.first == "dU") {
- continue;
- }
- nodeNew.append_attribute(attr.first.data()) = attr.second.data();
- }
- }
- //获取子元素列表
- static vector<xml_node> getChildElements(xml_node node, string childName)
- {
- int i = 0;
- vector<xml_node> vector;
- for (pugi::xml_node_iterator it2 = node.children().begin();
- it2 != node.children().end(); it2++)
- {
- xml_node n = *it2;
- if (n.type() != pugi::node_element)
- continue;
- if (n.name() == childName)
- {
- vector.push_back(n);
- }
- i++;
- }
- return vector;
- }
- static bool removeChildNode(xml_node node)
- {
- xml_node pa_node = node.parent();
- if (pa_node.empty())
- return false;
- return pa_node.remove_child(node);
- }
- //获取所有属性
- static map<string, string> getNodeAttributes(xml_node node)
- {
- map<string, string> attrMap;
- for (xml_attribute_iterator it1 = node.attributes().begin();
- it1 != node.attributes().end(); ++it1)
- {
- xml_attribute attr = *it1;
- attrMap[attr.name()] = attr.value();
- }
- return attrMap;
- }
- static vector<string> stringSplit(string str, char split)
- {
- vector<string> res;
- istringstream iss(str); // 输入流
- string token; // 接收缓冲区
- while (getline(iss, token, split)) // 以split为分隔符
- res.push_back(token);
- return res;
- }
- static string& replace_all(string& src, const string& old_value, const string& new_value) {
- // 每次重新定位起始位置,防止上轮替换后的字符串形成新的old_value
- for (string::size_type pos(0); pos != string::npos; pos += new_value.length()) {
- if ((pos = src.find(old_value, pos)) != string::npos) {
- src.replace(pos, old_value.length(), new_value);
- }
- else break;
- }
- return src;
- }
- static bool endWith(const string& str, const string& tail) {
- return str.compare(str.size() - tail.size(), tail.size(), tail) == 0;
- }
- static bool startWith(const string& str, const string& head) {
- return str.compare(0, head.size(), head) == 0;
- }
- static string trim(string& text) {
- if (!text.empty())
- {
- text.erase(0, text.find_first_not_of(" \n\r\t"));
- text.erase(text.find_last_not_of(" \n\r\t") + 1);
- }
- return text;
- }
- static std::string remove_spaces_except_in_quotes(const std::string& input)
- {
- std::string output;
- bool quote_flag = false; // 是否在引号内的标志
- bool attr_flag = false; // 是否在<>内的标志
- for (char c : input) // 遍历每个字符
- {
- if (c == '"') // 如果是引号
- {
- quote_flag = !quote_flag; // 切换引号标志
- }
- if (c == '<')
- {
- attr_flag = true;
- }
- if (c == '>')
- {
- attr_flag = false; // 切换引号标志
- }
- if (c != ' ' || quote_flag || !attr_flag) // 如果不是空格或者在引号内
- {
- output += c; // 保留字符
- }
- }
- return output;
- }
- };
|