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);
    //log
    gScreenItems.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);
    }
    //log
    gScreenPrefabItems.print();

    //std::cout << "     match item prefab->prefab lib" << std::endl;
    //GWCluster/Prefabs/DarkBgForShowHMI/ -> DarkBgForShowHMI


    std::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);

            //log
            one->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++;
    }
}


6. 补充3.9.8版本脚本

追加子工程递归查找引用工程。

// 解析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;
static std::unordered_map<std::string, int> gSubProjectPaths;

struct KanziBinding
{
    std::string propertyTypeName;
    std::string expression;
};

struct KanziItem
{
    std::string name;
    std::string projectName;
    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 + ",\n";
            //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 std::vector<KanziItem*> gSubProjectPrefabItems;

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, std::vector<std::string>& referenceItems);
static bool FindProjectReferenceItemValue(tinyxml2::XMLElement* root, std::string type, std::string name, std::vector<std::string>& referenceItems);

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);

static void HandleReferenceProject(std::vector<std::string>& referenceItems, std::string head);


static int mainTest(int argc, char *argv[])
{
    std::cout << "Hello World! kanzi 3.9.8\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\\3DKanzi\\3DKanzi\\Launcher3d_P03&B07\\3DLauncher\\Launcher3d\\Tool_project\\Launcher3d.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", gReferenceItems);

    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);
    }

    gScreenItems.projectName = kzprojName;
    FindProjectScreenItem(ScreenLibrary, gScreenItems);
    //log
    gScreenItems.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);
    }
    //log
    gScreenPrefabItems.print();

    //std::cout << "     match item prefab->prefab lib" << std::endl;
    //GWCluster/Prefabs/DarkBgForShowHMI/ -> DarkBgForShowHMI
    HandleReferenceProject(gReferenceItems, kzprojHead);

    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);
    //}

    std::unordered_map<std::string, int>::iterator it = gSubProjectPaths.begin();
    for (it;  it != gSubProjectPaths.end(); ++it) {
        std::cout << "gSubProjectPaths subpath = " << gSubProjectPaths.size() << it->first << std::endl;
    }

    for (int i = 0; i < gSubProjectPrefabItems.size(); i++) {
        KanziItem* item = gSubProjectPrefabItems[i];
        output += "============================" + item->projectName + "/PrefabItems\n";
        item->generateOutput(output, item->projectName);
    }

    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, std::vector<std::string>& referenceItems) {
    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", referenceItems);
                    continue;
                }
            } 

        FindProjectReferenceItem(child, type, name, referenceItems);
        i++;
    }
}

