XML生成编辑器工具类

  • 初步创建编辑器自定义窗口
  • 添加窗口内部UI
  • 添加创建XML文件功能
  • 创建Asset数据用于保存XML数据
  • 自行更改Asset数据保存路径和名称
  • 自动填入选取的Asset数据
  • 添加勾选框决定是否要生成Asset数据
  • 添加输入警示
  • 添加数据为空时创建文件的警告窗口
  • 主要工具类完整代码


初步创建编辑器自定义窗口

新建CustomTooL.cs脚本,并编写以下代码,因为我们要定义自己的编辑器窗口,因此脚本要放在Editor文件夹下,同时要继承EditorWindow类

unity 编辑器 动态创建枚举 unity自定义编辑器_数据

public class CustomTool : EditorWindow
{
    //XML文件名称
    public string XmlName;
    //根节点名称
    public string root;
    
    CustomTool()
    {
        this.titleContent = new GUIContent("XmlTool");
    }

    [MenuItem("CustomTool/XML")]
    static void showWindow()
    {
        EditorWindow.GetWindow(typeof(CustomTool));
    }

	void OnGUI()
    {
        EditorGUILayout.BeginVertical();

        ScrollPos = EditorGUILayout.BeginScrollView(ScrollPos);

        //绘制标题
        GUILayout.Space(10);
        GUILayout.Label("Create/Update Xml");


        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndVertical();
    }
}

这样在编辑器顶部工具栏中就会出现我们自己定义的编辑器窗口

unity 编辑器 动态创建枚举 unity自定义编辑器_unity_02


打开窗口即可看到如下界面

unity 编辑器 动态创建枚举 unity自定义编辑器_xml_03

添加窗口内部UI

首先先绘制两个文字输入框以及一个按钮,分别是记录XML文件名,XML文件根节点名称以及创建按钮,在OnGUI方法中编写如下代码

void OnGUI()
    {
        EditorGUILayout.BeginVertical();

        ScrollPos = EditorGUILayout.BeginScrollView(ScrollPos);

        //绘制标题
        GUILayout.Space(10);
        GUILayout.Label("Create/Update Xml");

        //xml的名字
        GUILayout.Space(10);
        XmlName = EditorGUILayout.TextField("XML Name", XmlName);

        //根节点名称
        GUILayout.Space(10);
        root = EditorGUILayout.TextField("Root Name", root);

	    //按钮
        if (GUILayout.Button("Create/Update XML"))
        {

        }

        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndVertical();
    }

保存后再次打开窗口就会发现窗口内已经绘制出了我们所需要的UI

unity 编辑器 动态创建枚举 unity自定义编辑器_xml_04

添加创建XML文件功能

声明子节点的结构体

/// <summary>
/// 子节点结构体
/// </summary>
[System.Serializable]
public struct elmNew
{
	//子节点名称
    public string childRootName;
    //id
    public string attributeId;
    //Name
    public string attributeName;
    //下层子节点结构体
    public elmChildNode[] ElmChildNode;
}

/// <summary>
/// 子节点下层节点结构体
/// </summary>
[System.Serializable]
public struct elmChildNode
{
    public string name;
    public string innerText;
}

声明对应变量和序列化属性

//子节点
    [SerializeField]
    private List<elmNew> child = new List<elmNew>();

    //序列化属性
    protected SerializedProperty _assetLstProperty;
    //序列化对象
    protected SerializedObject _serializedObject;
    
    void OnEnable()
    {
        //序列化子节点结构体
        _serializedObject = new SerializedObject(this);
        _assetLstProperty = _serializedObject.FindProperty("child");
    }

编写CreateXML方法用于创建XML文件

/// <summary>
    /// 创建Xml文件
    /// </summary>
    /// <param name="fileName"></param>
    public void CreateXml(string fileName)
    {
        string filePath = Application.streamingAssetsPath + "/" + fileName + ".xml";

        //创建Xml文件实例
        XmlDocument xmlDoc = new XmlDocument();
        //创建root节点
        XmlElement root = xmlDoc.CreateElement(this.root);
        for (int i = 0; i < child.Count; i++)
        {
            //继续创建子节点
            XmlElement elmNew = xmlDoc.CreateElement(child[i].childRootName);
            //配置节点的两个属性
            elmNew.SetAttribute("id", child[i].attributeId);
            elmNew.SetAttribute("name", child[i].attributeName);
            //继续创建下一层节点
            for (int j = 0; j < child[i].ElmChildNode.Length; j++)
            {
                XmlElement childnode = xmlDoc.CreateElement(child[i].ElmChildNode[j].name);
                //设置节点数据
                childnode.InnerText = child[i].ElmChildNode[j].innerText;
                elmNew.AppendChild(childnode);
            }

            //把节点一层一层添加到XmlDoc里---------------->>>注意先后顺序

            root.AppendChild(elmNew);
        }

        xmlDoc.AppendChild(root);

        xmlDoc.Save(filePath);

        Debug.Log("CreateXml OK");
    }

