硬件管理平台-硬件网关-XML相关基础类
硬件管理平台-硬件网关-XML相关基础类
简介
本章是硬件管理平台-硬件网关-插件模块-集成(上)的延申部分,因集成模块时还需要有配置文件的相关操作,因此需要将xml部分进行说明,其中需要说明的部分有xml的操作类、xml与硬件的交互类以及配置文件中对于xml的获取及操作。主要工作是约定xml的格式,遵照这个约定我们进行操作,通过网关配置程序将现场的硬件设备进行初始化,并使用xml进行保存,网关服务通过xml配置文件获得相关的硬件并保存在内存中,当上位机调用时,我们通过传入的设备主键以及设备类型能定位到特定的硬件并调用它。
约定
我们约定保存硬件数据的xml的版本为1.0,编码方式为utf-8
-
保存硬件的xml:
HardwareInfo.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <root> <HardwareInfos> <HardwareInfo></HardwareInfo> </HardwareInfos> </root>
最顶层为root标签,然后就是所有硬件的父级标签
,每个HardwareInfo表示一个硬件。 -
保存产品库中配置的硬件信息:FunctionSetting.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <root> <Functions> <Function 功能="报警" cron="0 */10 * * * ?" /> <Function 功能="获取温湿度" cron="0 0 * * * ?" /> <Function 功能="心跳" cron="0 30 */2 * * ?" /> <Function 功能="漏水报警" cron="0 */10 * * * ?" /> </Functions> <TypeFunctions> <TypeFunction 主键="中控-报警" 类型="中控" 功能="报警" cron="0 * * * * ?" /> </TypeFunctions> <HardwareLinks /> <DeviceTypes> <DeviceType 主键="1001" 名称="温湿度传感器" /> <DeviceType 主键="1002" 名称="漏水传感器" /> <DeviceType 主键="1003" 名称="声光报警器" /> <DeviceType 主键="1005" 名称="空气质量传感器" /> <DeviceType 主键="12" 名称="RID手持终端" /> <DeviceType 主键="13" 名称="RFID工作台" /> <DeviceType 主键="11" 名称="RFID盘点车" /> <DeviceType 主键="1004" 名称="红外双鉴传感器" /> </DeviceTypes> </root>
Functions:公共定时任务的Cron
TypeFunctions:按照类型分的定时任务的Cron
DeviceTypes:不需要控制的设备类型
说明:xml会在定时任务模块中展开说明
XML帮助类
我们在公共包中创建一个xml的操作类,该类主要的作用是便于操作xml,并命名为XmlHelper.cs
/// <summary>
/// Xml的操作公共类
/// </summary>
public class XmlHelper
{
#region 字段定义
/// <summary>
/// XML文件的物理路径
/// </summary>
private string _filePath = string.Empty;
/// <summary>
/// Xml文档
/// </summary>
private XmlDocument _xml;
/// <summary>
/// XML的根节点
/// </summary>
private XmlElement _element;
#endregion
#region 构造方法
/// <summary>
/// 实例化XmlHelper对象
/// </summary>
public XmlHelper(string xmlFile)
{
_filePath = string.Format("{0}{1}", GlobalVar.LocalPath, xmlFile);
}
#endregion
#region 创建XmlElement 节点
public XmlElement CreateElement(string elementName)
{
return _xml.CreateElement(elementName);
}
#endregion
#region 创建xml文件
private void CreateXmlNew()
{
//使用XmlDocument创建xml
XmlDocument xmldoc = new XmlDocument();
XmlDeclaration xmldec = xmldoc.CreateXmlDeclaration("1.0", "utf-8", "yes");
xmldoc.AppendChild(xmldec);
XmlElement root = xmldoc.CreateElement("root");
root.AppendChild(xmldoc.CreateElement("HardwareInfos"));
root.AppendChild(xmldoc.CreateElement("Functions"));
root.AppendChild(xmldoc.CreateElement("TypeFunctions"));
root.AppendChild(xmldoc.CreateElement("HardwareLinks"));
root.AppendChild(xmldoc.CreateElement("DeviceTypes"));
//添加根节点
xmldoc.AppendChild(root);
xmldoc.Save(_filePath);
}
#endregion
#region 创建XML的根节点
/// <summary>
/// 创建XML的根节点
/// </summary>
private void CreateXMLElement()
{
if (_xml == null || _element == null)
{
//创建一个XML对象
_xml = new XmlDocument();
if (File.Exists(_filePath))
{
//加载XML文件
_xml.Load(this._filePath);
}
else
{
CreateXmlNew();
//加载XML文件
_xml.Load(this._filePath);
}
//为XML的根节点赋值
_element = _xml.DocumentElement;
}
}
#endregion
#region 获取指定XPath表达式的节点对象
/// <summary>
/// 获取指定XPath表达式的节点对象
/// </summary>
/// <param name="xPath">XPath表达式,
/// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
/// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
/// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
/// </param>
public XmlNode GetNode(string xPath)
{
//创建XML的根节点
CreateXMLElement();
XmlNode xmlNode = _element.SelectSingleNode(xPath);
if (xmlNode == null)
{
xmlNode = _xml.SelectSingleNode(xPath);
if (xmlNode == null)
{
return null;
}
}
//返回XPath节点
return xmlNode;
}
public XmlNodeList GetNodes(string xPath)
{
//创建XML的根节点
CreateXMLElement();
return _element.SelectNodes(xPath);
}
#endregion
#region 获取指定XPath表达式节点的值
/// <summary>
/// 获取指定XPath表达式节点的值
/// </summary>
/// <param name="xPath">XPath表达式,
/// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
/// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
/// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
/// </param>
public string GetValue(string xPath)
{
//创建XML的根节点
CreateXMLElement();
//返回XPath节点的值
return _element.SelectSingleNode(xPath).InnerText;
}
public void RefreshXml()
{
if (_xml == null)
{
CreateXMLElement();
}
else
{
_xml.Load(this._filePath);
//为XML的根节点赋值
_element = _xml.DocumentElement;
}
}
#endregion
#region 获取指定XPath表达式节点的属性值
/// <summary>
/// 获取指定XPath表达式节点的属性值
/// </summary>
/// <param name="xPath">XPath表达式,
/// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
/// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
/// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
/// </param>
/// <param name="attributeName">属性名</param>
public string GetAttributeValue(string xPath, string attributeName)
{
//创建XML的根节点
CreateXMLElement();
//返回XPath节点的属性值
return _element.SelectSingleNode(xPath).Attributes[attributeName].Value;
}
#endregion
#region 新增节点
/// <summary>
/// 1. 功能:新增节点。
/// 2. 使用条件:将任意节点插入到当前Xml文件中。
/// </summary>
/// <param name="xmlNode">要插入的Xml节点</param>
public void AppendNode(XmlNode xmlNode)
{
//创建XML的根节点
CreateXMLElement();
//导入节点
XmlNode node = _xml.ImportNode(xmlNode, true);
//将节点插入到根节点下
_element.AppendChild(node);
}
/// <summary>
/// 1. 功能:新增节点。
/// 2. 使用条件:将DataSet中的第一条记录插入Xml文件中。
/// </summary>
/// <param name="ds">DataSet的实例,该DataSet中应该只有一条记录</param>
public void AppendNode(DataSet ds)
{
//创建XmlDataDocument对象
XmlDataDocument xmlDataDocument = new XmlDataDocument(ds);
//导入节点
XmlNode node = xmlDataDocument.DocumentElement.FirstChild;
//将节点插入到根节点下
AppendNode(node);
}
#endregion
#region 删除节点
/// <summary>
/// 删除指定XPath表达式的节点
/// </summary>
/// <param name="xPath">XPath表达式,
/// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
/// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
/// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
/// </param>
public void RemoveNode(string xPath)
{
//创建XML的根节点
CreateXMLElement();
//获取要删除的节点
XmlNode node = GetNode(xPath);
if (node != null)
{
//删除节点
node.ParentNode.RemoveChild(node);
}
Save();
}
#endregion //删除节点
#region 保存XML文件
/// <summary>
/// 保存XML文件
/// </summary>
public void Save()
{
//创建XML的根节点
CreateXMLElement();
//保存XML文件
_xml.Save(this._filePath);
}
#endregion //保存XML文件
#region 静态方法
#region 创建根节点对象
/// <summary>
/// 创建根节点对象
/// </summary>
/// <param name="xmlFilePath">Xml文件的相对路径</param>
private static XmlElement CreateRootElement(string xmlFile)
{
//定义变量,表示XML文件的绝对路径
string filePath = "";
//获取XML文件的绝对路径
filePath = string.Format("{0}\\{1}", GlobalVar.LocalPath, xmlFile);
//创建XmlDocument对象
XmlDocument xmlDocument = new XmlDocument();
//加载XML文件
xmlDocument.Load(filePath);
//返回根节点
return xmlDocument.DocumentElement;
}
#endregion
#region 获取指定XPath表达式节点的值
/// <summary>
/// 获取指定XPath表达式节点的值
/// </summary>
/// <param name="xmlFilePath">Xml文件的相对路径</param>
/// <param name="xPath">XPath表达式,
/// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
/// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
/// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
/// </param>
public static string GetValue(string xmlFilePath, string xPath)
{
//创建根对象
XmlElement rootElement = CreateRootElement(xmlFilePath);
//返回XPath节点的值
return rootElement.SelectSingleNode(xPath).InnerText;
}
#endregion
#region 获取指定XPath表达式节点的属性值
/// <summary>
/// 获取指定XPath表达式节点的属性值
/// </summary>
/// <param name="xmlFilePath">Xml文件的相对路径</param>
/// <param name="xPath">XPath表达式,
/// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
/// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
/// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
/// </param>
/// <param name="attributeName">属性名</param>
public static string GetAttributeValue(string xmlFilePath, string xPath, string attributeName)
{
//创建根对象
XmlElement rootElement = CreateRootElement(xmlFilePath);
//返回XPath节点的属性值
return rootElement.SelectSingleNode(xPath).Attributes[attributeName].Value;
}
#endregion
#endregion
}
硬件xml类
该类主要为了便于操作硬件与xml所产生的,主要为了查询及操作xml方便。创建一个硬件访问xml的entity类:HardwareXmlEntity。
该类主要便于展示xml信息及操作,例如_param属性,我们可以通过约定的主键属性就能获得其数值。而且硬件属性除了最基本的属性外,都是可变的,因此使用了Dictionary类型进行存储,之前设计时原本想将类型或约定放入其中,例如IP一定是一定为*.*.*.*
类型,而端口号一定为整型,否则我们就会认为输入错误,后来将该判断放入了硬件部分中,没有在该处添加,因为这样需要再进行额外的配置,而且按照约定来说,现场的人员对于IP和端口号应该不会理解有误(约定大于配置)。
public class HardwareXmlEntity
{
/// <summary>
/// HardwareInfo标签内的属性和值
/// 例如:Ip地址="COM9" 端口号="115200" 设备类型="短信猫" 类型主键="15" 设备型号="短信池" 型号主键="1503"
/// </summary>
Dictionary<String, String> _param;
/// <summary>
/// 定时相关的功能
/// </summary>
private List<FunctionSetting> _settingsFunction;
/// <summary>
/// 可操作的功能
/// </summary>
private List<Function> _operationFunction;
/// <summary>
/// 初始化的功能
/// </summary>
private List<Function> _initializationFunction;
// 三个功能的描述
private string _operationTxt;
private string _initializationTxt;
private string _settingsTxt;
public Dictionary<string, string> Param { get => _param; set => _param = value; }
public List<FunctionSetting> SettingsFun { get => _settingsFunction; set => _settingsFunction = value; }
public List<Function> OperationFun { get => _operationFunction; set => _operationFunction = value; }
public List<Function> InitializationFun { get => _initializationFunction; set => _initializationFunction = value; }
public string OperationTxt { get => _operationTxt; set => _operationTxt = value; }
public string InitializationTxt { get => _initializationTxt; set => _initializationTxt = value; }
public string SettingsTxt { get => _settingsTxt; set => _settingsTxt = value; }
public String ParamJson { get => JSONUtils.SerializeObject(_param); }
public String PrimaryKey { get => _param["设备主键"]; }
}
新增HardwareXmlEntity操作类
当HardwareXmlEntity获得后,需要对于他进行一系列的操作,在HardwareLibrary中创建AssemblyUtil.cs类
该类的作用是将Function的相关类型进行转换,例如,已知其描述获取其enum的值;已知其值获得相关描述信息。
public class AssemblyUtil
{
/// <summary>
/// 通过传入的描述属性获得该描述属性对应的值
/// </summary>
/// <param name="descriptions"></param>
/// <returns></returns>
public static List<Function> GetEnumByDescriptions(string[] descriptions)
{
List<Function> functions = new List<Function>();
Dictionary<string, Function> keyValues = GetDictionary<Function>();
foreach (string item in descriptions)
{
if (keyValues.ContainsKey(item))
{
functions.Add(keyValues[item]);
}
}
return functions;
}
/// <summary>
/// 通过传入的类型获取其描述属性及其值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Dictionary<string, T> GetDictionary<T>()
{
Dictionary<string, T> keyValues = new Dictionary<string, T>();
System.Reflection.FieldInfo[] fields = typeof(T).GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false); //获取描述属性
if (objs.Length > 0 && !string.IsNullOrEmpty((objs[0] as DescriptionAttribute).Description))
{
keyValues.Add((objs[0] as DescriptionAttribute).Description, (T)field.GetValue(null));
}
}
return keyValues;
}
/// <summary>
/// 获取类型的描述内容
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static string GetDescriptionByEnum<T>(T obj)
{
string objName = obj.ToString();
Type t = obj.GetType();
System.Reflection.FieldInfo fi = t.GetField(objName);
System.ComponentModel.DescriptionAttribute[] arrDesc = (System.ComponentModel.DescriptionAttribute[])fi.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
return arrDesc[0].Description;
}
/// <summary>
/// 获取列表中描述的属性,并按照逗号分隔
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="objs"></param>
/// <returns></returns>
public static string GetDescriptionByEnumLis<T>(List<T> objs)
{
List<string> descripts = new List<string>();
objs.ForEach(obj => {
descripts.Add(GetDescriptionByEnum(obj));
});
return string.Join(",", descripts);
}
/// <summary>
/// 根据描述属性获取类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="description"></param>
/// <returns></returns>
public static T GetEnumByDescription<T>(string description)
{
System.Reflection.FieldInfo[] fields = typeof(T).GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false); //获取描述属性
if (objs.Length > 0 && (objs[0] as DescriptionAttribute).Description == description)
{
return (T)field.GetValue(null);
}
}
return default(T);
}
}
以上我们就完成了xml相关类的基本添加。