/************************************************* * 描述: * * Author:ys * Date:2019/12/19 20:23:48 * Update: * ************************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace XMLDemo { using System; using System.Data; using System.IO; using System.Text; using System.Threading; using System.Xml; using System.Xml.Serialization; namespace HelperXML { public static class XmlHelper { #region Fields and Properties public enum XmlType { File=0, String=1 } #endregion #region Methods /// <summary> /// 創建XML文檔 /// </summary> /// <param name="name">根節點名稱</param> /// <param name="type">根節點的一個屬性值</param> /// <returns></returns> public static XmlDocument CreateXmlDocument(string name, string type) { /************************************************** * .net中調用方法:寫入文件中,則: *document = XmlOperate.CreateXmlDocument("sex", "sexy"); *document.Save("c:/bookstore.xml"); ************************************************/ XmlDocument xmlDocument; try { xmlDocument = new XmlDocument(); xmlDocument.LoadXml("<" + name + "/>"); var rootElement = xmlDocument.DocumentElement; rootElement?.SetAttribute("type", type); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } return xmlDocument; } /// <summary> /// 刪除數據 /// </summary> /// <param name="path">路徑</param> /// <param name="node">節點</param> /// <param name="attribute">屬性名,非空時刪除該節點屬性值,否則刪除節點值</param> /// <returns></returns> public static void Delete(string path, string node, string attribute) { /************************************************** * 使用示列: * XmlHelper.Delete(path, "/Node", "") * XmlHelper.Delete(path, "/Node", "Attribute") ************************************************/ try { var xmlDocument = new XmlDocument(); xmlDocument.Load(path); var selectSingleNode = xmlDocument.SelectSingleNode(node); var xmlElement = (XmlElement)selectSingleNode; if (attribute.Equals("")) selectSingleNode?.ParentNode?.RemoveChild(selectSingleNode); else xmlElement?.RemoveAttribute(attribute); xmlDocument.Save(path); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } } /// <summary> /// 讀取XML資源到DataSet中 /// </summary> /// <param name="source">XML資源,文件為路徑,否則為XML字符串</param> /// <param name="xmlType">XML資源類型</param> /// <returns>DataSet</returns> public static DataSet GetDataSet(string source, XmlType xmlType) { try { var dataSet = new DataSet(); if (xmlType == XmlType.File) { dataSet.ReadXml(source); } else { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(source); var xmlNodeReader = new XmlNodeReader(xmlDocument); dataSet.ReadXml(xmlNodeReader); } return dataSet; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 獲得xml文件中指定節點的節點數據 /// </summary> /// <returns></returns> public static string GetNodeInfoByNodeName(string path, string nodeName) { try { var xmlString = ""; var xmlDocument = new XmlDocument(); xmlDocument.Load(path); var documentElementRoot = xmlDocument.DocumentElement; var selectSingleNode = documentElementRoot?.SelectSingleNode("//" + nodeName); if (selectSingleNode != null) xmlString = selectSingleNode.InnerText; return xmlString; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 讀取XML資源中的指定節點內容 /// </summary> /// <param name="source">XML資源</param> /// <param name="xmlType">XML資源類型:文件,字符串</param> /// <param name="nodeName">節點名稱</param> /// <returns>節點內容</returns> public static string GetNodeValue(string source, XmlType xmlType, string nodeName) { var xmlDocument = new XmlDocument(); if (xmlType == XmlType.File) xmlDocument.Load(source); else xmlDocument.LoadXml(source); var documentElement = xmlDocument.DocumentElement; var selectSingleNode = documentElement?.SelectSingleNode("//" + nodeName); return selectSingleNode?.InnerText; } /// <summary> /// 讀取XML資源中的指定節點屬性的內容 /// </summary> /// <param name="source">XML資源</param> /// <param name="xmlType">XML資源類型:文件,字符串</param> /// <param name="nodeName">屬性節點名稱</param> /// <param name="attributeString"></param> /// <returns>節點內容</returns> public static string GetNodeAttributeValue(string source, XmlType xmlType, string nodeName, string attributeString) { var xmlDocument = new XmlDocument(); if (xmlType == XmlType.File) xmlDocument.Load(source); else xmlDocument.LoadXml(source); var documentElement = xmlDocument.DocumentElement; var selectSingleNode = (XmlElement)documentElement?.SelectSingleNode("//" + nodeName); //if (selectSingleNode != null) return selectSingleNode?.GetAttribute(attributeString); } /// <summary> /// 讀取XML資源中的指定節點內容 /// </summary> /// <param name="source">XML資源</param> /// <param name="nodeName">節點名稱</param> /// <returns>節點內容</returns> public static string GetNodeValue(string source, string nodeName) { if (source == null || nodeName == null || source == "" || nodeName == "" || source.Length < nodeName.Length * 2) return null; var start = source.IndexOf("<" + nodeName + ">", StringComparison.Ordinal) + nodeName.Length + 2; var end = source.IndexOf("</" + nodeName + ">", StringComparison.Ordinal); if (start == -1 || end == -1) return null; return start >= end ? null : source.Substring(start, end - start); } /// <summary> /// 讀取XML資源到DataTable中 /// </summary> /// <param name="source">XML資源,文件為路徑,否則為XML字符串</param> /// <param name="xmlType">XML資源類型:文件,字符串</param> /// <param name="tableName">表名稱</param> /// <returns>DataTable</returns> public static DataTable GetTable(string source, XmlType xmlType, string tableName) { try { var dataSet = new DataSet(); if (xmlType == XmlType.File) { dataSet.ReadXml(source); } else { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(source); var xmlNodeReader = new XmlNodeReader(xmlDocument); dataSet.ReadXml(xmlNodeReader); } return dataSet.Tables[tableName]; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 讀取XML資源中指定的DataTable的指定行指定列的值 /// </summary> /// <param name="source">XML資源</param> /// <param name="xmlType">XML資源類型:文件,字符串</param> /// <param name="tableName">表名</param> /// <param name="rowIndex">行號</param> /// <param name="colName">列名</param> /// <returns>值,不存在時返回Null</returns> public static object GetTableCell(string source, XmlType xmlType, string tableName, int rowIndex, string colName) { try { var dataSet = new DataSet(); if (xmlType == XmlType.File) { dataSet.ReadXml(source); } else { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(source); var xmlNodeReader = new XmlNodeReader(xmlDocument); dataSet.ReadXml(xmlNodeReader); } return dataSet.Tables[tableName].Rows[rowIndex][colName]; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 讀取XML資源中指定的DataTable的指定行指定列的值 /// </summary> /// <param name="source">XML資源</param> /// <param name="xmlType">XML資源類型:文件,字符串</param> /// <param name="tableName">表名</param> /// <param name="rowIndex">行號</param> /// <param name="colIndex">列號</param> /// <returns>值,不存在時返回Null</returns> public static object GetTableCell(string source, XmlType xmlType, string tableName, int rowIndex, int colIndex) { try { var dataSet = new DataSet(); if (xmlType == XmlType.File) { dataSet.ReadXml(source); } else { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(source); var xmlNodeReader = new XmlNodeReader(xmlDocument); dataSet.ReadXml(xmlNodeReader); } return dataSet.Tables[tableName].Rows[rowIndex][colIndex]; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 獲取一個字符串xml文檔中的dataSet /// </summary> /// <param name="xmlString">含有xml信息的字符串</param> /// <param name="dataSet"></param> public static void GetXmlValueDataSet(string xmlString, ref DataSet dataSet) { try { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xmlString); var xmlNodeReader = new XmlNodeReader(xmlDocument); dataSet.ReadXml(xmlNodeReader); xmlNodeReader.Close(); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } } /// <summary> /// 插入數據 /// </summary> /// <param name="path">路徑</param> /// <param name="node">節點</param> /// <param name="element">元素名,非空時插入新元素,否則在該元素中插入屬性</param> /// <param name="attribute">屬性名,非空時插入該元素屬性值,否則插入元素值</param> /// <param name="value">值</param> /// <returns></returns> public static void Insert(string path, string node, string element, string attribute, string value) { /************************************************** * 使用示列: * XmlHelper.Insert(path, "/Node", "Element", "", "Value") * XmlHelper.Insert(path, "/Node", "Element", "Attribute", "Value") * XmlHelper.Insert(path, "/Node", "", "Attribute", "Value") ************************************************/ try { var xmlDocument = new XmlDocument(); xmlDocument.Load(path); var selectSingleNode = xmlDocument.SelectSingleNode(node); if (element.Equals("")) { if (!attribute.Equals("")) { var xmlElement = (XmlElement)selectSingleNode; xmlElement?.SetAttribute(attribute, value); } } else { var xmlElement = xmlDocument.CreateElement(element); if (attribute.Equals("")) xmlElement.InnerText = value; else xmlElement.SetAttribute(attribute, value); selectSingleNode?.AppendChild(xmlElement); } xmlDocument.Save(path); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } } /// <summary> /// 讀取數據 /// </summary> /// <param name="path">路徑</param> /// <param name="node">節點</param> /// <param name="attribute">屬性名,非空時返回該屬性值,否則返回串聯值</param> /// <returns>string</returns> public static string Read(string path, string node, string attribute) { /************************************************** * 使用示列: * XmlHelper.Read(path, "/Node", "") * XmlHelper.Read(path, "/Node/Element[@Attribute='Name']", "Attribute") ************************************************/ var value = ""; try { var xmlDocument = new XmlDocument(); xmlDocument.Load(path); var selectSingleNode = xmlDocument.SelectSingleNode(node); value = attribute.Equals("") ? selectSingleNode?.InnerText : selectSingleNode?.Attributes?[attribute].Value; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } return value; } /// <summary> /// 讀取xml的節點 /// </summary> /// <param name="path">路徑</param> /// <param name="nodeName">節點名稱</param> /// <param name="name">屬性名稱</param> /// <returns></returns> public static string ReadXml(string path, string nodeName, string name) //讀取XML { try { var xmlValue = ""; if (!File.Exists(path)) return xmlValue; var myFile = new FileStream(path, FileMode.Open); //打開xml文件 var xmlTextReader = new XmlTextReader(myFile); //xml文件閱讀器 while (xmlTextReader.Read()) if (xmlTextReader.Name == nodeName) { //獲取服務器的地址//獲取升級文檔的最后一次更新日期 xmlValue = xmlTextReader.GetAttribute(name); break; } xmlTextReader.Close(); myFile.Close(); return xmlValue; } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 讀取xml文件,並將文件序列化為類 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="path"></param> /// <returns></returns> public static T ReadXML<T>(string path) { try { var reader = new XmlSerializer(typeof(T)); var file = new StreamReader(path); return (T)reader.Deserialize(file); } catch (Exception exception) { // LogHelper.LogError("Error! ", exception); return default(T); } } /// <summary> /// 將DataTable寫入XML文件中 /// </summary> /// <param name="dataTable">含有數據的DataTable</param> /// <param name="filePath">文件路徑</param> public static void SaveTableToFile(DataTable dataTable, string filePath) { try { var dataSet = new DataSet("Config"); dataSet.Tables.Add(dataTable.Copy()); dataSet.WriteXml(filePath); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } } /// <summary> /// 將DataTable以指定的根結點名稱寫入文件 /// </summary> /// <param name="dataTable">含有數據的DataTable</param> /// <param name="rootName">根結點名稱</param> /// <param name="filePath">文件路徑</param> public static void SaveTableToFile(DataTable dataTable, string rootName, string filePath) { try { var dataSet = new DataSet(rootName); dataSet.Tables.Add(dataTable.Copy()); dataSet.WriteXml(filePath); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } } /// <summary> /// 靜態擴展 /// </summary> /// <typeparam name="T">需要序列化的對象類型,必須聲明[Serializable]特征</typeparam> /// <param name="obj">需要序列化的對象</param> /// <param name="omitXmlDeclaration">true:省略XML聲明;否則為false.默認false,即編寫 XML 聲明。</param> /// <returns></returns> public static string SerializeToXmlStr<T>(T obj, bool omitXmlDeclaration) { try { return XmlSerialize(obj, omitXmlDeclaration); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); return null; } } /// <summary> /// 修改數據 /// </summary> /// <param name="path">路徑</param> /// <param name="node">節點</param> /// <param name="attribute">屬性名,非空時修改該節點屬性值,否則修改節點值</param> /// <param name="value">值</param> /// <returns></returns> public static void Update(string path, string node, string attribute, string value) { /************************************************** * 使用示列: * XmlHelper.Insert(path, "/Node", "", "Value") * XmlHelper.Insert(path, "/Node", "Attribute", "Value") ************************************************/ try { var xmlDocument = new XmlDocument(); xmlDocument.Load(path); var selectSingleNode = xmlDocument.SelectSingleNode(node); var xmlElement = (XmlElement)selectSingleNode; if (attribute.Equals("")) { if (xmlElement != null) xmlElement.InnerText = value; } else { xmlElement?.SetAttribute(attribute, value); } xmlDocument.Save(path); } catch (Exception exception) { //LogHelper.LogError("Error! ", exception); } } /// <summary> /// 更新XML文件中的指定節點內容 /// </summary> /// <param name="filePath">文件路徑</param> /// <param name="nodeName">節點名稱</param> /// <param name="nodeValue">更新內容</param> /// <returns>更新是否成功</returns> public static bool UpdateNode(string filePath, string nodeName, string nodeValue) { bool flag; var xmlDocument = new XmlDocument(); xmlDocument.Load(filePath); var documentElement = xmlDocument.DocumentElement; var selectSingleNode = documentElement?.SelectSingleNode("//" + nodeName); if (selectSingleNode != null) { selectSingleNode.InnerText = nodeValue; flag = true; } else { flag = false; } return flag; } /// <summary> /// 使用DataSet方式更新XML文件節點 /// </summary> /// <param name="filePath">XML文件路徑</param> /// <param name="tableName">表名稱</param> /// <param name="rowIndex">行號</param> /// <param name="colName">列名</param> /// <param name="content">更新值</param> /// <returns>更新是否成功</returns> public static bool UpdateTableCell(string filePath, string tableName, int rowIndex, string colName, string content) { bool flag; var dataSet = new DataSet(); dataSet.ReadXml(filePath); var dataTable = dataSet.Tables[tableName]; if (dataTable.Rows[rowIndex][colName] != null) { dataTable.Rows[rowIndex][colName] = content; dataSet.WriteXml(filePath); flag = true; } else { flag = false; } return flag; } /// <summary> /// 使用DataSet方式更新XML文件節點 /// </summary> /// <param name="filePath">XML文件路徑</param> /// <param name="tableName">表名稱</param> /// <param name="rowIndex">行號</param> /// <param name="colIndex">列號</param> /// <param name="content">更新值</param> /// <returns>更新是否成功</returns> public static bool UpdateTableCell(string filePath, string tableName, int rowIndex, int colIndex, string content) { bool flag; var dataSet = new DataSet(); dataSet.ReadXml(filePath); var dataTable = dataSet.Tables[tableName]; if (dataTable.Rows[rowIndex][colIndex] != null) { dataTable.Rows[rowIndex][colIndex] = content; dataSet.WriteXml(filePath); flag = true; } else { flag = false; } return flag; } /// <summary> /// 將對象寫入XML文件 /// </summary> /// <typeparam name="T">C#對象名</typeparam> /// <param name="item">對象實例</param> /// <param name="path">路徑</param> /// <param name="jjdbh">標號</param> /// <param name="ends">結束符號(整個xml的路徑類似如下:C:\xmltest\201111send.xml,其中path=C:\xmltest,jjdbh=201111,ends=send)</param> /// <returns></returns> public static string WriteXML<T>(T item, string path, string jjdbh, string ends) { if (string.IsNullOrEmpty(ends)) ends = "send"; var i = 0; //控制寫入文件的次數, var serializer = new XmlSerializer(item.GetType()); object[] obj = { path, "\\", jjdbh, ends, ".xml" }; var xmlPath = string.Concat(obj); while (true) try { var fileStream = File.Create(xmlPath); //用filestream方式創建文件不會出現“文件正在占用中,用File.create”則不行 fileStream.Close(); TextWriter writer = new StreamWriter(xmlPath, false, Encoding.UTF8); var xmlSerializerNamespaces = new XmlSerializerNamespaces(); xmlSerializerNamespaces.Add(string.Empty, string.Empty); serializer.Serialize(writer, item, xmlSerializerNamespaces); writer.Flush(); writer.Close(); break; } catch (Exception exception) { if (i < 5) i++; else { //LogHelper.LogError("Error! ", exception); break; } } return SerializeToXmlStr(item, true); } /// <summary> /// 使用XmlSerializer反序列化對象 /// </summary> /// <param name="xmlOfObject">需要反序列化的xml字符串</param> /// <returns>反序列化后的對象</returns> public static T XmlDeserialize<T>(string xmlOfObject) where T : class { var xmlReader = XmlReader.Create(new StringReader(xmlOfObject), new XmlReaderSettings()); return (T)new XmlSerializer(typeof(T)).Deserialize(xmlReader); } /// <summary> /// 從文件讀取並反序列化為對象 (解決: 多線程或多進程下讀寫並發問題) /// </summary> /// <typeparam name="T">返回的對象類型</typeparam> /// <param name="path">文件地址</param> /// <returns></returns> public static T XmlFileDeserialize<T>(string path) { var bytes = ShareReadFile(path); if (bytes.Length < 1) //當文件正在被寫入數據時,可能讀出為0 for (var i = 0; i < 5; i++) { bytes = ShareReadFile(path); //5次機會,采用這樣詭異的做法避免獨占文件和文件正在被寫入時讀出來的數據為0字節的問題。 if (bytes.Length > 0) break; Thread.Sleep(50); //悲觀情況下總共最多消耗1/4秒,讀取文件 } var xmlDocument = new XmlDocument(); xmlDocument.Load(new MemoryStream(bytes)); if (xmlDocument.DocumentElement != null) return (T)new XmlSerializer(typeof(T)).Deserialize(new XmlNodeReader(xmlDocument.DocumentElement)); return default(T); /*var xmlReaderSettings = new XmlReaderSettings(); xmlReaderSettings.CloseInput = true; using (var xmlReader = XmlReader.Create(path, xmlReaderSettings)) { var obj = (T) new XmlSerializer(typeof(T)).Deserialize(xmlReader); return obj; }*/ } /// <summary> /// 使用XmlSerializer序列化對象 /// </summary> /// <typeparam name="T">需要序列化的對象類型,必須聲明[Serializable]特征</typeparam> /// <param name="obj">需要序列化的對象</param> /// <param name="omitXmlDeclaration">true:省略XML聲明;否則為false.默認false,即編寫 XML 聲明。</param> /// <returns>序列化后的字符串</returns> public static string XmlSerialize<T>(T obj, bool omitXmlDeclaration) { /* This property only applies to XmlWriter instances that output text content to a stream; otherwise, this setting is ignored. 可能很多朋友遇見過 不能轉換成Xml不能反序列化成為UTF8XML聲明的情況,就是這個原因。 */ var xmlSettings = new XmlWriterSettings { OmitXmlDeclaration = omitXmlDeclaration, Encoding = new UTF8Encoding(false) }; var stream = new MemoryStream(); //var writer = new StringWriter(); var xmlwriter = XmlWriter.Create(stream /*writer*/, xmlSettings); //這里如果直接寫成:Encoding = Encoding.UTF8 會在生成的xml中加入BOM(Byte-order Mark) 信息(Unicode 字節順序標記) , 所以new System.Text.UTF8Encoding(false)是最佳方式,省得再做替換的麻煩 var xmlSerializerNamespaces = new XmlSerializerNamespaces(); xmlSerializerNamespaces.Add(string.Empty, string.Empty); //在XML序列化時去除默認命名空間xmlns:xsd和xmlns:xsi var xmlSerializer = new XmlSerializer(typeof(T)); xmlSerializer.Serialize(xmlwriter, obj, xmlSerializerNamespaces); return Encoding.UTF8.GetString(stream.ToArray()); //writer.ToString(); } /// <summary> /// 使用XmlSerializer序列化對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="path">文件路徑</param> /// <param name="obj">需要序列化的對象</param> /// <param name="omitXmlDeclaration">true:省略XML聲明;否則為false.默認false,即編寫 XML 聲明。</param> /// <param name="removeDefaultNamespace">是否移除默認名稱空間(如果對象定義時指定了:XmlRoot(Namespace = "http://www.xxx.com/xsd")則需要傳false值進來)</param> /// <returns>序列化后的字符串</returns> public static void XmlSerialize<T>(string path, T obj, bool omitXmlDeclaration, bool removeDefaultNamespace) { var xmlWriterSettings = new XmlWriterSettings { OmitXmlDeclaration = omitXmlDeclaration }; using (var xmlWriter = XmlWriter.Create(path, xmlWriterSettings)) { var xmlSerializerNamespaces = new XmlSerializerNamespaces(); if (removeDefaultNamespace) xmlSerializerNamespaces.Add(string.Empty, string.Empty); //在XML序列化時去除默認命名空間xmlns:xsd和xmlns:xsi var xmlSerializer = new XmlSerializer(typeof(T)); xmlSerializer.Serialize(xmlWriter, obj, xmlSerializerNamespaces); } } private static byte[] ShareReadFile(string filePath) { byte[] bytes; //避免"正由另一進程使用,因此該進程無法訪問此文件"造成異常 共享鎖 flieShare必須為ReadWrite,但是如果文件不存在的話,還是會出現異常,所以這里不能吃掉任何異常,但是需要考慮到這些問題 using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { bytes = new byte[fileStream.Length]; var numBytesToRead = (int)fileStream.Length; var numBytesRead = 0; while (numBytesToRead > 0) { var bytesRead = fileStream.Read(bytes, numBytesRead, numBytesToRead); if (bytesRead == 0) break; numBytesRead += bytesRead; numBytesToRead -= bytesRead; } } return bytes; } #endregion } } }