OnGUI方法内绘制子节点输入框

//根节点名称
        GUILayout.Space(10);
        root = EditorGUILayout.TextField("Root Name", root);


        //子节点信息
        GUILayout.Space(10);
        _serializedObject.Update();
        //检查是否有修改
        EditorGUI.BeginChangeCheck();
        //显示
        EditorGUILayout.PropertyField(_assetLstProperty, true);
        //当检查结束时应用最新修改数据
        if (EditorGUI.EndChangeCheck())
        {
            _serializedObject.ApplyModifiedProperties();
        }

添加点击创建按钮后执行的方法

if (GUILayout.Button("Create/Update XML"))
        {
            CreateXml(XmlName);
        }

随后打开窗口即可看到

unity 编辑器 动态创建枚举 unity自定义编辑器_xml_05


输入数据并点击按钮生成文件

unity 编辑器 动态创建枚举 unity自定义编辑器_数据_06


unity 编辑器 动态创建枚举 unity自定义编辑器_xml_07


打开XML文件查看数据

unity 编辑器 动态创建枚举 unity自定义编辑器_数据_08

创建Asset数据用于保存XML数据

新建脚本XmlAsset.cs,继承自ScriptableObject,同样放置在Editor文件夹下

public class XmlAsset : ScriptableObject
{
    public string XmlName;
    public string root;
    public List<elmNew> child = new List<elmNew>();
}

回到CustomTool脚本,声明变量

//asset数据类
    public XmlAsset asset;

声明保存Asset数据方法,注意AssetDatabase.CreateAsset()方法的路径参数要填写相对路径

/// <summary>
    /// 保存Xml数据为Asset
    /// </summary>
    public void SaveAsset()
    {
        XmlAsset xmlAsset = ScriptableObject.CreateInstance<XmlAsset>();
        xmlAsset.XmlName = XmlName;
        xmlAsset.root = root;
        xmlAsset.child = child;
        AssetDatabase.CreateAsset(xmlAsset, "Assets/test.asset");

    }

调用SaveAsset方法

if (GUILayout.Button("Create/Update XML"))
        {
            CreateXml(XmlName);
            SaveAsset();
        }

运行测试

unity 编辑器 动态创建枚举 unity自定义编辑器_c#_09


unity 编辑器 动态创建枚举 unity自定义编辑器_xml_10

自行更改Asset数据保存路径和名称

这种保存数据需要能够自己决定保存的路径,因此在创建数据文件时需要弹出窗口选择保存路径
首先新建两个类,用于调用Window打开窗口的系统函数

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class OpenFileName
{
    public int structSize = 0;
    public IntPtr dlgOwner = IntPtr.Zero;
    public IntPtr instance = IntPtr.Zero;
    public String filter = null;
    public String customFilter = null;
    public int maxCustFilter = 0;
    public int filterIndex = 0;
    public String file = null;
    public int maxFile = 0;
    public String fileTitle = null;
    public int maxFileTitle = 0;
    public String initialDir = null;
    public String title = null;
    public int flags = 0;
    public short fileOffset = 0;
    public short fileExtension = 0;
    public String defExt = null;
    public IntPtr custData = IntPtr.Zero;
    public IntPtr hook = IntPtr.Zero;
    public String templateName = null;
    public IntPtr reservedPtr = IntPtr.Zero;
    public int reservedInt = 0;
    public int flagsEx = 0;
}

public class LocalDialog
{
    //链接指定系统函数       打开文件对话框
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
    public static bool GetOFN([In, Out] OpenFileName ofn)
    {
        return GetOpenFileName(ofn);
    }
        
    //链接指定系统函数        另存为对话框
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
    public static bool GetSFN([In, Out] OpenFileName ofn)
    {
        return GetSaveFileName(ofn);
    }

}

