trim HttpHeaders
石头 编写于 2024-06-22 08:55:23
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using NewLife.Reflection;
using NewLife.Serialization;

namespace NewLife.Xml
{
    /// <summary>Xml读取器</summary>
    public class XmlReaderX : TextReaderBase<XmlReaderWriterSettings>
    {
        #region 属性
        private XmlReader _Reader;
        /// <summary>读取器</summary>
        public XmlReader Reader
        {
            get
            {
                if (_Reader == null)
                {
                    //var settings = new XmlReaderSettings();
                    //settings.IgnoreWhitespace = true;
                    //settings.IgnoreComments = true;
                    //_Reader = XmlReader.Create(Stream, settings);
                    // 使用XmlReader.Create会导致读取字符串时\r\n变成\n
                    var xr = new XmlTextReader(Stream);
                    xr.WhitespaceHandling = WhitespaceHandling.Significant;
                    _Reader = xr;
                }
                return _Reader;
            }
            set
            {
                _Reader = value;

                var xr = _Reader as XmlTextReader;
                if (xr != null && Settings.Encoding != xr.Encoding) Settings.Encoding = xr.Encoding;
            }
        }

        /// <summary>数据流。更改数据流后,重置Reader为空,以使用新的数据流</summary>
        public override Stream Stream
        {
            get { return base.Stream; }
            set
            {
                if (base.Stream != value) _Reader = null;
                base.Stream = value;
            }
        }

        /// <summary>获取一个值,该值表示当前的流位置是否在流的末尾。</summary>
        /// <returns>如果当前的流位置在流的末尾,则为 true;否则为 false。</returns>
        public override bool EndOfStream
        {
            get
            {
                var r = Reader;
                if (r != null) return r.EOF;

                var s = Stream;
                if (s != null) return s.Position == s.Length;

                return false;
            }
        }

        /// <summary>初始化</summary>
        public XmlReaderX() { }

        /// <summary>使用xml字符串初始化</summary>
        /// <param name="xml"></param>
        public XmlReaderX(String xml)
        {
            Stream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
        }

        private String _RootName;
        /// <summary>根元素名</summary>
        public String RootName { get { return _RootName; } set { _RootName = value; } }

        private String _Lengths;
        /// <summary>多维数组长度</summary>
        public String Lengths { get { return _Lengths; } set { _Lengths = value; } }
        #endregion

        #region 基础元数据
        /// <summary>从当前流中读取一个字符串。字符串有长度前缀,一次 7 位地被编码为整数。</summary>
        /// <returns></returns>
        public override String ReadString()
        {
            var isElement = Reader.NodeType == XmlNodeType.Element;
            if (isElement)
            {
                if (SkipEmpty()) return null;
                Reader.ReadStartElement();
            }

            String str;
            // 字符串可能以字符数组的形式存在
            if (Reader.NodeType == XmlNodeType.Element && Reader.Name.EqualIgnoreCase("char"))
            {
                var sb = new StringBuilder();
                while (Reader.NodeType == XmlNodeType.Element && Reader.Name.EqualIgnoreCase("char"))
                {
                    Reader.ReadStartElement();
                    var s = Reader.ReadContentAsString();
                    sb.Append((Char)Int32.Parse(s));
                    Reader.ReadEndElement();
                }
                str = sb.ToString();
            }
            else
                str = Reader.ReadContentAsString();

            if (isElement && Reader.NodeType == XmlNodeType.EndElement) Reader.ReadEndElement();

            WriteLog(1, "ReadString", str);
            return str;
        }

        /// <summary>从当前流中读取 count 个字符,以字符数组的形式返回数据,并根据所使用的 Encoding 和从流中读取的特定字符,提升当前位置。</summary>
        /// <param name="count">要读取的字符数。</param>
        /// <returns></returns>
        public override char[] ReadChars(int count)
        {
            var str = ReadString();
            if (str == null) return null;

            return str.ToCharArray();
        }

        /// <summary>从当前流中读取下一个字符,并根据所使用的 Encoding 和从流中读取的特定字符,提升流的当前位置。</summary>
        /// <returns></returns>
        public override Char ReadChar() { return (Char)Byte.Parse(ReadString()); }

        /// <summary>读取一个时间日期</summary>
        /// <returns></returns>
        public override DateTime ReadDateTime() { return XmlConvert.ToDateTime(ReadString(), Settings.DateTimeMode); }

        /// <summary>尝试读取值类型数据,返回是否读取成功</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <returns></returns>
        public override bool ReadValue(Type type, ref object value)
        {
            if (type == null)
            {
                if (value == null) return false;
                type = value.GetType();
            }

            var code = Type.GetTypeCode(type);
            // XmlConvert特殊处理时间,输出Char时按字符输出,不同于Xml序列化的数字,所以忽略
            if (code != TypeCode.Char && code != TypeCode.String && code != TypeCode.DateTime)
            {
                // XmlConvert也支持这三种值类型
                if (type.CanXmlConvert())
                {
                    var xml = ReadString();
                    value = XmlHelper.XmlConvertFromString(type, xml);
                    return true;
                }
            }

            return base.ReadValue(type, ref value);
        }
        #endregion

