| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Linq;
- using System.Windows.Forms;
- using System.Xml;
- using System.Xml.Linq;
- public static class SymbolParser
- {
- public static List<TypeBase> ParseTypeList(string filePath)
- {
- XmlDocument doc = new XmlDocument();
- doc.Load(filePath);
- // 1. 动态获取命名空间
- string namespaceUri = doc.DocumentElement?.NamespaceURI ?? "";
- // 2. 创建命名空间管理器
- XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
- nsmgr.AddNamespace("ns", namespaceUri);
- var typeList = doc.SelectNodes("//ns:TypeList/*", nsmgr);
- if (typeList == null)
- {
- throw new Exception("无法找到 TypeList 节点,请检查XML结构或命名空间。");
- }
- List<TypeBase> types = new List<TypeBase>();
- // 解析类型定义
- foreach (XmlNode typeNode in typeList)
- {
- var type= ParseTypeDefinition(typeNode, nsmgr);
- if(type!=null)
- { types.Add(type); }
- }
- return types;
- }
- private static TypeBase ParseTypeDefinition(XmlNode node, XmlNamespaceManager nsmgr)
- {
- string typeName = GetAttribute(node, "name");
- if (typeName == null)
- return null;
- switch (node.Name)
- {
- case "TypeSimple":
- var typeSimple = new TypeSimple()
- {
- Name = GetAttribute(node, "name"),
- Size = int.Parse(GetAttribute(node, "size")),
- SwapSize = int.Parse(GetAttribute(node, "swapsize")),
- TypeClass = GetAttribute(node, "typeclass"),
- IecName = GetAttribute(node, "iecname"),
- BitOffset = int.Parse(string.IsNullOrEmpty(GetAttribute(node, "bitoffset")) ? "0" : GetAttribute(node, "bitoffset"))
- };
- return typeSimple;
- case "TypeArray":
- var typeArray = new TypeArray()
- {
- Name = GetAttribute(node, "name"),
- Size = int.Parse(GetAttribute(node, "size")),
- NativeSize = int.Parse(GetAttribute(node, "nativesize")),
- TypeClass = GetAttribute(node, "typeclass"),
- IecName = GetAttribute(node, "iecname"),
- BaseType = GetAttribute(node, "basetype")
- };
- var dimensions = GetArrayDimensions(node, nsmgr);
- typeArray.Rank = dimensions.Count;
- if (typeArray.Rank > 0)
- {
- typeArray.MinRange = new int[typeArray.Rank];
- typeArray.MaxRange = new int[typeArray.Rank];
- for (int i = 0; i < typeArray.Rank; i++)
- {
- typeArray.MinRange[i] = dimensions[i].Min;
- typeArray.MaxRange[i] = dimensions[i].Max;
- }
- }
- return typeArray;
- case "TypeUserDef":
- var typeUserDef = new TypeUserDef()
- {
- Name = GetAttribute(node, "name"),
- Size = int.Parse(GetAttribute(node, "size")),
- NativeSize = int.Parse(GetAttribute(node, "nativesize")),
- TypeClass = GetAttribute(node, "typeclass"),
- PouClass = GetAttribute(node, "pouclass"),
- IecName = GetAttribute(node, "iecname"),
- };
- typeUserDef.UserDefElements = GetUserDefElement(node, nsmgr);
- return typeUserDef;
- default:
- return null;
- }
- }
- public static List<(int Min, int Max)> GetArrayDimensions(XmlNode arrayNode, XmlNamespaceManager nsmgr)
- {
- var result = new List<(int Min, int Max)>();
- XmlNodeList dimNodes = arrayNode.SelectNodes("ns:ArrayDim", nsmgr);
- if (dimNodes == null) return result;
- foreach (XmlNode dim in dimNodes)
- {
- if (int.TryParse(dim.Attributes["minrange"]?.Value, out int min) &&
- int.TryParse(dim.Attributes["maxrange"]?.Value, out int max))
- {
- result.Add((min, max));
- }
- }
- return result;
- }
- public static List<UserDefElement> GetUserDefElement(XmlNode arrayNode, XmlNamespaceManager nsmgr)
- {
- var result = new List<UserDefElement>();
- XmlNodeList dimNodes = arrayNode.SelectNodes("ns:UserDefElement", nsmgr);
- if (dimNodes == null) return result;
- foreach (XmlNode dim in dimNodes)
- {
- var element = new UserDefElement
- {
- IecName = dim.Attributes["iecname"]?.Value,
- Type = dim.Attributes["type"].Value,
- //ByteOffset = uint.Parse(dim.Attributes["byteoffset"]?.Value),
- VarType = dim.Attributes["vartype"]?.Value,
- Access = dim.Attributes["access"]?.Value
- };
- //if(element.Type!=GetAttribute(arrayNode, "name"))//如果一个类型的name和子类型的type相同,则不能添加进去,否则在添加Node时会出现一直递归,堆栈溢出
- result.Add(element);
- }
- return result;
- }
- public static XmlVariable ParseNode(string filePath, List<TypeBase> types)
- {
- XmlDocument doc = new XmlDocument();
- doc.Load(filePath);
- // 1. 动态获取命名空间
- string namespaceUri = doc.DocumentElement?.NamespaceURI ?? "";
- // 2. 创建命名空间管理器
- XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
- //nsmgr.AddNamespace("ns", "http://www.3s-software.com/schemas/Symbolconfiguration.xsd");
- nsmgr.AddNamespace("ns", namespaceUri);
- // 使用命名空间前缀进行查询
- XmlNode rootNode = doc.SelectSingleNode("//ns:NodeList/ns:Node", nsmgr);
- if (rootNode == null)
- {
- throw new Exception("无法找到 NodeList/Node 节点,请检查XML结构或命名空间。");
- }
- //var varNode= ParseNode(rootNode);
- var varNode= ParseAllElementNode(rootNode, nsmgr, types);
- return varNode;
- }
- private static XmlVariable ParseAllElementNode(XmlNode xmlNode, XmlNamespaceManager nsmgr, List<TypeBase> types)
- {
- var varNode = GetNodeValue(xmlNode, nsmgr);
- if (!varNode.IsLeaf)
- {
- foreach (XmlNode xmlChild in xmlNode.ChildNodes)
- {
- if (xmlChild.Name == "Node")
- {
- string strXmlChildNodeType = GetAttribute(xmlChild, "type");
- if (string.IsNullOrEmpty(strXmlChildNodeType))//不是具体的数据,有子Node
- varNode.Children.Add(ParseAllElementNode(xmlChild, nsmgr, types));
- else
- {
- var xmlChildNodeType = types.First(t => t.Name == strXmlChildNodeType);//找到具体是之前搜索到的具体哪个类型
- if (xmlChildNodeType is TypeSimple)//简单数据类型,直接添加
- {
- var subNode = GetNodeValue(xmlChild, nsmgr);
- varNode.Children.Add(subNode);
- }
- else if (xmlChildNodeType is TypeArray typeArray)//数组类型
- {
- var subNode = GetNodeValue(xmlChild, nsmgr);
- subNode.IsLeaf = false;
- varNode.Children.Add(subNode);//添加数组名本身,然后再添加其下面的元素
- int count = 1;
- for (int i = 0; i < typeArray.Rank; i++)
- {
- count *= (typeArray.MaxRange[i] + 1 - typeArray.MinRange[i]);
- }
- int[] cIndex = new int[typeArray.Rank];
- for (int i = 0; i < count; i++)
- {
- string name = IndicesToString(GetNDElement(typeArray.Rank, typeArray.MinRange, typeArray.MaxRange, i));
- subNode.Children.Add(ParseArrayAndUserDefElement(name, typeArray.BaseType, types));
- }
- }
- else if (xmlChildNodeType is TypeUserDef typeUserDef)//结构体类型
- {
- var subNode = GetNodeValue(xmlChild, nsmgr);
- subNode.IsLeaf = false;
- varNode.Children.Add(subNode);//添加结构体名本身,然后再添加其下面的元素
- foreach (var userDefElement in typeUserDef.UserDefElements)
- {
- subNode.Children.Add(ParseArrayAndUserDefElement(userDefElement.IecName, userDefElement.Type, types));
- }
- }
- }
- }
- }
- }
- return varNode;
- }
- private static int[] GetNDElement(int N, int[] MinRange, int[] MaxRange, int linearIndex)
- {
- // 1. 计算每个维度的长度
- int[] lengths = new int[N];
- for (int i = 0; i < N; i++)
- {
- lengths[i] = MaxRange[i] - MinRange[i] + 1;
- }
- int totalElements = 1;
- for (int i = 0; i < N; i++)
- {
- totalElements *= lengths[i];
- }
- if (linearIndex < 0 || linearIndex >= totalElements)
- {
- throw new IndexOutOfRangeException("线性索引超出数组范围");
- }
- // 2. 计算每个维度的步长(Stride)
- int[] strides = new int[N];
- strides[N - 1] = 1;
- for (int i = N - 2; i >= 0; i--)
- {
- strides[i] = strides[i + 1] * lengths[i + 1];
- }
- // 3. 还原每个维度的索引(加上偏移 MinRange[i])
- int[] result = new int[N];
- for (int i = 0; i < N; i++)
- {
- int index = (linearIndex / strides[i]) % lengths[i];
- result[i] = MinRange[i] + index;
- }
- return result;
- }
- private static string IndicesToString(int[] indices)
- {
- if (indices == null || indices.Length == 0)
- return "[]";
- return "[" + string.Join(",", indices) + "]";
- }
- private static XmlVariable ParseArrayAndUserDefElement(string name, string baseType, List<TypeBase> types)
- {
- var type = types.First(t => t.Name == baseType);//找到数组的基本类型是哪种类型(也即素组的元素是什么类型)
- if (type is TypeSimple typeSimple)//简单数据类型,直接添加
- {
- var subNode = new XmlVariable()
- {
- Name = name,
- Type = typeSimple.Name,
- IsLeaf = true,
- };
- return subNode;
- }
- else if (type is TypeArray typeArray)
- {
- var subNode = new XmlVariable();
- subNode.Name = name;
- int count = 1;
- for (int i = 0; i < typeArray.Rank; i++)
- {
- count *= (typeArray.MaxRange[i] + 1 - typeArray.MinRange[i]);
- }
- int[] cIndex = new int[typeArray.Rank];
- for (int i = 0; i < count; i++)
- {
- string n = IndicesToString(GetNDElement(typeArray.Rank, typeArray.MinRange, typeArray.MaxRange, i));
- subNode.Children.Add(ParseArrayAndUserDefElement(n, typeArray.BaseType, types));
- }
- return subNode;//添加数组名本身
- }
- else if (type is TypeUserDef typeUserDef)//结构体类型
- {
-
- var subNode = new XmlVariable();
- subNode.Name = name;
- foreach (var userDefElement in typeUserDef.UserDefElements)
- {
- subNode.Children.Add(ParseArrayAndUserDefElement(userDefElement.IecName, userDefElement.Type, types));
- }
- return subNode;
- }
- return null;
- }
- static XmlVariable GetNodeValue(XmlNode xmlNode, XmlNamespaceManager nsmgr)
- {
- var node = new XmlVariable
- {
- Name = GetAttribute(xmlNode, "name"),
- Type = GetAttribute(xmlNode, "type"),
- Access = GetAttribute(xmlNode, "access"),
- Comment= xmlNode.SelectSingleNode("ns:Comment", nsmgr)?.InnerText.Trim() ?? null,
- IsLeaf = xmlNode.SelectNodes("ns:Node", nsmgr).Count == 0
- };
- return node;
- }
- private static string GetAttribute(XmlNode node, string attrName)
- {
- XmlAttribute attr = node.Attributes?[attrName];
- return attr?.Value ?? string.Empty;
- }
- }
|