回到CustomTool脚本,声明路径变量

public string assetSavePath;

声明OpenSaveWindow方法和GetRelativePath方法

/// <summary>
    /// 绝对路径转相对路径
    /// </summary>
    /// <param name="filespec"></param>
    /// <param name="folder"></param>
    /// <returns></returns>
    public static string GetRelativePath(string filespec, string folder)
    {
         const string directorySeparatorChar = "\\";
         Uri pathUri = new Uri(filespec);

         if (!folder.EndsWith(directorySeparatorChar))
         {
             folder += directorySeparatorChar;
         }
         Uri folderUri = new Uri(folder);
         return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace("/", directorySeparatorChar));
    }    

	/// <summary>
    /// 开启Window保存文件窗口
    /// </summary>
    /// <param name="title"></param>
    /// <param name="_filter"></param>
    void OpenSaveWindow(string title, string _filter)
    {
        OpenFileName openFileName = new OpenFileName();
        openFileName.structSize = Marshal.SizeOf(openFileName);
        openFileName.filter = _filter;
        openFileName.file = new string(new char[256]);
        openFileName.maxFile = openFileName.file.Length;
        openFileName.fileTitle = new string(new char[64]);
        openFileName.maxFileTitle = openFileName.fileTitle.Length;
        openFileName.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//默认路径
        openFileName.title = title;
        openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;
        if (LocalDialog.GetSaveFileName(openFileName))
        {
            assetSavePath = GetRelativePath(openFileName.file, Application.dataPath);
        }
    }

修改SaveAsset方法

/// <summary>
    /// 保存Xml数据为Asset
    /// </summary>
    public void SaveAsset()
    {
        XmlAsset xmlAsset = ScriptableObject.CreateInstance<XmlAsset>();
        OpenSaveWindow("保存Xml数据", "asset文件(*.asset)\0*.asset");
        xmlAsset.XmlName = XmlName;
        xmlAsset.root = root;
        xmlAsset.child = child;
        AssetDatabase.CreateAsset(xmlAsset, "Assets/" + assetSavePath + ".asset");

    }

运行测试

unity 编辑器 动态创建枚举 unity自定义编辑器_unity_11


unity 编辑器 动态创建枚举 unity自定义编辑器_unity_12

自动填入选取的Asset数据

声明变量

//asset数据类
    public XmlAsset asset;

在OnGUI内添加

GUILayout.Label("Create/Update Xml");

        //读取asset数据
        asset = EditorGUILayout.ObjectField("选取Xml数据", asset, typeof(XmlAsset), true) as XmlAsset;
        if (asset != null)
        {
            XmlName = asset.XmlName;
            root = asset.root;
            child = asset.child;
        }

        //绘制文本

再次打开窗口测试

可以看到第一行多出来一个选择资源的选项框

unity 编辑器 动态创建枚举 unity自定义编辑器_数据_13


选取数据后

unity 编辑器 动态创建枚举 unity自定义编辑器_unity 编辑器 动态创建枚举_14

添加勾选框决定是否要生成Asset数据

声明变量

private bool isSaveAsset;

在OnGUI内添加语句,并修改按钮判断

GUILayout.Space(10);
        isSaveAsset = GUILayout.Toggle(isSaveAsset, "是否保存数据为Asset资源");

        if (GUILayout.Button("Create/Update XML"))
        {
            CreateXml(XmlName);
            if (isSaveAsset)
            {
                SaveAsset();
            }
        }

打开窗口测试就会发现按钮上一行多了个勾选项,当勾选时生成XML文件则会进行保存Asset数据操作,反之则只会生成XML文件

unity 编辑器 动态创建枚举 unity自定义编辑器_unity_15

添加输入警示

首先要判断是否有数据输入,在子节点的结构体里添加属性,用于判断是否有输入数据

/// <summary>
/// 子节点结构体
/// </summary>
[System.Serializable]
public struct elmNew
{
    public string childRootName;
    public string attributeId;
    public string attributeName;
    public elmChildNode[] ElmChildNode;

    /// <summary>
    /// 是否有填入数据
    /// </summary>
    public bool HasContent
    {
        get
        {
            for (int i = 0; i < ElmChildNode.Length; i++)
            {
                return childRootName.Length > 0 && attributeId.Length > 0 && attributeName.Length > 0 &&
                       ElmChildNode.Length > 0 && ElmChildNode[i].HasContent;
            }

            return childRootName.Length > 0 && attributeId.Length > 0 && attributeName.Length > 0 &&
                   ElmChildNode.Length > 0;
        }
    }
}