        #region 扩展类型
        /// <summary>读对象类型</summary>
        /// <returns></returns>
        protected override Type OnReadType()
        {
            if (Reader.MoveToAttribute("Type"))
            {
                var t = base.OnReadType();
                if (Reader.NodeType == XmlNodeType.Attribute) Reader.MoveToElement();
                return t;
            }

            return base.OnReadType();
        }
        #endregion

        #region 字典
        /// <summary>尝试读取字典类型对象</summary>
        /// <param name="type">类型</param>
        /// <param name="value">对象</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        public override bool ReadDictionary(Type type, ref object value, ReadObjectCallback callback)
        {
            if (SkipEmpty()) return true;

            return base.ReadDictionary(type, ref value, callback);
        }

        /// <summary>读取字典项</summary>
        /// <param name="keyType">键类型</param>
        /// <param name="valueType">值类型</param>
        /// <param name="value">字典项</param>
        /// <param name="index">元素序号</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        protected override bool ReadDictionaryEntry(Type keyType, Type valueType, ref DictionaryEntry value, Int32 index, ReadObjectCallback callback)
        {
            if (Reader.NodeType == XmlNodeType.EndElement) return false;

            Object key = null;
            Object val = null;

            // <Item>
            Reader.ReadStartElement();

            // <Key>
            Reader.ReadStartElement();
            if (!ReadObject(keyType, ref key)) return false;
            // </Key>
            if (Reader.NodeType == XmlNodeType.EndElement) Reader.ReadEndElement();

            // <Value>
            if (!ReadObject(valueType, ref val)) return false;
            // </Value>

            value.Key = key;
            value.Value = val;

            // </Item>
            if (Reader.NodeType == XmlNodeType.EndElement) Reader.ReadEndElement();

            return true;
        }
        #endregion

        #region 枚举
        /// <summary>尝试读取枚举</summary>
        /// <remarks>重点和难点在于如果得知枚举元素类型,这里假设所有元素类型一致,否则实在无法处理</remarks>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        public override bool ReadEnumerable(Type type, ref object value, ReadObjectCallback callback)
        {
            Type t = type.GetElementType();

            #region 锯齿二维数组处理
            Int32 length = 1;
            while (typeof(IEnumerable).IsAssignableFrom(t))
            {
                length++;
                t = t.GetElementType();
            }

            if (length > 1)
            {
                Array array = type.CreateInstance(length) as Array;
                t = type.GetElementType();
                for (int j = 0; j < length - 1; j++)
                {
                    //开始循环之前已赋值,所以第一次循环时跳过
                    if (j > 0) t = t.GetElementType();

                    for (int i = 0; i < array.Length; i++)
                    {
                        if (value != null) value = null;
                        if (base.ReadEnumerable(t, ref value, callback) && value != null)
                        {
                            array.SetValue(value, i);
                        }
                    }
                }
                if (array != null && array.Length > 0) value = array;
                return true;
            }
            #endregion

            return base.ReadEnumerable(type, ref value, callback);
        }

        /// <summary>读取枚举项</summary>
        /// <param name="type">类型</param>
        /// <param name="value">数值</param>
        /// <param name="index">元素序号</param>
        /// <param name="callback">处理元素的方法</param>
        /// <returns></returns>
        protected override bool ReadItem(Type type, ref object value, Int32 index, ReadObjectCallback callback)
        {
            String name = type.GetCustomAttributeValue<XmlRootAttribute, String>(true);
            if (String.IsNullOrEmpty(name) && type != null) name = type.Name;

            if (Reader.NodeType == XmlNodeType.EndElement || Reader.Name != name) return false;

            Boolean rs = base.ReadItem(type, ref value, index, callback);

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

            return rs;
        }
        #endregion

        #region 读取对象
        /// <summary>尝试读取目标对象指定成员的值,通过委托方法递归处理成员</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        protected override bool OnReadObject(Type type, ref object value, ReadObjectCallback callback)
        {
            if (Depth > 1) return base.OnReadObject(type, ref value, callback);

            while (Reader.NodeType != XmlNodeType.Element) { if (!Reader.Read())return false; }
            if (String.IsNullOrEmpty(RootName)) RootName = Reader.Name;

            return base.OnReadObject(type, ref value, callback);
        }

