发布0101
大石头 编写于 2020-01-01 23:35:09
X
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;

namespace NewLife.Configuration
{
    /// <summary>Xml文件配置提供者</summary>
    /// <remarks>
    /// 支持从不同配置文件加载到不同配置模型
    /// </remarks>
    public class XmlConfigProvider : FileConfigProvider
    {
        /// <summary>读取配置文件,得到字典</summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        protected override IDictionary<String, String> OnRead(String fileName)
        {
            using var fs = File.OpenRead(fileName);
            using var reader = XmlReader.Create(fs);

            var dic = new Dictionary<String, Object>();

            // 移动到第一个元素
            while (reader.NodeType != XmlNodeType.Element) reader.Read();

            reader.ReadStartElement();
            while (reader.NodeType == XmlNodeType.Comment || reader.NodeType == XmlNodeType.Whitespace) reader.Skip();

            ReadNode(reader, dic);

            if (reader.NodeType == XmlNodeType.EndElement) reader.ReadEndElement();

            var rs = new Dictionary<String, String>();
            Map(dic, rs, null);

            return rs;
        }

        private void ReadNode(XmlReader reader, IDictionary<String, Object> dic)
        {
            while (true)
            {
                if (reader.NodeType != XmlNodeType.Element) break;

                var name = reader.Name;

                reader.ReadStartElement();
                while (reader.NodeType == XmlNodeType.Comment || reader.NodeType == XmlNodeType.Whitespace) reader.Skip();

                if (reader.NodeType != XmlNodeType.Element)
                    dic[name] = reader.ReadContentAsString();
                else
                {
                    var dic2 = new Dictionary<String, Object>();
                    ReadNode(reader, dic2);

                    dic[name] = dic2;
                }

                if (reader.NodeType == XmlNodeType.Attribute) reader.Read();
                if (reader.NodeType == XmlNodeType.EndElement) reader.ReadEndElement();
                while (reader.NodeType == XmlNodeType.Comment || reader.NodeType == XmlNodeType.Whitespace) reader.Skip();
            }
        }

        /// <summary>把字典写入配置文件</summary>
        /// <param name="fileName"></param>
        /// <param name="source"></param>
        protected override void OnWrite(String fileName, IDictionary<String, String> source)
        {
            var set = new XmlWriterSettings
            {
                Encoding = Encoding.UTF8,
                Indent = true
            };

            var rs = new Dictionary<String, Object>();
            Map(source, rs);

            using var fs = File.OpenWrite(fileName);
            using var writer = XmlWriter.Create(fs, set);

            writer.WriteStartDocument();
            var name = Path.GetFileNameWithoutExtension(fileName);
            WriteNode(writer, name, rs);
            writer.WriteEndDocument();

            // 截断文件
            writer.Flush();
            fs.SetLength(fs.Position);
        }

        private void WriteNode(XmlWriter writer, String name, IDictionary<String, Object> source)
        {
            writer.WriteStartElement(name);

            foreach (var item in source)
            {
                if (item.Value is IDictionary<String, Object> dic)
                    WriteNode(writer, item.Key, dic);
                else
                {
                    writer.WriteStartElement(item.Key);
                    writer.WriteValue(item.Value);
                    writer.WriteEndElement();
                }
            }

            writer.WriteEndElement();
        }
    }
}