using System;
using System.IO;
using System.Xml;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    /// <summary>
    /// [静态]Xml功能类。
    /// 创建时间:2011年12月26日
    /// 创建者:杨震宇
    /// 
    /// 主要内容:为XmlNode添加了几个扩展方法,以便操作Xml文件。
    /// </summary>
    public static class XmlTools
    {
        /// <summary>
        /// [扩展方法]将一串Xml格式的文本转换成XmlNode节点,并插入为此节点的子节点。
        /// 
        /// 异常:
        ///   ArgumentNullException
        /// </summary>
        /// <param name="xmlNode">调用本方法的Xml节点(本节点将成为新节点的父节点)。</param>
        /// <param name="xmlText">需要转换成新子节点的Xml文本(需要符合Xml格式)。</param>
        /// <returns>如果成功转换并插入到当前节点尾部,成为当前节点的最后一个子节点,就返回【新子节点】。失败则返回null。</returns>
        public static XmlNode AppendXmlAsChild(this XmlNode xmlNode, String xmlText)
        {

            if (xmlText == null || xmlText.Length <= 0)
                throw new ArgumentNullException("XmlNode的AppendXmlAsChild()扩展方法的“xmlText”参数值不能为null或空字符串!");

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlText);
            XmlNode newNode = xmlNode.OwnerDocument.CreateNode
                (doc.FirstChild.NodeType, doc.FirstChild.Name, doc.FirstChild.NamespaceURI);

            foreach (XmlAttribute attribute in doc.FirstChild.Attributes)
            {
                XmlAttribute newAttribute = xmlNode.OwnerDocument.CreateAttribute(attribute.Name);
                newAttribute.Value = attribute.Value;
                newNode.Attributes.Append(newAttribute);
            }

            newNode.InnerXml = doc.FirstChild.InnerXml;

            xmlNode.AppendChild(newNode);

            return newNode;
        }

        public static XmlElement AppendXmlAsChild(this XmlElement xmlElement, String xmlText)
        {

            if (xmlText == null || xmlText.Length <= 0)
                throw new ArgumentNullException("XmlNode的AppendXmlAsChild()扩展方法的“xmlText”参数值不能为null或空字符串!");

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlText);
            XmlElement newElement = xmlElement.OwnerDocument.CreateElement(doc.FirstChild.Name, doc.FirstChild.NamespaceURI);

            foreach (XmlAttribute attribute in doc.FirstChild.Attributes)
            {
                XmlAttribute newAttribute = xmlElement.OwnerDocument.CreateAttribute(attribute.Name);
                newAttribute.Value = attribute.Value;
                newElement.Attributes.Append(newAttribute);
            }

            newElement.InnerXml = doc.FirstChild.InnerXml;

            xmlElement.AppendChild(newElement);

            return newElement;
        }

        /// <summary>
        /// [扩展方法]取出当前节点XmlNode中指定名称的属性。如果指定的属性不存在,会返回null。
        /// </summary>
        /// <param name="xmlNode">要取属性的节点。</param>
        /// <param name="attributeName">要取的属性的名称。</param>
        /// <returns>返回指定名称的属性。如果不存在,返回null。</returns>
        public static XmlAttribute GetAttribute(this XmlNode xmlNode, String attributeName)
        {
            if (xmlNode == null) return null;
            if (xmlNode.Attributes == null) return null;

            XmlAttributeCollection attributes = xmlNode.Attributes;
            foreach (XmlAttribute attribute in attributes)
            {
                if (attribute.Name == attributeName)
                {
                    return attribute;
                }
            }

            return null;
        }

        /// <summary>
        /// [扩展方法]取XmlElement的属性。如果存在指定名称的属性(Attribute),
        /// 返回此属性(Attribute)。否则返回null。
        /// </summary>
        /// <param name="xmlElement">要调用本扩展方法的XmlElement元素自身。</param>
        /// <param name="attributeName">要删除的属性的名称。</param>
        /// <returns>返回属性。</returns>
        public static XmlAttribute GetAttributeByName(this XmlElement xmlElement, String attributeName)
        {
            if (xmlElement.Attributes == null) return null;

            XmlAttributeCollection attributes = xmlElement.Attributes;
            foreach (XmlAttribute attribute in attributes)
            {
                if (attribute.Name == attributeName)
                {
                    return attribute;
                }
            }

            return null;
        }

        /// <summary>
        /// [扩展方法]取出节点中指定名称的属性的文本值。如果不存在,返回null,而不是返回空字符串。
        /// </summary>
        /// <param name="xmlNode">调用本方法的XmlNode节点(取其属性值的节点)。</param>
        /// <param name="attributeName">要取值的属性的名称。</param>
        /// <returns>返回属性的值(文本值)。如果不存在该属性,返回null。</returns>
        public static String GetAttributeValueText(this XmlNode xmlNode, String attributeName)
        {
            XmlAttributeCollection attributes = xmlNode.Attributes;
            foreach (XmlAttribute attribute in attributes)
            {
                if (attribute.Name == attributeName)
                {
                    return attribute.InnerText;
                }
            }

            return null;
        }

        /// <summary>
        /// [扩展方法]取本节点的子节点列表中指定的某个子节点的索引值。
        /// 如果指定的节点不是当前节点的子节点,返回-1。
        /// 
        /// 异常:
        ///   Exception
        /// </summary>
        /// <param name="xmlNode">调用本方法的节点。</param>
        /// <param name="childNode">应为调用节点的子节点。返回值将是这个子节点的索引。</param>
        /// <returns>如果指定子节点不是调用此方法的节点的子节点,返回-1。如果找到,则返回其索引。</returns>
        public static int IndexOf(this XmlNode xmlNode, XmlNode childNode)
        {
            if (childNode == null) return -1;

            XmlNode parentNode = xmlNode;
            if (parentNode == null)
                throw new Exception("XmlNode的IndexOf()扩展方法在执行时未找到父节点。");

            int curIndex = -1;
            for (int i = 0; i < parentNode.ChildNodes.Count; i++)
            {
                XmlNode node = parentNode.ChildNodes[i];
                if (node == childNode)
                {
                    curIndex = i; break;
                }
            }

            return curIndex;
        }

        /// <summary>
        /// [扩展方法]在当前节点的子节点列表中,按指定索引插入一个新的XmlNode。
        /// 如果插入成功,返回true。
        /// 
        /// 异常:
        ///   IndexOutOfRangeException
        /// </summary>
        /// <param name="xmlNode">调用本方法的节点(新节点将成为此节点的子节点)。</param>
        /// <param name="index">新节点应插入到的位置。</param>
        /// <param name="newXmlChildNode">新子节点。</param>
        /// <returns>如果插入成功,返回true。</returns>
        public static bool InsertChildNodeAt(this XmlNode xmlNode, int index, XmlNode newXmlChildNode)
        {
            if (xmlNode.OwnerDocument == null)
                throw new Exception("节点不在文档中!");

            if (xmlNode.OwnerDocument.PreserveWhitespace)
                throw new Exception("Xml文档的“PreserveWhitespace”属性值不应为true。");

            if (index < 0)
                throw new IndexOutOfRangeException("XmlNode的InsertChildNodeAt()扩展方法的“index”参数值不能小于0!");

            if (index == 0)
            {
                if (xmlNode.FirstChild != null)
                {
                    xmlNode.InsertBefore(newXmlChildNode, xmlNode.FirstChild);
                    return true;
                }
                else
                {
                    xmlNode.AppendChild(newXmlChildNode);
                    return true;
                }
            }

            if (index == xmlNode.ChildNodes.Count)
            {
                xmlNode.AppendChild(newXmlChildNode);
                return true;
            }

            XmlNodeList childNodeList = xmlNode.ChildNodes;
            if (index > childNodeList.Count)
                throw new IndexOutOfRangeException("XmlNode的InsertChildNodeAt()扩展方法的“index”参数值不能大于子节点总数目!");

            return (xmlNode.InsertAfter(newXmlChildNode, childNodeList[index - 1]) != null);
        }

        /// <summary>
        /// [扩展方法]将提供的Xml文本转换成一个XmlNode并插入到自身的后面或前面。
        /// 新节点与当前调用本方法的节点平级。
        /// 注意:只能传入一个节点的OutXmlText,不能同时传入多个节点的。
        /// </summary>
        /// <param name="xmlNode">调用本方法的节点。(新节点将与本节点平级。)</param>
        /// <param name="xmlText">新节点的OutXmlText文本。</param>
        /// <param name="afterMe">默认为:true,表示在本节点之后;false表示在本节点之前插入。</param>
        /// <returns>如果插入成功,返回true。</returns>
        public static bool InsertXml(this XmlNode xmlNode, String xmlText, bool afterMe = true)
        {
            XmlNode parentNode = xmlNode.ParentNode;
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlText);

            XmlNode newNode = xmlNode.OwnerDocument.CreateNode
                (doc.FirstChild.NodeType, doc.FirstChild.Name, doc.FirstChild.NamespaceURI);

            foreach (XmlAttribute attribute in doc.FirstChild.Attributes)
            {
                XmlAttribute newAttribute = xmlNode.OwnerDocument.CreateAttribute(attribute.Name);
                newAttribute.Value = attribute.Value;
                newNode.Attributes.Append(newAttribute);
            }

            newNode.InnerXml = doc.FirstChild.InnerXml;

            if (afterMe)
            {
                parentNode.InsertAfter(newNode, xmlNode);
            }
            else
            {
                parentNode.InsertBefore(newNode, xmlNode);
            }

            return true;
        }

        /// <summary>
        /// [扩展方法]在指定索引处插入新的Xml节点。新节点将成为子节点。返回子节点。
        /// 
        /// 异常:
        ///   IndexOutOfRangeException
        ///   ArgumentNullException
        /// </summary>
        /// <param name="xmlNode">调用本方法的XmlNode(将成为新节点的父节点)。</param>
        /// <param name="xmlText">新子节点的OutXml文本。</param>
        /// <param name="index">新子节点应出现在父节点中哪个位置,索引值从0开始计算。</param>
        /// <returns>返回子节点。</returns>
        public static XmlNode InsertXmlAt(this XmlNode xmlNode, String xmlText, int index)
        {
            if (index < 0)
                throw new IndexOutOfRangeException("XmlNode的InsertXmlAt()扩展方法的“index”参数值不能小于0!");

            if (xmlText == null || xmlText.Length <= 0)
                throw new ArgumentNullException("XmlNode的InsertXmlAt()扩展方法的“xmlText”参数不能为null或空字符串!");

            if (index > xmlNode.ChildNodes.Count)
                throw new IndexOutOfRangeException("XmlNode的InsertXmlAt()扩展方法的“index”参数值不能大于子节点最大索引!");

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlText);

            XmlNode newNode = xmlNode.OwnerDocument.CreateNode
                (doc.FirstChild.NodeType, doc.FirstChild.Name, doc.FirstChild.NamespaceURI);

            foreach (XmlAttribute attribute in doc.FirstChild.Attributes)
            {
                XmlAttribute newAttribute = xmlNode.OwnerDocument.CreateAttribute(attribute.Name);
                newAttribute.Value = attribute.Value;
                newNode.Attributes.Append(newAttribute);
            }

            newNode.InnerXml = doc.FirstChild.InnerXml;

            if (index > 0)
            {
                XmlNode preNode = xmlNode.ChildNodes[index - 1];
                if (preNode == null) return null;

                return xmlNode.InsertAfter(newNode, preNode);
            }
            else
            {
                return xmlNode.InsertBefore(newNode, xmlNode.FirstChild);
            }
        }

        /// <summary>
        /// [静态方法]从磁盘上读取Xml文件,如果正常,返回一个XmlDocument对象。
        /// 
        /// 异常:
        ///   ArgumentNullException
        ///   FileNotFoundException
        /// </summary>
        /// <param name="fileFullPath">Xml文件在磁盘上的完整路径。</param>
        /// <returns>如果正常,返回一个XmlDocument对象。</returns>
        public static XmlDocument LoadXmlFile(string fileFullPath)
        {
            if (fileFullPath == null || fileFullPath.Length <= 0)
                throw new ArgumentNullException("XmlTools.LocaXmlFile()方法的“fileFullPath”参数值不能为null或空字符串!");

            if (System.IO.File.Exists(fileFullPath) == false)
                throw new FileNotFoundException("XmlTools.LocaXmlFile()方法未能找到文件:" + fileFullPath);

            XmlReader reader = null;

            try
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ConformanceLevel = ConformanceLevel.Document;
                settings.IgnoreWhitespace = true;
                settings.IgnoreComments = true;

                string uriStr = fileFullPath; //fileFullPath.StartsWith("file:///") ? fileFullPath : "file:///" + fileFullPath;

                reader = XmlReader.Create(uriStr, settings);

                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.RemoveAll();

                System.Xml.XmlNode node = xmlDoc.ReadNode(reader); ;

                while (node != null)
                {
                    xmlDoc.AppendChild(node);
                    node = xmlDoc.ReadNode(reader);
                }

                return xmlDoc;
            }
            finally
            {
                if (reader != null) reader.Close();
            }
        }

        /// <summary>
        /// [扩展方法]将当前节点移动到同级节点中的指定索引位置。如果当前位置即是指定位置,也返回true。
        /// 如果此节点没有父节点,则不能移动。如果指定索引值越界,也不能移动。
        /// 
        /// 异常:
        ///   Exception
        ///   IndexOutOfRangeException
        /// </summary>
        /// <param name="xmlNode">调用本方法的当前节点。</param>
        /// <param name="newIndex">当前节点的新索引。必须介于[0,同级节点数目-1]之间。</param>
        /// <returns>如果成功返回true。</returns>
        public static bool MoveTo(this XmlNode xmlNode, int newIndex)
        {
            if (newIndex < 0)
                throw new IndexOutOfRangeException("XmlNode的扩展方法MoveTo()的“newIndex”参数值不能小于零!");

            XmlNode parentNode = xmlNode.ParentNode;
            if (parentNode == null)
                throw new Exception("XmlNode的扩展方法MoveTo()在执行时未找到“parentNode”,无法继续。");

            if (newIndex >= parentNode.ChildNodes.Count)
                throw new IndexOutOfRangeException("XmlNode的扩展方法MoveTo()的“newIndex”参数值不能大于同级节点最大索引!");

            int curIndex = parentNode.IndexOf(xmlNode);

            if (curIndex < 0)
                throw new Exception("发生意外,未找到当前节点在同级节点列表中的索引。XmlNode的IndexOf()扩展方法执行错误。");

            if (newIndex < curIndex)
            {
                parentNode.RemoveChild(xmlNode);
                parentNode.InsertBefore(xmlNode, parentNode.ChildNodes[newIndex]);
                return true;
            }
            else if (newIndex > curIndex)
            {
                XmlNode baseDestNode = parentNode.ChildNodes[newIndex];
                if (baseDestNode == null)
                    throw new IndexOutOfRangeException("XmlNode的扩展方法MoveTo()执行“向后移动”时未能找到“newIndex”位置的节点!");

                parentNode.RemoveChild(xmlNode);
                parentNode.InsertAfter(xmlNode, baseDestNode);
                return true;
            }
            else return true;
        }

        /// <summary>
        /// [扩展方法]将调用本方法的节点与同级节点中的前一个节点对调位置。
        /// 如果此节点本身已经是同级节点中的首位,则不进行任何操作并返回false。
        /// 
        /// 异常:
        ///   Exception
        /// </summary>
        /// <param name="xmlNode">调用本方法的节点本身。</param>
        /// <returns>如果找不到父节点,或本身就是首节点,返回false。成功后返回true。</returns>
        public static bool MoveToPrevious(this XmlNode xmlNode)
        {
            XmlNode previousNode = xmlNode.PreviousSibling;
            if (previousNode == null) return false;

            XmlNode parentNode = xmlNode.ParentNode;
            if (parentNode == null)
                throw new Exception("XmlNode的MoveToPrevious()扩展方法在执行时未找到父节点。");

            parentNode.RemoveChild(xmlNode);
            parentNode.InsertBefore(xmlNode, previousNode);
            return true;
        }

        /// <summary>
        /// [扩展方法]将调用本方法的节点与同级节点中的后一个节点对调位置。
        /// 如果此节点本身已经是同级节点中的最后一个节点,则不进行任何操作并返回false。
        /// 
        /// 异常:
        ///   Exception
        /// </summary>
        /// <param name="xmlNode">调用本方法的节点本身。</param>
        /// <returns>如果找不到父节点,或本身就是最后一个节点,返回false。成功后返回true。</returns>
        public static bool MoveToNext(this XmlNode xmlNode)
        {
            XmlNode nextNode = xmlNode.NextSibling;
            if (nextNode == null) return false;

            XmlNode parentNode = xmlNode.ParentNode;
            if (parentNode == null)
                throw new Exception("XmlNode的MoveToNext()扩展方法在执行时未找到父节点。");

            parentNode.RemoveChild(xmlNode);
            parentNode.InsertAfter(xmlNode, nextNode);
            return true;
        }

        /// <summary>
        /// [扩展方法]删除此节点的所有子节点(node)。但不删除Attributes。
        /// </summary>
        /// <param name="xmlElement">调用此扩展方法的XmlNode实例本身。</param>
        public static void RemoveAllChildNodes(this XmlNode xmlNode)
        {
            if (xmlNode == null) return;
            if (xmlNode.ChildNodes.Count <= 0) return;

            for (int i = xmlNode.ChildNodes.Count - 1; i >= 0; i--)
            {
                xmlNode.RemoveChild(xmlNode.ChildNodes[i]);
            }
        }

        /// <summary>
        /// [扩展方法]移除指定名称的属性。
        /// </summary>
        /// <param name="xmlNode">节点。</param>
        /// <param name="attributeName">属性名。</param>
        /// <returns>是否移除成功。</returns>
        public static bool RemoveAttributeByName(this XmlNode xmlNode, string attributeName)
        {
            if (xmlNode == null) return false;
            if (xmlNode.Attributes == null) return false;

            XmlAttributeCollection attributes = xmlNode.Attributes;
            foreach (XmlAttribute attribute in attributes)
            {
                if (attribute.Name == attributeName)
                {
                    xmlNode.Attributes.Remove(attribute);
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// [扩展方法]替换当前节点的OutXmlText(此节点的所有内容:名称、特性、子节点等等均将由提供的Xml字符串所决定。
        /// 返回替换后的新节点。
        /// 
        /// 异常:
        ///   ArgumentNullException
        /// </summary>
        /// <param name="xmlNode">调用本方法的(要替换的)节点。</param>
        /// <param name="newOutXmlText">节点的新OutXml文本。</param>
        /// <returns>返回被替换后的新节点。</returns>
        public static XmlNode ReplaceOutXmlText(this XmlNode xmlNode, string xmlText)
        {
            if (xmlText == null || xmlText.Length <= 0)
                throw new ArgumentNullException("XmlNode的ReplaceOutXmlText()扩展方法的“XmlText”参数不能为null或空字符串!");

            XmlNode parentNode = xmlNode.ParentNode;
            XmlDocument doc = new XmlDocument();

            //Load方法不需要XmlHeader!!!
            //if (xmlText.StartsWith("<xml") == false)
            //{
            //    xmlText = xmlHeaderText + xmlText;
            //}

            doc.LoadXml(xmlText);

            XmlNode newNode = xmlNode.OwnerDocument.CreateNode
                (doc.FirstChild.NodeType, doc.FirstChild.Name, doc.FirstChild.NamespaceURI);

            if (doc.FirstChild.Attributes != null && doc.FirstChild.Attributes.Count > 0)
            {
                foreach (XmlAttribute attribute in doc.FirstChild.Attributes)
                {
                    XmlAttribute newAttribute = xmlNode.OwnerDocument.CreateAttribute(attribute.Name);
                    newAttribute.Value = attribute.Value;
                    newNode.Attributes.Append(newAttribute);
                }
            }

            newNode.InnerXml = doc.FirstChild.InnerXml;

            if (parentNode.ReplaceChild(newNode, xmlNode) != null)
            {
                return newNode;
            }
            else return null;
        }

        /// <summary>
        /// [静态方法]将文本中的小于号和&符转换成&lt;和&amp;以防止造成Xml格式失效。
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ReplaceXmlChars(string source)
        {
            if (source == null) return null;
            if (source.Length <= 0) return string.Empty;

            //Xml预定的转义字符有五个,只有“<”和“&”是严格禁止使用的。
            string result = source.Replace("&", "&amp;");
            result = result.Replace("<", "&lt;");
            result = result.Replace(">", "&gt;");
            result = result.Replace("'", "&apos;");
            result = result.Replace("\"", "&quot;");
            return result;
        }

        /// <summary>
        /// [静态方法]将Xml文本中的&lt;和&amp;转换回小于号和&符。
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string RestoreXmlChars(string source)
        {
            if (source == null) return null;
            if (source.Length <= 0) return string.Empty;

            //Xml预定的转义字符有五个,只有“<”和“&”是严格禁止使用的。
            string result = source.Replace("&quot;", "\"");
            result = result.Replace("&apos;", "'");
            result = result.Replace("&gt;", ">");
            result = result.Replace("&lt;", "<");
            result = result.Replace("&amp;", "&");
            return result;
        }

        /// <summary>
        /// [静态方法]将Xml序列字符串保存为一个磁盘上的Xml文件。
        /// ★注意:XmlDocument.LoadXml()方法传入的文本不需要以Xml声明文本开头!!!不必重复检查!!!
        /// 
        /// 异常:
        ///   ArgumentException
        ///   ArgumentNullException
        /// </summary>
        /// <param name="fullPathOfXmlFile">文件路径。</param>
        /// <param name="xmlString">Xml字符串。</param>
        /// <returns>返回保存后的XmlDocument对象。</returns>
        public static XmlDocument SaveToXmlFile(string fullPathOfXmlFile, string xmlString)
        {
            if (fullPathOfXmlFile == null || fullPathOfXmlFile.Length <= 0)
                throw new ArgumentNullException("XmlNode的SaveToXmlFile()扩展方法的“fullPathOfXmlFile”参数值不能为null或空字符串!");

            if (xmlString == null || xmlString.Length <= 0)
                throw new ArgumentNullException("XmlNode的SaveToXmlFile()扩展方法的“xmlString”参数值不能为null或空字符串!");

            //if (xmlString.StartsWith("<?xml") == false)
            //{
            //    xmlString = XmlTools.XmlHeaderText + xmlString;
            //}
            //LoadXml方法不需要XmlHeader。
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlString);

            string directoryString;

            int indexOfLastSeparator = fullPathOfXmlFile.LastIndexOf("\\");
            if (indexOfLastSeparator == -1)
            {
                throw new ArgumentException("XmlTools.SaveToXmlFile()方法的“fullPathOfXmlFile”参数有误,未找到目录分割符“\\”。");
            }

            directoryString = fullPathOfXmlFile.Substring(0, indexOfLastSeparator);
            if (Directory.Exists(directoryString) == false)
            {
                Directory.CreateDirectory(directoryString);
                if (Directory.Exists(directoryString) == false) return null;//未能创建目录。
            }

            doc.Save(fullPathOfXmlFile);
            return doc;
        }

        /// <summary>
        /// [扩展方法]为节点设置一个属性(Attribute)值。如果已存在该属性,则更新其值;若尚无该属性,则添加一个新属性。
        /// 
        /// 异常:
        ///   ArgumentNullException
        /// </summary>
        /// <param name="xmlNode">调用本方法(要设置属性值)的节点。</param>
        /// <param name="attributeName">属性名。不能是null或空字符串。</param>
        /// <param name="attributeValue">属性值。不能为null,但可以是空字符串。</param>
        public static void SetAttribute(this XmlNode xmlNode, string attributeName, string attributeValue)
        {
            if (attributeName == null || attributeName.Length <= 0)
                throw new ArgumentNullException("XmlNode的SetAttribute()扩展方法的“attributeName”参数值不能是null或空字符串!");

            if (attributeValue == null)
                throw new ArgumentNullException("XmlNode的SetAttribute()扩展方法的“attributeValue”参数值不能是null!");

            XmlAttributeCollection attributes = xmlNode.Attributes;
            XmlAttribute attribute = null;

            foreach (XmlAttribute a in attributes)
            {
                if (a.Name == attributeName)
                {
                    attribute = a;
                    break;
                }
            }

            if (attribute == null)
            {
                XmlAttribute newAttribute = xmlNode.OwnerDocument.CreateAttribute(attributeName);
                newAttribute.InnerText = attributeValue;
                xmlNode.Attributes.Append(newAttribute);
            }
            else
            {
                if (attribute.InnerText != attributeValue)
                {
                    attribute.InnerText = attributeValue;
                }
            }
        }

        public static void SetAttribute(this XmlElement xmlElement, string attributeName, string attributeValue)
        {
            if (attributeName == null || attributeName.Length <= 0)
                throw new ArgumentNullException("XmlElement的SetAttribute()扩展方法的“attributeName”参数值不能是null或空字符串!");

            if (attributeValue == null)
                throw new ArgumentNullException("XmlElement的SetAttribute()扩展方法的“attributeValue”参数值不能是null!");

            XmlAttributeCollection attributes = xmlElement.Attributes;
            XmlAttribute attribute = null;

            foreach (XmlAttribute a in attributes)
            {
                if (a.Name == attributeName)
                {
                    attribute = a;
                    break;
                }
            }

            if (attribute == null)
            {
                XmlAttribute newAttribute = xmlElement.OwnerDocument.CreateAttribute(attributeName);
                newAttribute.InnerText = attributeValue;
                xmlElement.Attributes.Append(newAttribute);
            }
            else
            {
                if (attribute.InnerText != attributeValue)
                {
                    attribute.InnerText = attributeValue;
                }
            }
        }

        private static readonly string xmlHeaderText = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

        /// <summary>
        /// [只读]返回Xml文件头一行声明字符串:"&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;";
        /// </summary>
        public static string XmlHeaderText { get { return xmlHeaderText; } }

    }
}