        /// <summary>尝试读取引用对象</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        protected override bool ReadRefObject(Type type, ref object value, ReadObjectCallback callback)
        {
            Boolean isElement = Reader.NodeType == XmlNodeType.Element;
            Boolean isAtt = Settings.MemberAsAttribute && XmlWriterX.IsAttributeType(type);
            if (isElement && !isAtt)
            {
                if (SkipEmpty()) return true;
                if (Reader.MoveToAttribute("Lengths"))
                {
                    WriteLog("ReadLengths");
                    Lengths = ReadString();
                    if (Reader.NodeType == XmlNodeType.Attribute) Reader.MoveToElement();
                }
                Reader.ReadStartElement();
            }

            Boolean b = base.ReadRefObject(type, ref value, callback);

            if (isElement && !isAtt && Reader.NodeType == XmlNodeType.EndElement) Reader.ReadEndElement();

            return b;
        }

        /// <summary>读取成员之前获取要读取的成员,默认是index处的成员,实现者可以重载,改变当前要读取的成员,如果当前成员不在数组里面,则实现者自己跳到下一个可读成员。</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="members">可匹配成员数组</param>
        /// <param name="index">索引</param>
        /// <returns></returns>
        protected override IObjectMemberInfo GetMemberBeforeRead(Type type, object value, IObjectMemberInfo[] members, int index)
        {
            String name = String.Empty;

            while (Reader.NodeType != XmlNodeType.None && Reader.IsStartElement())
            {
                name = Reader.Name;

                IObjectMemberInfo member = GetMemberByName(members, name);
                if (member != null) return member;

                if (SkipEmpty()) continue;

                Reader.ReadStartElement();

                if (!SkipEmpty()) Reader.Read();

                if (Reader.NodeType == XmlNodeType.EndElement) Reader.ReadEndElement();
            }

            return null;
        }

        /// <summary>读取对象成员</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="member">成员</param>
        /// <param name="index">成员索引</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        protected override bool OnReadMember(Type type, ref object value, IObjectMemberInfo member, Int32 index, ReadObjectCallback callback)
        {
            Boolean isAtt = Settings.MemberAsAttribute && XmlWriterX.IsAttributeType(member.Type);
            if (isAtt) Reader.MoveToAttribute(member.Name);

            return base.OnReadMember(type, ref value, member, index, callback);
        }

        /// <summary>读取对象引用计数</summary>
        /// <returns></returns>
        protected override int OnReadObjRefIndex()
        {
            if (Reader.MoveToAttribute("ObjRef"))
            {
                Int32 rs = ReadInt32();

                // 从特性移到元素,方便后续读取操作,如果后续还需要读取特性,则应该自己移到特性处
                if (Reader.NodeType == XmlNodeType.Attribute) Reader.MoveToElement();

                // 跳过空元素,可能该元素已经读取了对象引用
                SkipEmpty();

                return rs;
            }

            return -1;
        }
        #endregion

        #region 未知对象
        /// <summary>读取未知对象(其它所有方法都无法识别的对象),采用BinaryFormatter或者XmlSerialization</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        public override bool ReadUnKnown(Type type, ref object value, ReadObjectCallback callback)
        {
            try
            {
                WriteLog("XmlSerializer", type.Name);
                //XmlSerializer serializer = new XmlSerializer(type);
                //String str = Reader.ReadString();
                //if (!String.IsNullOrEmpty(str))
                //{
                //    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(str));
                //    value = serializer.Deserialize(ms);
                //}
                value = Reader.ReadString().ToXmlEntity(type);
                return true;
            }
            catch
            {
                //只能处理公共类型,Type因其保护级别而不可访问。
            }
            return base.ReadUnKnown(type, ref value, callback);
        }
        #endregion

        #region 方法
        /// <summary>当前节点是否空。如果是空节点,则读一次,让指针移到下一个元素</summary>
        Boolean SkipEmpty()
        {
            // 空元素直接返回
            if (Reader.IsEmptyElement)
            {
                // 读一次,把指针移到下一个元素上
                Reader.Read();
                return true;
            }

            return false;
        }

        /// <summary>读取多维数组相关参数</summary>
        /// <returns></returns>
        protected override string ReadLengths() { return Lengths; }

        /// <summary>备份当前环境,用于临时切换数据流等</summary>
        /// <returns>本次备份项集合</returns>
        public override IDictionary<String, Object> Backup()
        {
            var dic = base.Backup();
            dic["Reader"] = Reader;

            return dic;
        }

        /// <summary>恢复最近一次备份</summary>
        /// <returns>本次还原项集合</returns>
        public override IDictionary<String, Object> Restore()
        {
            var dic = base.Restore();
            Reader = dic["Reader"] as XmlReader;

            return dic;
        }
        #endregion

        #region 序列化接口
        /// <summary>读取实现了可序列化接口的对象</summary>
        /// <param name="type">要读取的对象类型</param>
        /// <param name="value">要读取的对象</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否读取成功</returns>
        public override bool ReadSerializable(Type type, ref object value, ReadObjectCallback callback)
        {
            if (!typeof(IXmlSerializable).IsAssignableFrom(type))
                return base.ReadSerializable(type, ref value, callback);

            if (value == null) value = type.CreateInstance();
            ((IXmlSerializable)value).ReadXml(Reader);
            return true;
        }
        #endregion
    }
}