/// <summary>
/// 子节点下层节点结构体
/// </summary>
[System.Serializable]
public struct elmChildNode
{
    public string name;
    public string innerText;

    /// <summary>
    /// 是否有填入数据
    /// </summary>
    public bool HasContent
    {
        get { return name.Length > 0 && innerText.Length > 0; }
    }
}

声明剩余数据变量的判断方法

/// <summary>
    /// 判断XML名称是否为空
    /// </summary>
    /// <returns></returns>
    bool HasXmlNameContent()
    {
        return XmlName != null && XmlName.Length > 0;
    }

    /// <summary>
    /// 判断根节点是否为空
    /// </summary>
    /// <returns></returns>
    bool HasRootNameContent()
    {
        return root != null && root.Length > 0;
    }

    /// <summary>
    /// 判断子节点是否填入数据
    /// </summary>
    /// <returns></returns>
    bool HasChildContent()
    {
        if (child.Count < 0)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < child.Count; i++)
            {
                if (!child[i].HasContent)
                {
                    return false;
                }
                else if (i == child.Count - 1 && child[i].HasContent)
                {
                    return true;
                }
            }
        }

        return false;
    }

修改OnGUI的语句

//xml的名字
        GUILayout.Space(10);
        XmlName = EditorGUILayout.TextField("XML Name", XmlName);
        if (!HasXmlNameContent())
        {
            EditorGUILayout.HelpBox("XML文件名不能为空!", MessageType.Error);
        }

        //根节点名称
        GUILayout.Space(10);
        root = EditorGUILayout.TextField("Root Name", root);
        if (!HasRootNameContent())
        {
            EditorGUILayout.HelpBox("根节点不能为空!", MessageType.Error);
        }

        //子节点信息
        GUILayout.Space(10);
        _serializedObject.Update();
        //检查是否有修改
        EditorGUI.BeginChangeCheck();
        //显示
        EditorGUILayout.PropertyField(_assetLstProperty, true);
        //当检查结束时应用最新修改数据
        if (EditorGUI.EndChangeCheck())
        {
            _serializedObject.ApplyModifiedProperties();
        }

        if (!HasChildContent())
        {
            EditorGUILayout.HelpBox("子节点不能为空!", MessageType.Error);
        }

打开窗口可以看到,当我们没有输入数据时会有出现警告

unity 编辑器 动态创建枚举 unity自定义编辑器_xml_16


unity 编辑器 动态创建枚举 unity自定义编辑器_c#_17


unity 编辑器 动态创建枚举 unity自定义编辑器_c#_18

添加数据为空时创建文件的警告窗口

新建CreateXmlMessage.cs脚本,继承自EditorWindow,放置在Editor文件夹下

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class CreateXmlMessage : EditorWindow {

    void OnGUI()
    {
        EditorGUILayout.LabelField("XML数据不能为空");
        GUILayout.Space(100);
        if (GUILayout.Button("Close"))
        {
            this.Close();
        }
    }
}

回到CustomTool脚本,声明CheckInputData()方法,用于判断所有输入框是否都已经填入数据

/// <summary>
    /// 判断是否有数据填入
    /// </summary>
    /// <returns></returns>
    bool CheckInputData()
    {
        if (!HasChildContent() || !HasRootNameContent() || !HasXmlNameContent())
        {
            CreateXmlMessage _mesWindow = ScriptableObject.CreateInstance<CreateXmlMessage>();
            _mesWindow.position = new Rect(Screen.width / 2, Screen.height / 2, 250, 150);
            _mesWindow.ShowPopup();
            return false;
        }

        return true;
    }

再次修改OnGUI内按钮判断

if (GUILayout.Button("Create/Update XML"))
        {
            if (CheckInputData())
            {
                CreateXml(XmlName);
                if (isSaveAsset)
                {
                    SaveAsset();
                }
            }
        }

打开窗口测试,在不输入数据的情况下创建XML则会弹出提示窗口

unity 编辑器 动态创建枚举 unity自定义编辑器_unity 编辑器 动态创建枚举_19

主要工具类完整代码

CustomTool.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Xml;
using UnityEditor;
using UnityEngine;

