kanzi工程辅助解析

背景:实际开发过程中,使用kanzi studio工程,遇到一个很大的问题,就是在多工程,多预设件,复杂绑定算式情况下,很难梳理接口绑定情况,而且kanzi自带的查找很不好用。尤其是拿到一个新工程,光理解工程逻辑就需要花很大精力。
为此,写一个脚本工具,直接解析.kzproj文件,获取有效信息,帮助快速上手新项目。

如果关心kanzi实际运行时节点情况,请参考帖子kanzi运行时节点状态展示

1. 需求分析(kanzi 3.6.10)

kanzi studio工程文件文件,后缀名kzproj,本质是一个巨大的xml文件。
在这里插入图片描述
经过仔细分析,我们提取重要的字段

    1. 工程引用,一个主工程一般会引用多个子工程,ProjectReferenceItem,如果没有子工程,没有字段ProjectReferenceItem
    1. 场景节点,主工程的场景节点是这样的Screens-Screen-RootPage,在ScreenLibrary这个类型下,通过children|ProjectItem|SerializedName能够提取树状结构
    1. 预设件,除了普通节点,就是预设件几点,一般通过占位符引用子工程预设件。类型PrefabLibrary,同2取树状结构
    1. 绑定表达式,MultiExpressionPropertyBinding字段含有表达式内容
    1. 导出文件,将节点信息,预设件路径,绑定表达式导出,方便搜索接口

2. 脚本流程

2.1 读取主工程.kzproj
2.2 通过tinyxml2转为xml文档
2.3 查找ProjectReferenceItem,找到后递归读取i:type=d9p1:string,获取子工程列表
2.4 查找i:type=d3p1:ScreenLibrary,找到后递归读取子节点SerializedName获取树状节点名称。同时在properties里读取MultiExpressionPropertyBinding
2.5 查找i:type=d3p1:PrefabLibrary,找到后递归读取子节点SerializedName获取树状节点名称。同时在properties里读取MultiExpressionPropertyBinding。同时在PrefabViewConcept.Prefab里读取预设件URL路径
2.6 遍历子工程,重复步骤2.5

3. 导出文件说明

在这里插入图片描述

============================主工程.kzproj/ScreenItems 【主工程节点】
树状节点名【工程名】
是预设件输出Prefabs路径
有绑定输出绑定内容bindgs
============================主工程.kzproj/PrefabItems 【主工程预设件】
树状节点名【工程名】
有绑定输出绑定内容bindgs
============================..\子工程\子工程.kzproj/PrefabItems【子工程预设件】
树状节点名【工程名】
有绑定输出绑定内容bindgs

4. 使用说明

比如要查看Datasource里ShowHMI接口相关节点逻辑
可以在导出文件中搜索ShowHMI,可以看到绑定该接口的节点信息,如果是绑定到私有属性,可以同时搜属性名,这样能在kanzi工程中快速定位,上手业务,不至于晕头转向。

5.代码