bool FindProjectReferenceItemValue(tinyxml2::XMLElement* root, std::string type, std::string name, std::vector<std::string>& referenceItems) {
    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;
                    referenceItems.push_back(child->GetText());
                    return true;
                }
            }
        //}

        bool r = FindProjectReferenceItemValue(child, type, name, referenceItems);
        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;
            //}
            /*if (strcmp("APA2DController", item.name.c_str()) == 0) {
                std::cout << "a";
            }*/
            
        }
        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(":TriggerNodeComponent");
                        int index3 = std::string(attr->Value()).find(":BindingItem");
                        //int index2 = std::string(attr->Value()).find(":LayerPrefabPlaceholder");
                        //int index3 = std::string(attr->Value()).find(":ComponentNode2D");

                        if (index  >= 0 || index2 >= 0 || index3 >= 0) {
                            if (index3 >= 0) {
                                //properties
                                for (tinyxml2::XMLElement* childproperty = child_children->FirstChildElement(); childproperty; childproperty = childproperty->NextSiblingElement())
                                {
                                    if (childproperty->Name() && strcmp(childproperty->Name(), "properties") == 0) {
                                        KanziBinding kanziBinding;                                       
                                       
                                      // 
                                        bool finish_code = false;
                                        for (tinyxml2::XMLElement* childKeyValueOfstringDynamicPropertyeuDbPpRS = childproperty->FirstChildElement(); childKeyValueOfstringDynamicPropertyeuDbPpRS; childKeyValueOfstringDynamicPropertyeuDbPpRS = childKeyValueOfstringDynamicPropertyeuDbPpRS->NextSiblingElement()) {
                                            for (tinyxml2::XMLElement* childKey = childKeyValueOfstringDynamicPropertyeuDbPpRS->FirstChildElement(); childKey; childKey = childKey->NextSiblingElement()) {
                                                //std::cout << childKey->Name() << std::endl;
                                                if (childKey->GetText()) {
                                                    if (strcmp(childKey->GetText(), "BindingItem.Target") == 0) {
                                                        tinyxml2::XMLElement* propertyTypeName = FindLabelFromChildRecurseByName(childKeyValueOfstringDynamicPropertyeuDbPpRS, ":propertyTypeName");
                                                        kanziBinding.propertyTypeName = propertyTypeName->GetText();
                                                        break;
                                                    }
                                                    else if (strcmp(childKey->GetText(), "BindingItem.DisplayCodeForMerge") == 0) {
                                                        tinyxml2::XMLElement* code = FindLabelFromChildRecurseByName(childKeyValueOfstringDynamicPropertyeuDbPpRS, "value");
                                                        kanziBinding.expression = code->GetText();
                                                        finish_code = true;
                                                        break;
                                                    }
                                                }                                                
                                            }
                                            if (finish_code) {
                                                item.bindgs.push_back(kanziBinding);
                                                break;
                                            }
                                        }

                                    }
                                }
                            }
                            continue;
                        }                        
                        else {
                            KanziItem* itemchild = new KanziItem;
                            itemchild->projectName = item.projectName;
                            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::cout << __LINE__ << child->GetText() << std::endl;

            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;
                if (strcmp("APA2DController", item.name.c_str()) == 0) {
                    std::cout << "a";
                }
            }            

        }
        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) {
                    //skip binditem
                    
                    const tinyxml2::XMLAttribute* attr = child_children->FindAttribute("i:type");
                    if (attr) {
                        //std::cout << attr->Value() << std::endl;

                        int index = std::string(attr->Value()).find(":ResourceDictionaryItem");
                        int index2 = std::string(attr->Value()).find(":TriggerNodeComponent");
                        int index3 = std::string(attr->Value()).find(":BindingItem");
                        int index4 = std::string(attr->Value()).find(":NodeComponent");
                       // int index5 = std::string(attr->Value()).find(":EmptyLayer");

                        if (index >= 0 || index2 >= 0 || index3 >= 0 || index4 >= 0) {

                            if (index3 >= 0) {
                                //properties
                                for (tinyxml2::XMLElement* childproperty = child_children->FirstChildElement(); childproperty; childproperty = childproperty->NextSiblingElement())
                                {
                                    if (childproperty->Name() && strcmp(childproperty->Name(), "properties") == 0) {
                                        KanziBinding kanziBinding;

                                        // 
                                        bool finish_code = false;
                                        for (tinyxml2::XMLElement* childKeyValueOfstringDynamicPropertyeuDbPpRS = childproperty->FirstChildElement(); childKeyValueOfstringDynamicPropertyeuDbPpRS; childKeyValueOfstringDynamicPropertyeuDbPpRS = childKeyValueOfstringDynamicPropertyeuDbPpRS->NextSiblingElement()) {
                                            for (tinyxml2::XMLElement* childKey = childKeyValueOfstringDynamicPropertyeuDbPpRS->FirstChildElement(); childKey; childKey = childKey->NextSiblingElement()) {
                                                if (childKey->GetText()) {
                                                    if (strcmp(childKey->GetText(), "BindingItem.Target") == 0) {
                                                        tinyxml2::XMLElement* propertyTypeName = FindLabelFromChildRecurseByName(childKeyValueOfstringDynamicPropertyeuDbPpRS, ":propertyTypeName");
                                                        kanziBinding.propertyTypeName = propertyTypeName->GetText();
                                                        break;
                                                    }
                                                    else if (strcmp(childKey->GetText(), "BindingItem.DisplayCodeForMerge") == 0) {
                                                        tinyxml2::XMLElement* code = FindLabelFromChildRecurseByName(childKeyValueOfstringDynamicPropertyeuDbPpRS, "value");
                                                        kanziBinding.expression = code->GetText();
                                                        finish_code = true;
                                                        break;
                                                    }
                                                }
                                                
                                            }
                                            if (finish_code) {
                                                item.bindgs.push_back(kanziBinding);
                                                break;
                                            }
                                        }

                                    }
                                }
                            }

                            continue;
                        }
                    }

                    KanziItem* itemchild = new KanziItem;
                    itemchild->projectName = item.projectName;
                    FindPrefabsItem(child_children, *itemchild);
                    if (itemchild->name.size() > 0) {
                        item.childs.push_back(itemchild);
                    }
                }
            }            
        }
        i++;
    }
}

void HandleReferenceProject(std::vector<std::string>& referenceItems, std::string head) {

    for (int a = 0; a < referenceItems.size(); a++) {
        std::cout << "start parse: SubProject Prefabs Items" << a << referenceItems[a] << std::endl;
        std::string subpath = head + referenceItems[a];

        int lastIndexPath = subpath.find_last_of("\\");
        std::string kzprojectName = subpath.substr(lastIndexPath+1, subpath.size());

        std::unordered_map<std::string, int>::iterator it = gSubProjectPaths.find(kzprojectName);
        if (it != gSubProjectPaths.end()) {
            std::cout << "!!!!!! has handle subpath = " << kzprojectName << std::endl;
            continue;
        }

        std::cout << " new sub project = " << kzprojectName << std::endl;

        gSubProjectPaths[kzprojectName] = 1;

        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::vector<std::string> tempReferenceItems;
        tempReferenceItems.clear();

        std::cout << "      parse: SubProject References" << std::endl;        
        FindProjectReferenceItem(root, "i:type", "d3p1:ProjectReferenceItem", tempReferenceItems);

        std::cout << "      parse: SubProject Prefabs Items" << referenceItems[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;
            one->projectName = kzprojectName;
            FindPrefabsItem(PrefabItems, *one);
            gSubProjectPrefabItems.push_back(one);

            //log
            one->print();
        }

        //
        if (tempReferenceItems.size() > 0) {
            int lastIndex = subpath.find_last_of("\\");
            std::string currentkzprojHead = subpath.substr(0, lastIndex + 1);
            std::cout << "subpath=" << subpath << std::endl;
            std::cout << "currentkzprojHead=" << currentkzprojHead << std::endl;
            HandleReferenceProject(tempReferenceItems, currentkzprojHead);
        }        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值