/// <summary>
/// 子节点结构体
/// </summary>
[System.Serializable]
public struct elmNew
{
    public string childRootName;
    public string attributeId;
    public string attributeName;
    public elmChildNode[] ElmChildNode;

    /// <summary>
    /// 是否有填入数据
    /// </summary>
    public bool HasContent
    {
        get
        {
            for (int i = 0; i < ElmChildNode.Length; i++)
            {
                return childRootName.Length > 0 && attributeId.Length > 0 && attributeName.Length > 0 &&
                       ElmChildNode.Length > 0 && ElmChildNode[i].HasContent;
            }

            return childRootName.Length > 0 && attributeId.Length > 0 && attributeName.Length > 0 &&
                   ElmChildNode.Length > 0;
        }
    }
}

/// <summary>
/// 子节点下层节点结构体
/// </summary>
[System.Serializable]
public struct elmChildNode
{
    public string name;
    public string innerText;

    /// <summary>
    /// 是否有填入数据
    /// </summary>
    public bool HasContent
    {
        get { return name.Length > 0 && innerText.Length > 0; }
    }
}

public class CustomTool : EditorWindow
{
    //XML文件名称
    public string XmlName;

    //根节点名称
    public string root;

    //子节点
    [SerializeField]
    private List<elmNew> child = new List<elmNew>();

    //序列化属性
    protected SerializedProperty _assetLstProperty;
    //序列化对象
    protected SerializedObject _serializedObject;

    public Vector2 ScrollPos;

    //asset数据保存路径
    public string assetSavePath;

    //asset数据类
    public XmlAsset asset;
    private bool isSaveAsset;

    CustomTool()
    {
        //设置窗口标题
        this.titleContent = new GUIContent("XmlTool");
    }

    [MenuItem("CustomTool/XML")]
    static void showWindow()
    {
        //获取窗口,如果没有则创建一个新的
        EditorWindow.GetWindow(typeof(CustomTool));
    }

    void OnEnable()
    {
        //序列化子节点结构体
        _serializedObject = new SerializedObject(this);
        _assetLstProperty = _serializedObject.FindProperty("child");
    }

    void OnGUI()
    {
        EditorGUILayout.BeginVertical();

        ScrollPos = EditorGUILayout.BeginScrollView(ScrollPos);

        //绘制标题
        GUILayout.Space(10);
        GUILayout.Label("Create/Update Xml");

        //读取asset数据
        asset = EditorGUILayout.ObjectField("选取Xml数据", asset, typeof(XmlAsset), true) as XmlAsset;
        if (asset != null)
        {
            XmlName = asset.XmlName;
            root = asset.root;
            child = asset.child;
        }
        
        //xml的名字
        GUILayout.Space(10);
        XmlName = EditorGUILayout.TextField("XML Name", XmlName);
        if (!HasXmlNameContent())
        {
            EditorGUILayout.HelpBox("XML文件名不能为空!", MessageType.Error);
        }

        //根节点名称
        GUILayout.Space(10);
        root = EditorGUILayout.TextField("Root Name", root);
        if (!HasRootNameContent())
        {
            EditorGUILayout.HelpBox("根节点不能为空!", MessageType.Error);
        }

        //子节点信息
        GUILayout.Space(10);
        _serializedObject.Update();
        //检查是否有修改
        EditorGUI.BeginChangeCheck();
        //显示
        EditorGUILayout.PropertyField(_assetLstProperty, true);
        //当检查结束时应用最新修改数据
        if (EditorGUI.EndChangeCheck())
        {
            _serializedObject.ApplyModifiedProperties();
        }

        if (!HasChildContent())
        {
            EditorGUILayout.HelpBox("子节点不能为空!", MessageType.Error);
        }

        GUILayout.Space(10);
        isSaveAsset = GUILayout.Toggle(isSaveAsset, "是否保存数据为Asset资源");

        if (GUILayout.Button("Create/Update XML"))
        {
            if (CheckInputData())
            {
                CreateXml(XmlName);
                if (isSaveAsset)
                {
                    SaveAsset();
                }
            }
        }

        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndVertical();
    }