// 解析GWCluster.kzproj,获取节点名称,路径,绑定信息
// 解析子工程.kzproj
// 解析xml,获取xml节点名称
// 按xml查找工程节点信息,遇到绑定,增加查找列表,最后匹配生成表格
// 导出excel#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <iostream>
#include <sstream>
#include "tinyxml2.h"#define TEST (1)static std::string Number2Stri(int value)
{std::string str;std::stringstream ss;ss << value;ss >> str;return str;
}static tinyxml2::XMLElement* gRootElement = NULL;
static std::vector<std::string> gReferenceItems;struct KanziBinding
{std::string propertyTypeName;std::string expression;
};struct KanziItem
{std::string name;std::string referredItemPath;std::vector<KanziBinding> bindgs;KanziItem* prefabItem=NULL;std::vector<KanziItem*> childs;KanziItem() :name(""), referredItemPath("") {}void print(int level = 0) {std::cout << name << ": " << childs.size() << " ";if (referredItemPath.size() != 0) {std::cout << "referredItemPath=" << referredItemPath << std::endl;}else {std::cout << std::endl;}if (bindgs.size() != 0) {for (int i = 0; i < bindgs.size(); i++) {std::cout << "bindgs/" << i << ":" << bindgs[i].propertyTypeName << "=" << bindgs[i].expression << std::endl;}}for (int i = 0; i < childs.size(); i++) {std::string str;str.resize(level, '-');std::cout << str << i << "-";childs[i]->print(level + 1);}}void generateOutput(std::string& output, std::string& projectname, int level = 0) {std::string str;str.resize(level, '-');output += str + name + "," + referredItemPath + ",[" + projectname + "]\n";for (int i = 0; i < bindgs.size(); i++) {output += "bindgs/" + Number2Stri(i + 1) + "," + bindgs[i].propertyTypeName + "=" + bindgs[i].expression + ",";if (i == bindgs.size() - 1) {output += "\n";}}for (int i = 0; i < childs.size(); i++) {childs[i]->generateOutput(output, projectname, level+1);}}
};
static KanziItem gScreenItems;
static KanziItem gScreenPrefabItems;static void ReadFileContentsByte(std::string filename, std::vector<char>& data);
static void WriteFileContentsByte(std::string filename, std::string& data);
static tinyxml2::XMLError ParseFile(std::vector<char>& fileData);
static tinyxml2::XMLElement* FindLabel(tinyxml2::XMLElement* root, std::string name);
static tinyxml2::XMLElement* FindLabelFromChildByName(tinyxml2::XMLElement* root, std::string name);
static tinyxml2::XMLElement* FindLabelFromChildRecurseByName(tinyxml2::XMLElement* root, std::string name);
static tinyxml2::XMLElement* FindLabelFromChildRecurseByNameValue(tinyxml2::XMLElement* root, std::string name, std::string value);
static tinyxml2::XMLElement* FindElementByAttr(tinyxml2::XMLElement* root, std::string type, std::string name);
static void FindProjectReferenceItem(tinyxml2::XMLElement* root, std::string type, std::string name);
static bool FindProjectReferenceItemValue(tinyxml2::XMLElement* root, std::string type, std::string name);static void FindProjectScreenItem(tinyxml2::XMLElement* root, KanziItem& item);
static bool FindProjectScreenItemValue(tinyxml2::XMLElement* root, std::string name);static void FindPrefabsItem(tinyxml2::XMLElement* root, KanziItem& item);int main(int argc, char *argv[])
{std::cout << "Hello World!\n";std::string kzproj = "";std::string kzprojHead = "";std::string kzprojName = "";std::string xmlpath = "";for (int i = 0; i < argc; i++) {std::cout << i << ":" << argv[i] << std::endl;if (1 == i) {kzproj = std::string(argv[i]);}// else if (2 == i) {//     xmlpath = std::string(argv[i]);// }}if(kzproj.size() == 0)kzproj = "D:\\chenchao\\hmi\\v4\\cluster_es15_code\\cluster_es15_code\\GWCluster\\1Main\\GWCluster.kzproj";std::cout << "kzproj:" << kzproj << std::endl;int lastIndex = kzproj.find_last_of("\\");kzprojHead = kzproj.substr(0, lastIndex+1);kzprojName = kzproj.substr(lastIndex+1, kzproj.size());std::cout << "kzprojHead:" << kzprojHead << std::endl;std::cout << "kzprojName:" << kzprojName << std::endl;//if (xmlpath.size() == 0)//    xmlpath = "D:\\chenchao\\hmi\\v4\\cluster_es15_code\\cluster_es15_code\\GWCluster\\Application\\bin\\ClusterData.xml";//std::cout << "xmlpath:" << xmlpath << std::endl;std::cout << "start parse:" << kzproj << std::endl;std::vector<char> data;ReadFileContentsByte(kzproj, data);if (data.size() == 0) {std::cout << "error: " << kzproj << " size=0" << std::endl;exit(0);}tinyxml2::XMLDocument doc;tinyxml2::XMLError error = doc.Parse(data.data(), data.size());if (error == tinyxml2::XML_SUCCESS){        }else {std::cout << "error: " << kzproj << " ParseFile" << std::endl;exit(0);}gRootElement = doc.RootElement();if (gRootElement == NULL) {std::cout << "error: " << kzproj << " gRootElement=0" << std::endl;exit(0);}std::cout << "      parse: Project References" << std::endl;gReferenceItems.clear();FindProjectReferenceItem(gRootElement, "i:type", "d3p1:ProjectReferenceItem");std::cout << "      parse: Screen Items" << std::endl;tinyxml2::XMLElement* ScreenLibrary = FindElementByAttr(gRootElement, "i:type", "d3p1:ScreenLibrary");if (ScreenLibrary == NULL) {std::cout << "error: " << kzproj << " ScreenLibrary=0" << std::endl;exit(0);}FindProjectScreenItem(ScreenLibrary, gScreenItems);//loggScreenItems.print();std::cout << "      parse: Prefabs Items" << std::endl;tinyxml2::XMLElement* PrefabItems = FindElementByAttr(gRootElement, "i:type", "d3p1:PrefabLibrary");if (PrefabItems == NULL) {std::cout << "error: " << kzproj << " PrefabItems=0" << std::endl;// exit(0);}else {FindPrefabsItem(PrefabItems, gScreenPrefabItems);}//loggScreenPrefabItems.print();//std::cout << "     match item prefab->prefab lib" << std::endl;//GWCluster/Prefabs/DarkBgForShowHMI/ -> DarkBgForShowHMIstd::vector<KanziItem*> gSubProjectPrefabItems;for (int a = 0; a < gReferenceItems.size(); a++) {std::cout << "start parse: SubProject Prefabs Items" << a << gReferenceItems[a] << std::endl;std::string subpath = kzprojHead + gReferenceItems[a];std::vector<char> data;ReadFileContentsByte(subpath, data);if (data.size() == 0) {std::cout << "error: " << subpath << " size=0" << std::endl;exit(0);}tinyxml2::XMLDocument doc;tinyxml2::XMLError error = doc.Parse(data.data(), data.size());if (error == tinyxml2::XML_SUCCESS){}else {std::cout << "error: " << subpath << " ParseFile" << std::endl;exit(0);}tinyxml2::XMLElement* root = doc.RootElement();if (root == NULL) {std::cout << "error: " << subpath << " root=0" << std::endl;exit(0);}std::cout << "      parse: SubProject Prefabs Items" << gReferenceItems[a] << std::endl;tinyxml2::XMLElement* PrefabItems = FindElementByAttr(root, "i:type", "d3p1:PrefabLibrary");if (PrefabItems == NULL) {std::cout << "error: " << subpath << " PrefabItems=0" << std::endl;// exit(0);}else {KanziItem* one = new KanziItem;FindPrefabsItem(PrefabItems, *one);gSubProjectPrefabItems.push_back(one);//logone->print();}}std::cout << "     create output file" << std::endl;std::string output = "";output += "============================" + kzprojName + "/ScreenItems\n";gScreenItems.generateOutput(output, kzprojName);output += "============================" + kzprojName + "/PrefabItems\n";gScreenPrefabItems.generateOutput(output, kzprojName);if (gSubProjectPrefabItems.size() != gReferenceItems.size()) {std::cout << "error: gSubProjectPrefabItems.size() != gReferenceItems.size()" << gSubProjectPrefabItems.size() << "," << gReferenceItems.size() << std::endl;exit(0);}for (int i = 0; i < gSubProjectPrefabItems.size(); i++) {output += "============================" + gReferenceItems[i] + "/PrefabItems\n";gSubProjectPrefabItems[i]->generateOutput(output, gReferenceItems[i]);}WriteFileContentsByte("nodexml.txt", output);std::cout << "Finish!" << std::endl;}static void ReadFileContentsByte(std::string filename, std::vector<char>& data)
{std::fstream fin;fin.open(filename, std::ios::in | std::ios::binary);if (!fin.is_open()){return;}//const int LENGTH = 1000;fin.seekg(0, std::ios::end);long int size = fin.tellg();fin.seekg(0, std::ios::beg);data.resize(size, 0);char temp;long i = 0;while ((temp = fin.get()) != EOF){//str.push_back((char)temp);if (i >= size) {std::cout << i << "/" << size << std::endl;exit(0);}data[i] = temp;i++;//std::cout << (byte)temp;}fin.close();
}static void WriteFileContentsByte(std::string filename, std::string& data)
{std::fstream fout;fout.open(filename, std::ios::out);if (!fout.is_open()){std::cout << "no open file " << filename << std::endl;return;}fout << data;fout.close();
}tinyxml2::XMLError ParseFile(std::vector<char>& fileData)
{// Parse the XML document from the memory and release the open file.tinyxml2::XMLDocument doc;tinyxml2::XMLError error = doc.Parse(fileData.data(), fileData.size());// If the plugin successfully loads the file set in the XML Data Source File property, create data objects.//if (error == tinyxml2::XML_SUCCESS)//{//    // Get the root XML element.//    tinyxml2::XMLElement* element = doc.RootElement();//    return element;//}return error;
}tinyxml2::XMLElement* FindLabel(tinyxml2::XMLElement* root, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        if (child->Name() && strcmp(child->Name(), "SerializedName") == 0) {if (child->GetText() && strcmp(child->GetText(), "Project References") == 0) {std::cout << "FindLabel find Project References";return root;}}tinyxml2::XMLElement* r = FindLabel(child, name);if (r) {std::cout << "<-" << child->Name();return r;}i++;}return NULL;
}tinyxml2::XMLElement* FindLabelFromChildByName(tinyxml2::XMLElement* root, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        /*if (child->Name() && strcmp(child->Name(), name.c_str()) == 0) {return child;}*/std::string a = std::string(child->Name());int index = a.find(name);if (index >= 0)return child;i++;}return NULL;
}tinyxml2::XMLElement* FindLabelFromChildRecurseByName(tinyxml2::XMLElement* root, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        if (child->Name() /*strcmp(child->Name(), name.c_str()) == 0*/) {std::string a = std::string(child->Name());int index = a.find(name);if(index >= 0)return child;}tinyxml2::XMLElement* r = FindLabelFromChildRecurseByName(child, name);if (r) {return r;}i++;}return NULL;
}tinyxml2::XMLElement* FindLabelFromChildRecurseByNameValue(tinyxml2::XMLElement* root, std::string name, std::string value) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.  if (child->Name() && child->GetText()) {std::string a = std::string(child->Name());std::string b = std::string(child->GetText());int index = a.find(name);int index2 = b.find(value);if (index >= 0 && index2 >= 0)return child;}//std::cout << child->Name() << " " << (child->GetText() ? child->GetText():"") << std::endl;tinyxml2::XMLElement* r = FindLabelFromChildRecurseByNameValue(child, name, value);if (r) {return r;}i++;}return NULL;
}void FindProjectReferenceItem(tinyxml2::XMLElement* root, std::string type, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        const tinyxml2::XMLAttribute* attr = child->FindAttribute(type.c_str());if (attr) {if (strcmp(attr->Value(), name.c_str()) == 0) {FindProjectReferenceItemValue(child, "i:type", "d9p1:string");continue;}} FindProjectReferenceItem(child, type, name);i++;}
}bool FindProjectReferenceItemValue(tinyxml2::XMLElement* root, std::string type, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        //if (child->Name() && strcmp(child->Name(), "ProjectItem") == 0) {const tinyxml2::XMLAttribute* attr = child->FindAttribute(type.c_str());if (attr) {if (strcmp(attr->Value(), name.c_str()) == 0) {std::cout << __FUNCTION__ << " " <<child->GetText() << std::endl;gReferenceItems.push_back(child->GetText());return true;}}//}bool r = FindProjectReferenceItemValue(child, type, name);if (r) {return r;}i++;}return false;
}void FindProjectScreenItem(tinyxml2::XMLElement* root, KanziItem& item) {// "i:type", "d7p1:"int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.if (child->Name() && strcmp(child->Name(), "SerializedName") == 0) {item.name = child->GetText();//std::cout << "item.name=" <<item.name << std::endl;//if ("RootPage" == item.name) {//    std::cout << std::endl;//}}else if (child->Name() && strcmp(child->Name(), "properties") == 0) {tinyxml2::XMLElement* MultiExpressionPropertyBinding = FindLabelFromChildRecurseByName(child, ":MultiExpressionPropertyBinding");if (MultiExpressionPropertyBinding){tinyxml2::XMLElement* referenceKeyValuesInCode = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":referenceKeyValuesInCode");tinyxml2::XMLElement* targetPropertyTypeReference = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":targetPropertyTypeReference");if (referenceKeyValuesInCode && referenceKeyValuesInCode->FirstChildElement()&& targetPropertyTypeReference) {tinyxml2::XMLElement* pathString = FindLabelFromChildRecurseByName(referenceKeyValuesInCode, ":pathString");tinyxml2::XMLElement* propertyTypeName = FindLabelFromChildRecurseByName(referenceKeyValuesInCode, ":propertyTypeName");tinyxml2::XMLElement* propertyTypeNameTarget = FindLabelFromChildRecurseByName(targetPropertyTypeReference, ":propertyTypeName");if (pathString && propertyTypeName && propertyTypeNameTarget) {KanziBinding kanziBinding;kanziBinding.propertyTypeName = propertyTypeNameTarget->GetText();kanziBinding.expression = std::string(pathString->GetText())+ "->"+std::string(propertyTypeName->GetText());item.bindgs.push_back(kanziBinding);}}else {tinyxml2::XMLElement* code = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":code");tinyxml2::XMLElement* propertyTypeName = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":propertyTypeName");if (code && propertyTypeName) {KanziBinding kanziBinding;kanziBinding.propertyTypeName = propertyTypeName->GetText();kanziBinding.expression = code->GetText();item.bindgs.push_back(kanziBinding);}}}tinyxml2::XMLElement* d10p1_Key = FindLabelFromChildRecurseByNameValue(child, ":Key", "Node2DPrefabPlaceholderTemplate");if (d10p1_Key) {tinyxml2::XMLElement* pathString = FindLabelFromChildRecurseByName((tinyxml2::XMLElement*)d10p1_Key->Parent(), ":pathString");if (pathString) {item.referredItemPath = pathString->GetText();}}}else if (child->Name() && strcmp(child->Name(), "children") == 0) {for (tinyxml2::XMLElement* child_children = child->FirstChildElement(); child_children; child_children = child_children->NextSiblingElement()){if (child_children->Name() && strcmp(child_children->Name(), "ProjectItem") == 0) {const tinyxml2::XMLAttribute* attr = child_children->FindAttribute("i:type");if (attr) {int index = std::string(attr->Value()).find(":ResourceDictionaryItem");//int index2 = std::string(attr->Value()).find(":LayerPrefabPlaceholder");//int index3 = std::string(attr->Value()).find(":ComponentNode2D");if (index  >= 0) {continue;}                        else {KanziItem* itemchild = new KanziItem;FindProjectScreenItem(child_children, *itemchild);item.childs.push_back(itemchild);}}}}break;}i++;}
}bool FindProjectScreenItemValue(tinyxml2::XMLElement* root, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        if (child->Name() && strcmp(child->Name(), name.c_str()) == 0) {std::cout << __FUNCTION__ << " " << child->Name() << ":" <<child->GetText() << std::endl;gReferenceItems.push_back(child->GetText());}bool r = FindProjectScreenItemValue(child, name);//if (r) {//    return r;//}i++;}return false;
}tinyxml2::XMLElement* FindElementByAttr(tinyxml2::XMLElement* root, std::string type, std::string name) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.        //if (child->Name() && strcmp(child->Name(), "ProjectItem") == 0) {const tinyxml2::XMLAttribute* attr = child->FindAttribute(type.c_str());if (attr) {if (strncmp(attr->Value(), name.c_str(), name.size()) == 0) {return child;}}//}tinyxml2::XMLElement* r = FindElementByAttr(child, type, name);if (r)return r;i++;}return NULL;
}void FindPrefabsItem(tinyxml2::XMLElement* root, KanziItem& item) {int i = 0;for (tinyxml2::XMLElement* child = root->FirstChildElement(); child; child = child->NextSiblingElement()){// Recurse.if (child->Name() && strcmp(child->Name(), "SerializedName") == 0) {std::string Isolation = "<Isolation";std::string ResourceDictionaryInNode = "<ResourceDictionaryInNode>";std::string Placeholder = "<Preview Scene Lights Placeholder>";std::string Material_Preview = "<Material Preview";std::string Mesh_Preview = "<Mesh Preview";if (strncmp(child->GetText(), Isolation.c_str(), Isolation.size()) == 0|| strncmp(child->GetText(), ResourceDictionaryInNode.c_str(), ResourceDictionaryInNode.size()) == 0|| strncmp(child->GetText(), Placeholder.c_str(), Placeholder.size()) == 0|| strncmp(child->GetText(), Material_Preview.c_str(), Material_Preview.size()) == 0|| strncmp(child->GetText(), Mesh_Preview.c_str(), Mesh_Preview.size()) == 0) {continue;}else {item.name = child->GetText();//std::cout << "prefab item.name=" << item.name << std::endl;}            }else if (child->Name() && strcmp(child->Name(), "properties") == 0) {tinyxml2::XMLElement* d10p1_Key = FindLabelFromChildRecurseByNameValue(child, ":Key", "PrefabViewConcept.Prefab");if (d10p1_Key){tinyxml2::XMLElement* pathString = FindLabelFromChildRecurseByName((tinyxml2::XMLElement*)d10p1_Key->Parent(), ":pathString");if (pathString) {item.referredItemPath = pathString->GetText();}}tinyxml2::XMLElement* MultiExpressionPropertyBinding = FindLabelFromChildRecurseByName(child, ":MultiExpressionPropertyBinding");if (MultiExpressionPropertyBinding){tinyxml2::XMLElement* referenceKeyValuesInCode = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":referenceKeyValuesInCode");tinyxml2::XMLElement* targetPropertyTypeReference = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":targetPropertyTypeReference");if (referenceKeyValuesInCode && referenceKeyValuesInCode->FirstChildElement()&& targetPropertyTypeReference) {tinyxml2::XMLElement* pathString = FindLabelFromChildRecurseByName(referenceKeyValuesInCode, ":pathString");tinyxml2::XMLElement* propertyTypeName = FindLabelFromChildRecurseByName(referenceKeyValuesInCode, ":propertyTypeName");tinyxml2::XMLElement* propertyTypeNameTarget = FindLabelFromChildRecurseByName(targetPropertyTypeReference, ":propertyTypeName");if (pathString && propertyTypeName && propertyTypeNameTarget) {KanziBinding kanziBinding;kanziBinding.propertyTypeName = propertyTypeNameTarget->GetText();kanziBinding.expression = std::string(pathString->GetText()) + "->" + std::string(propertyTypeName->GetText());item.bindgs.push_back(kanziBinding);}}else {tinyxml2::XMLElement* code = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":code");tinyxml2::XMLElement* propertyTypeName = FindLabelFromChildRecurseByName(MultiExpressionPropertyBinding, ":propertyTypeName");if (code && propertyTypeName) {KanziBinding kanziBinding;kanziBinding.propertyTypeName = propertyTypeName->GetText();kanziBinding.expression = code->GetText();item.bindgs.push_back(kanziBinding);}}}}else if (child->Name() && strcmp(child->Name(), "children") == 0) {for (tinyxml2::XMLElement* child_children = child->FirstChildElement(); child_children; child_children = child_children->NextSiblingElement()) {if (child_children->Name() && strcmp(child_children->Name(), "ProjectItem") == 0) {KanziItem* itemchild = new KanziItem;FindPrefabsItem(child_children, *itemchild);if (itemchild->name.size() > 0) {item.childs.push_back(itemchild);}}}            }i++;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/827481.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

春季打卡圣地|超出片的成都文创产业园

春季拍照还在去人民公园、青龙湖吗&#xff1f;这个春天来点不一样的&#xff0c;就在金牛区的成都文创产业园——国际数字影像产业园旁&#xff0c;沙河源公园占地面积约150亩&#xff0c;地下室面积约4000平方米&#xff0c;这里的花能让摄影爱好者们拍个够。 国际数字影像产…

FFmpeg源码编译

msys2 依赖环境安装 依赖环境安装编译X264编译 fdk-aac文件处理编译x265编译FFmpeg 依赖环境安装 编译X264 用于h264 AVC视频格式编码 CCcl ./configure --enable-shared #指定使用cl,编译成动态链接库 make -j32 #使用32线程进行编码 make install命令一 关于第一条命令执…

攻击者使用新型隐写术攻击,针对全球320个组织

隐写术是一种将数据隐藏在看似无害的文件中的技术&#xff0c;使用户和安全产品无法检测到它们。 近期&#xff0c;Positive Technologies 发现了TA558 黑客组织正在开展的一项新活动&#xff0c;使用隐写术将恶意代码隐藏在图像内&#xff0c;从而将各种恶意软件工具传递到目…

展会媒体邀约资源,媒体宣传服务执行

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 在组织展会时&#xff0c;媒体宣传服务的执行是提升展会知名度和影响力的关键环节。 确定目标媒体&#xff1a;根据展会的主题和目标受众&#xff0c;选择适合的媒体进行邀请。这可能包…

docker 虚拟化与docker的概念

一、云计算的三种服务模式 laas、pass、saas 1.1 IaaS: Infrastructure-as-a-Service&#xff08;基础设施即服务&#xff09; 第一层叫做IaaS&#xff0c;有时候也叫做Hardware-as-a-Service&#xff0c;几年前如果你想在办公室或者公司的网站上运行一些企业应用&#xff0c…

将彩色图转化为灰度图及其原理介绍

彩色图介绍 彩色图像是一种包含颜色信息的图像&#xff0c;通常由红色、绿色和蓝色&#xff08;RGB&#xff09;三个颜色通道组成。这三种颜色通道可以叠加在一起来形成各种不同的颜色。 彩色图像中的每个像素都有三个数值&#xff0c;分别表示红色、绿色和蓝色通道的强度或亮…

vue 关键字变红

1.html <div v-html"replaceKeywordColor(item.title)" ></div> 2.js //value为搜索框内绑定的值 replaceKeywordColor(val) {if (val?.includes(this.value) && this.value ! ) {return val.replace(this.value,<font color"red&…

RuoYi-Vue-Plus (SaToken 注解鉴权)

一、SaInterceptor 注解鉴权和路由拦截鉴权 拦截器&#xff1a;SaInterceptor 实现类位置&#xff1a; cn.dev33.satoken.interceptor.SaInterceptor 功能&#xff1a;Sa-Token 综合拦截器&#xff0c;提供注解鉴权和路由拦截鉴权能力 /*** 创建一个 Sa-Token 综合拦截器&…

重学java 19.面向对象 继承 上

走不出的那段阴霾&#xff0c;很多时候只不过是&#xff0c;我们把它当成了唯一 —— 24.4.22 面向对象整体知识导向&#xff1a; 知识梳理&#xff1a; 1.知道继承的好处 2.会使用继承 3.继承之后成员变量和成员方法的访问特点 4.方法的重写&#xff0c;知道方法重写的使用场景…

从构成看自来水厂自动化控制系统的创新与发展

自来水厂自动化控制系统涵盖了多个关键组成部分&#xff0c;包括水管理云平台、供水监控系统以及供水调度平台。 系统内嵌了一系列自主创新的核心算法&#xff0c;这些算法结合了数学建模、机器仿真和流体力学等多元数据模型&#xff0c;以优化设备间的关联和控制关系&#xf…

python爬虫 - 爬取html中的script数据(爬取新闻 36kr.com)

文章目录 1. 分析页面内容数据格式2. 使用re.findall方法&#xff0c;爬取新闻3. 使用re.search 方法&#xff0c;爬取新闻 1. 分析页面内容数据格式 打开 https://36kr.com/ 按F12&#xff08;或 在网页上右键 --> 检查&#xff08;Inspect&#xff09;&#xff09; 找…

大珩PPT助手一键颜色设置

大珩PPT助手最新推出的一键设置文字颜色和背景色功能&#xff0c;为用户在创建演示文稿时带来了更便捷、高效的体验。这一功能使用户能够轻松调整演示文稿中文字的颜色和幻灯片的背景色&#xff0c;以满足不同场合和主题的需要。 以下是该功能的几个关键特点和优势&#xff1a…

2024深圳杯东三省数学建模竞赛A题个火箭残骸的准确定位代码成品论文

问题重述 绝大多数火箭为多级火箭&#xff0c;下面级火箭或助推器完成既定任务后&#xff0c;通过级间分离装置分离后坠落。在坠落至地面过程中&#xff0c;残骸会产生跨音速音爆。为了快速回收火箭残骸&#xff0c;在残骸理论落区内布置多台震动波监测设备&#xff0c;以接收不…

账号安全基本措施2

sudo命令 sudo(superuser do)&#xff0c;允许系统管理员让普通用户执行一些或者全部的root命令的一个工具。 其配置在/etc/sudoers权。它允许系统管理员集中的管理用户的使用权限和使用的主机。属性必须为0440。 语法检查&#xff1a; 检查语法&#xff1a; 修改文件时&…

刷课必备!用Python实现网上自动做题

前言 开学少不了老师会布置一些 软件上面的作业&#xff0c;今天教大家用python制作自动答题脚本&#xff0c;100%准确率哦喜欢的同学记得关注、收藏哦 环境使用 Python3.8Pycharm 模块使用 import requests —> 数据请求模块 pip install requestsimport parsel —>…

【Qt 学习笔记】Qt常用控件 | 显示类控件 | Calendar Widget的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 显示类控件 | Calendar Widget的使用及说明 文章编号&am…

基于STM32实现流水灯【Proteus仿真】

详情更多 wechat&#xff1a;嵌入式工程师成长日记 https://mp.weixin.qq.com/s?__bizMzg4Mzc3NDUxOQ&mid2247485624&idx1&sn4e553234c2624777409bd2067a07aad8&chksmcf430de0f83484f6189b119d9d83ea6e6f2a85d13afaa04d218483918231c38e6382d3007061&tok…

「React Native」为什么要选择 React Native 作为的跨端方案

文章目录 前言一、常见因素二、举个栗子2.1 项目背景2.2 为什么选择 React Native2.3 项目实施2.4 成果总结 前言 没有完美的跨端技术&#xff0c;只有适合的场景。脱离适用场景去谈跨端技术没有什么意义。 一、常见因素 共享代码库&#xff1a; React Native 允许开发者编写…

第⑮讲:Ceph集群管理与监控操作指南

文章目录 1.查看集群的状态信息2.动态的查看集群的状态信息3.查看集群的利用率4.查看OSD的资源利用率5.查看OSD的列表6.查看各组件的状态7.查看集群的仲裁信息8.查看/修改集群组件sock的配置参数 1.查看集群的状态信息 通过集群状态信息可以看到集群的健康状态、各个组件的运行…

PMP新版考试也要复习49个过程?如何复习更高效?

PMP中有五大过程组、十大知识领域&#xff0c;共计49个子过程&#xff0c;那么如何才能快速的记住这49个子过程&#xff0c;可以参考这篇文章理解加深记忆。 记忆需要花费时间&#xff1a;30分钟 记忆持续时间&#xff1a;永久 接下来按照思路进行 场景&#xff1a;大家都熟…