    /// <summary>
    /// 创建Xml文件
    /// </summary>
    /// <param name="fileName"></param>
    public void CreateXml(string fileName)
    {
        string filePath = Application.streamingAssetsPath + "/" + fileName + ".xml";

        //创建Xml文件实例
        XmlDocument xmlDoc = new XmlDocument();
        //创建root节点
        XmlElement root = xmlDoc.CreateElement(this.root);
        for (int i = 0; i < child.Count; i++)
        {
            //继续创建子节点
            XmlElement elmNew = xmlDoc.CreateElement(child[i].childRootName);
            //配置节点的两个属性
            elmNew.SetAttribute("id", child[i].attributeId);
            elmNew.SetAttribute("name", child[i].attributeName);
            //继续创建下一层节点
            for (int j = 0; j < child[i].ElmChildNode.Length; j++)
            {
                XmlElement childnode = xmlDoc.CreateElement(child[i].ElmChildNode[j].name);
                //设置节点数据
                childnode.InnerText = child[i].ElmChildNode[j].innerText;
                elmNew.AppendChild(childnode);
            }

            //把节点一层一层添加到XmlDoc里---------------->>>注意先后顺序

            root.AppendChild(elmNew);
        }

        xmlDoc.AppendChild(root);

        xmlDoc.Save(filePath);

        Debug.Log("CreateXml OK");
    }

    /// <summary>
    /// 保存Xml数据为Asset
    /// </summary>
    public void SaveAsset()
    {
        XmlAsset xmlAsset = ScriptableObject.CreateInstance<XmlAsset>();
        OpenSaveWindow("保存Xml数据", "asset文件(*.asset)\0*.asset");
        xmlAsset.XmlName = XmlName;
        xmlAsset.root = root;
        xmlAsset.child = child;
        AssetDatabase.CreateAsset(xmlAsset, "Assets/" + assetSavePath + ".asset");

    }

    /// <summary>
    /// 绝对路径转相对路径
    /// </summary>
    /// <param name="filespec"></param>
    /// <param name="folder"></param>
    /// <returns></returns>
    public static string GetRelativePath(string filespec, string folder)
    {
        const string directorySeparatorChar = "\\";
        Uri pathUri = new Uri(filespec);

        if (!folder.EndsWith(directorySeparatorChar))
        {
            folder += directorySeparatorChar;
        }
        Uri folderUri = new Uri(folder);
        return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace("/", directorySeparatorChar));
    }

    /// <summary>
    /// 开启Window保存文件窗口
    /// </summary>
    /// <param name="title"></param>
    /// <param name="_filter"></param>
    void OpenSaveWindow(string title, string _filter)
    {
        OpenFileName openFileName = new OpenFileName();
        openFileName.structSize = Marshal.SizeOf(openFileName);
        openFileName.filter = _filter;
        openFileName.file = new string(new char[256]);
        openFileName.maxFile = openFileName.file.Length;
        openFileName.fileTitle = new string(new char[64]);
        openFileName.maxFileTitle = openFileName.fileTitle.Length;
        openFileName.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//默认路径
        openFileName.title = title;
        openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;
        if (LocalDialog.GetSaveFileName(openFileName))
        {
            assetSavePath = GetRelativePath(openFileName.file, Application.dataPath);
        }
    }

    /// <summary>
    /// 判断XML名称是否为空
    /// </summary>
    /// <returns></returns>
    bool HasXmlNameContent()
    {
        return XmlName != null && XmlName.Length > 0;
    }

    /// <summary>
    /// 判断根节点是否为空
    /// </summary>
    /// <returns></returns>
    bool HasRootNameContent()
    {
        return root != null && root.Length > 0;
    }

    /// <summary>
    /// 判断子节点是否填入数据
    /// </summary>
    /// <returns></returns>
    bool HasChildContent()
    {
        if (child.Count < 0)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < child.Count; i++)
            {
                if (!child[i].HasContent)
                {
                    return false;
                }
                else if (i == child.Count - 1 && child[i].HasContent)
                {
                    return true;
                }
            }
        }

        return false;
    }

    /// <summary>
    /// 判断是否有数据填入
    /// </summary>
    /// <returns></returns>
    bool CheckInputData()
    {
        if (!HasChildContent() || !HasRootNameContent() || !HasXmlNameContent())
        {
            CreateXmlMessage _mesWindow = ScriptableObject.CreateInstance<CreateXmlMessage>();
            _mesWindow.position = new Rect(Screen.width / 2, Screen.height / 2, 250, 150);
            _mesWindow.ShowPopup();
            return false;
        }

        return true;
    }
}