mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-24 12:20:28 +08:00
534 lines
21 KiB
C#
534 lines
21 KiB
C#
#region copyright
|
||
//------------------------------------------------------------------------------
|
||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||
// QQ群:605534569
|
||
//------------------------------------------------------------------------------
|
||
#endregion
|
||
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
|
||
using Opc.Ua;
|
||
|
||
using System.Collections;
|
||
using System.IO;
|
||
using System.Text;
|
||
using System.Xml;
|
||
|
||
namespace ThingsGateway.Foundation.Adapter.OPCUA;
|
||
/// <summary>
|
||
/// 扩展方法
|
||
/// </summary>
|
||
public static class JsonUtils
|
||
{
|
||
#region Decode
|
||
|
||
/// <summary>
|
||
/// 解析获取DataValue
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static DataValue Decode(
|
||
IServiceMessageContext Context,
|
||
NodeId dataTypeId,
|
||
BuiltInType builtInType,
|
||
int valueRank,
|
||
JToken json
|
||
)
|
||
{
|
||
|
||
var data = DecoderObject(Context, dataTypeId, builtInType, valueRank, json);
|
||
var dataValue = new DataValue(new Variant(data));
|
||
return dataValue;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 解析获取object
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static object DecoderObject(
|
||
IServiceMessageContext Context,
|
||
NodeId dataTypeId,
|
||
BuiltInType builtInType,
|
||
int valueRank,
|
||
JToken json
|
||
)
|
||
{
|
||
object newData;
|
||
switch (builtInType)
|
||
{
|
||
case BuiltInType.ExtensionObject:
|
||
newData = new
|
||
{
|
||
Value = new
|
||
{
|
||
TypeId = new { Id = dataTypeId.Identifier, Namespace = dataTypeId.NamespaceIndex },
|
||
Body = json
|
||
}
|
||
}.ToJsonString();
|
||
break;
|
||
case BuiltInType.Variant:
|
||
var type = TypeInfo.GetDataTypeId(GetSystemType(json.Type));
|
||
newData = new
|
||
{
|
||
Value = new
|
||
{
|
||
Type = type.Identifier,
|
||
Body = json
|
||
}
|
||
|
||
}.ToJsonString();
|
||
break;
|
||
default:
|
||
newData = new
|
||
{
|
||
Value = json
|
||
}.ToJsonString();
|
||
break;
|
||
}
|
||
|
||
using var decoder = new JsonDecoder(newData.ToString(), Context);
|
||
var data = DecodeRawData(decoder, builtInType, valueRank, "Value");
|
||
return data;
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// DecodeRawData
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static object DecodeRawData(JsonDecoder decoder, BuiltInType builtInType, int ValueRank, string fieldName)
|
||
{
|
||
if (builtInType != 0)
|
||
{
|
||
if (ValueRank == ValueRanks.Scalar)
|
||
{
|
||
switch (builtInType)
|
||
{
|
||
case BuiltInType.Null: { var variant = decoder.ReadVariant(fieldName); return variant.Value; }
|
||
case BuiltInType.Boolean: { return decoder.ReadBoolean(fieldName); }
|
||
case BuiltInType.SByte: { return decoder.ReadSByte(fieldName); }
|
||
case BuiltInType.Byte: { return decoder.ReadByte(fieldName); }
|
||
case BuiltInType.Int16: { return decoder.ReadInt16(fieldName); }
|
||
case BuiltInType.UInt16: { return decoder.ReadUInt16(fieldName); }
|
||
case BuiltInType.Int32: { return decoder.ReadInt32(fieldName); }
|
||
case BuiltInType.UInt32: { return decoder.ReadUInt32(fieldName); }
|
||
case BuiltInType.Int64: { return decoder.ReadInt64(fieldName); }
|
||
case BuiltInType.UInt64: { return decoder.ReadUInt64(fieldName); }
|
||
case BuiltInType.Float: { return decoder.ReadFloat(fieldName); }
|
||
case BuiltInType.Double: { return decoder.ReadDouble(fieldName); }
|
||
case BuiltInType.String: { return decoder.ReadField(fieldName, out var cancellationToken) ? cancellationToken?.ToString() : null; }
|
||
case BuiltInType.DateTime: { return decoder.ReadDateTime(fieldName); }
|
||
case BuiltInType.Guid: { return decoder.ReadGuid(fieldName); }
|
||
case BuiltInType.ByteString: { return decoder.ReadByteString(fieldName); }
|
||
case BuiltInType.XmlElement: { return decoder.ReadXmlElement(fieldName); }
|
||
case BuiltInType.NodeId: { return decoder.ReadNodeId(fieldName); }
|
||
case BuiltInType.ExpandedNodeId: { return decoder.ReadExpandedNodeId(fieldName); }
|
||
case BuiltInType.StatusCode: { return decoder.ReadStatusCode(fieldName); }
|
||
case BuiltInType.QualifiedName: { return decoder.ReadQualifiedName(fieldName); }
|
||
case BuiltInType.LocalizedText: { return decoder.ReadLocalizedText(fieldName); }
|
||
case BuiltInType.ExtensionObject: { return decoder.ReadExtensionObject(fieldName); }
|
||
case BuiltInType.DataValue: { return decoder.ReadDataValue(fieldName); }
|
||
case BuiltInType.Enumeration:
|
||
{
|
||
Type type = TypeInfo.GetSystemType(builtInType, ValueRank);
|
||
return type.IsEnum ? decoder.ReadEnumerated(fieldName, type) : decoder.ReadInt32(fieldName);
|
||
}
|
||
case BuiltInType.DiagnosticInfo: { return decoder.ReadDiagnosticInfo(fieldName); }
|
||
case BuiltInType.Variant: { return decoder.ReadVariant(fieldName); }
|
||
}
|
||
}
|
||
if (ValueRank >= ValueRanks.OneDimension)
|
||
{
|
||
return decoder.ReadArray(fieldName, ValueRank, builtInType);
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region Encode
|
||
/// <summary>
|
||
/// OPCUAValue解析为Jtoken
|
||
/// </summary>
|
||
/// <param name="Context"></param>
|
||
/// <param name="type"></param>
|
||
/// <param name="value"></param>
|
||
/// <returns></returns>
|
||
internal static JToken Encode(
|
||
IServiceMessageContext Context,
|
||
BuiltInType type,
|
||
object value
|
||
)
|
||
{
|
||
//对于Integer,Int64,Number等会转化为string JValue!
|
||
|
||
using var encoder = CreateEncoder(Context, null, false);
|
||
Encode(encoder, type, "Value", value);
|
||
var textbuffer = encoder.CloseAndReturnText();
|
||
using var stringReader = new StringReader(textbuffer);
|
||
using var jsonReader = new JsonTextReader(stringReader);
|
||
var jToken = JToken.Load(jsonReader);
|
||
return jToken["Value"];
|
||
}
|
||
|
||
/// <summary>
|
||
/// CreateEncoder
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static OPCUAJsonEncoder CreateEncoder(
|
||
IServiceMessageContext context,
|
||
Stream stream,
|
||
bool useReversibleEncoding = false,
|
||
bool topLevelIsArray = false,
|
||
bool includeDefaultValues = true,
|
||
bool includeDefaultNumbers = true
|
||
)
|
||
{
|
||
|
||
return new OPCUAJsonEncoder(context, useReversibleEncoding, topLevelIsArray, stream)
|
||
{
|
||
IncludeDefaultValues = includeDefaultValues,
|
||
IncludeDefaultNumberValues = includeDefaultNumbers
|
||
};
|
||
}
|
||
|
||
private static void Encode(OPCUAJsonEncoder encoder, BuiltInType builtInType, string fieldName, object value)
|
||
{
|
||
bool isArray = (value?.GetType().IsArray ?? false) && (builtInType != BuiltInType.ByteString);
|
||
bool isCollection = (value is IList) && (builtInType != BuiltInType.ByteString);
|
||
if (!isArray && !isCollection)
|
||
{
|
||
switch (builtInType)
|
||
{
|
||
case BuiltInType.Null: { encoder.WriteVariant(fieldName, new Variant(value)); return; }
|
||
//case BuiltInType.Boolean: { encoder.WriteBoolean(fieldName, (bool)value); return; }
|
||
//case BuiltInType.SByte: { encoder.WriteSByte(fieldName, (sbyte)value); return; }
|
||
//case BuiltInType.Byte: { encoder.WriteByte(fieldName, (byte)value); return; }
|
||
//case BuiltInType.Int16: { encoder.WriteInt16(fieldName, (short)value); return; }
|
||
//case BuiltInType.UInt16: { encoder.WriteUInt16(fieldName, (ushort)value); return; }
|
||
//case BuiltInType.Int32: { encoder.WriteInt32(fieldName, (int)value); return; }
|
||
//case BuiltInType.UInt32: { encoder.WriteUInt32(fieldName, (uint)value); return; }
|
||
//case BuiltInType.Int64: { encoder.WriteInt64(fieldName, (long)value); return; }
|
||
//case BuiltInType.UInt64: { encoder.WriteUInt64(fieldName, (ulong)value); return; }
|
||
//case BuiltInType.Float: { encoder.WriteFloat(fieldName, (float)value); return; }
|
||
//case BuiltInType.Double: { encoder.WriteDouble(fieldName, (double)value); return; }
|
||
|
||
//case BuiltInType.Integer: { encoder.WriteInt64(fieldName, (long)value); return; }
|
||
//case BuiltInType.Number: { encoder.WriteInt64(fieldName, (long)value); return; }
|
||
//case BuiltInType.UInteger: { encoder.WriteUInt64(fieldName, (ulong)value); return; }
|
||
//case BuiltInType.String: { encoder.WriteString(fieldName, value?.ToString()); return; }
|
||
//case BuiltInType.DateTime: { encoder.WriteDateTime(fieldName, (DateTime)value); return; }
|
||
case BuiltInType.Boolean:
|
||
{
|
||
encoder.WriteBoolean(fieldName, Convert.ToBoolean(value));
|
||
return;
|
||
}
|
||
case BuiltInType.SByte:
|
||
{
|
||
encoder.WriteSByte(fieldName, Convert.ToSByte(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Byte:
|
||
{
|
||
encoder.WriteByte(fieldName, Convert.ToByte(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Int16:
|
||
{
|
||
encoder.WriteInt16(fieldName, Convert.ToInt16(value));
|
||
return;
|
||
}
|
||
case BuiltInType.UInt16:
|
||
{
|
||
encoder.WriteUInt16(fieldName, Convert.ToUInt16(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Int32:
|
||
{
|
||
encoder.WriteInt32(fieldName, Convert.ToInt32(value));
|
||
return;
|
||
}
|
||
case BuiltInType.UInt32:
|
||
{
|
||
encoder.WriteUInt32(fieldName, Convert.ToUInt32(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Int64:
|
||
{
|
||
encoder.WriteInt64(fieldName, Convert.ToInt64(value));
|
||
return;
|
||
}
|
||
case BuiltInType.UInt64:
|
||
{
|
||
encoder.WriteUInt64(fieldName, Convert.ToUInt64(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Float:
|
||
{
|
||
encoder.WriteFloat(fieldName, Convert.ToSingle(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Double:
|
||
{
|
||
encoder.WriteDouble(fieldName, Convert.ToDouble(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Integer:
|
||
{
|
||
encoder.WriteInt64(fieldName, Convert.ToInt64(value));
|
||
return;
|
||
}
|
||
case BuiltInType.Number:
|
||
{
|
||
encoder.WriteInt64(fieldName, Convert.ToInt64(value));
|
||
return;
|
||
}
|
||
case BuiltInType.UInteger:
|
||
{
|
||
encoder.WriteUInt64(fieldName, Convert.ToUInt64(value));
|
||
return;
|
||
}
|
||
case BuiltInType.String:
|
||
{
|
||
encoder.WriteString(fieldName, Convert.ToString(value));
|
||
return;
|
||
}
|
||
case BuiltInType.DateTime:
|
||
{
|
||
encoder.WriteDateTime(fieldName, Convert.ToDateTime(value));
|
||
return;
|
||
}
|
||
|
||
|
||
case BuiltInType.Guid: { encoder.WriteGuid(fieldName, (Uuid)value); return; }
|
||
case BuiltInType.ByteString: { encoder.WriteByteString(fieldName, (byte[])value); return; }
|
||
case BuiltInType.XmlElement: { encoder.WriteXmlElement(fieldName, (XmlElement)value); return; }
|
||
case BuiltInType.NodeId: { encoder.WriteNodeId(fieldName, (NodeId)value); return; }
|
||
case BuiltInType.ExpandedNodeId: { encoder.WriteExpandedNodeId(fieldName, (ExpandedNodeId)value); return; }
|
||
case BuiltInType.StatusCode: { encoder.WriteStatusCode(fieldName, (StatusCode)value); return; }
|
||
case BuiltInType.QualifiedName: { encoder.WriteQualifiedName(fieldName, (QualifiedName)value); return; }
|
||
case BuiltInType.LocalizedText: { encoder.WriteLocalizedText(fieldName, (LocalizedText)value); return; }
|
||
case BuiltInType.ExtensionObject: { encoder.WriteExtensionObject(fieldName, (ExtensionObject)value); return; }
|
||
case BuiltInType.DataValue: { encoder.WriteDataValue(fieldName, (DataValue)value); return; }
|
||
case BuiltInType.Enumeration:
|
||
{
|
||
if (value?.GetType().IsEnum == true)
|
||
{
|
||
encoder.WriteEnumerated(fieldName, (Enum)value);
|
||
}
|
||
else
|
||
{
|
||
encoder.WriteEnumerated(fieldName, (Enumeration)value);
|
||
}
|
||
return;
|
||
}
|
||
case BuiltInType.Variant: { encoder.WriteVariant(fieldName, new Variant(value)); return; }
|
||
case BuiltInType.DiagnosticInfo: { encoder.WriteDiagnosticInfo(fieldName, (DiagnosticInfo)value); return; }
|
||
|
||
//case BuiltInType.Boolean:
|
||
//case BuiltInType.SByte:
|
||
//case BuiltInType.Byte:
|
||
//case BuiltInType.Int16:
|
||
//case BuiltInType.UInt16:
|
||
//case BuiltInType.Int32:
|
||
//case BuiltInType.UInt32:
|
||
//case BuiltInType.Int64:
|
||
//case BuiltInType.UInt64:
|
||
//case BuiltInType.Float:
|
||
//case BuiltInType.Double:
|
||
//case BuiltInType.String:
|
||
//case BuiltInType.Number:
|
||
//case BuiltInType.Integer:
|
||
//case BuiltInType.UInteger:
|
||
// { encoder.WriteString(fieldName, value?.ToString()); return; }
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Array c = value as Array;
|
||
encoder.WriteArray(fieldName, c, c.Rank, builtInType);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region json
|
||
|
||
/// <summary>
|
||
/// 维度
|
||
/// </summary>
|
||
/// <param name="jToken"></param>
|
||
/// <returns></returns>
|
||
internal static int CalculateActualValueRank(this JToken jToken)
|
||
{
|
||
if (jToken.Type != JTokenType.Array)
|
||
return -1;
|
||
|
||
var jArray = jToken.ToArray();
|
||
int numDimensions = 1;
|
||
|
||
while (jArray.GetElementsType() == JTokenType.Array)
|
||
{
|
||
jArray = jArray.Children().ToArray();
|
||
numDimensions++;
|
||
}
|
||
return numDimensions;
|
||
}
|
||
private static bool ElementsHasSameType(this JToken[] jTokens)
|
||
{
|
||
var checkType = jTokens[0].Type == JTokenType.Integer ? JTokenType.Float : jTokens[0].Type;
|
||
return jTokens
|
||
.Select(x => (x.Type == JTokenType.Integer) ? JTokenType.Float : x.Type)
|
||
.All(t => t == checkType);
|
||
}
|
||
|
||
private static JTokenType GetElementsType(this JToken[] jTokens)
|
||
{
|
||
if (!jTokens.ElementsHasSameType())
|
||
throw new Exception("The array sent must have the same type of element in each dimension");
|
||
return jTokens.First().Type;
|
||
}
|
||
private static Type GetSystemType(JTokenType jsonType)
|
||
{
|
||
return jsonType switch
|
||
{
|
||
JTokenType.None => typeof(string),
|
||
JTokenType.Object => typeof(string),
|
||
JTokenType.Array => typeof(Array),
|
||
JTokenType.Constructor => typeof(string),
|
||
JTokenType.Property => typeof(string),
|
||
JTokenType.Comment => typeof(string),
|
||
JTokenType.Integer => typeof(long),
|
||
JTokenType.Float => typeof(float),
|
||
JTokenType.String => typeof(string),
|
||
JTokenType.Boolean => typeof(bool),
|
||
JTokenType.Null => typeof(string),
|
||
JTokenType.Undefined => typeof(string),
|
||
JTokenType.Date => typeof(DateTime),
|
||
JTokenType.Raw => typeof(string),
|
||
JTokenType.Bytes => typeof(byte[]),
|
||
JTokenType.Guid => typeof(Guid),
|
||
JTokenType.Uri => typeof(Uri),
|
||
JTokenType.TimeSpan => typeof(TimeSpan),
|
||
_ => null,
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Json序列化和反序列化
|
||
/// <summary>
|
||
/// 从字符串到json
|
||
/// </summary>
|
||
/// <param name="json"></param>
|
||
/// <param name="type"></param>
|
||
/// <returns></returns>
|
||
internal static object FromJsonString(this string json, Type type)
|
||
{
|
||
return Newtonsoft.Json.JsonConvert.DeserializeObject(json, type);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从字符串到json
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="json"></param>
|
||
/// <returns></returns>
|
||
internal static T FromJsonString<T>(this string json)
|
||
{
|
||
return (T)FromJsonString(json, typeof(T));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Json反序列化
|
||
/// </summary>
|
||
/// <typeparam name="T">反序列化类型</typeparam>
|
||
/// <param name="datas">数据</param>
|
||
/// <returns></returns>
|
||
internal static T JsonDeserializeFromBytes<T>(byte[] datas)
|
||
{
|
||
return (T)JsonDeserializeFromBytes(datas, typeof(T));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Json反序列化
|
||
/// </summary>
|
||
/// <param name="datas"></param>
|
||
/// <param name="type"></param>
|
||
/// <returns></returns>
|
||
internal static object JsonDeserializeFromBytes(byte[] datas, Type type)
|
||
{
|
||
return FromJsonString(Encoding.UTF8.GetString(datas), type);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Json反序列化
|
||
/// </summary>
|
||
/// <typeparam name="T">反序列化类型</typeparam>
|
||
/// <param name="path">文件路径</param>
|
||
/// <returns></returns>
|
||
internal static T JsonDeserializeFromFile<T>(string path)
|
||
{
|
||
return JsonDeserializeFromString<T>(File.ReadAllText(path));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Json反序列化
|
||
/// </summary>
|
||
/// <typeparam name="T">类型</typeparam>
|
||
/// <param name="json">json字符串</param>
|
||
/// <returns></returns>
|
||
internal static T JsonDeserializeFromString<T>(string json)
|
||
{
|
||
return FromJsonString<T>(json);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Json序列化数据对象
|
||
/// </summary>
|
||
/// <param name="obj">数据对象</param>
|
||
/// <returns></returns>
|
||
internal static byte[] JsonSerializeToBytes(object obj)
|
||
{
|
||
return Encoding.UTF8.GetBytes(ToJsonString(obj));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Json序列化至文件
|
||
/// </summary>
|
||
/// <param name="obj"></param>
|
||
/// <param name="path"></param>
|
||
internal static void JsonSerializeToFile(object obj, string path)
|
||
{
|
||
using (var fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||
{
|
||
var date = JsonSerializeToBytes(obj);
|
||
fileStream.Write(date, 0, date.Length);
|
||
fileStream.Close();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换为Json
|
||
/// </summary>
|
||
/// <param name="item"></param>
|
||
/// <param name="isIndented"></param>
|
||
/// <returns></returns>
|
||
internal static string ToJsonString(this object item, bool isIndented = false)
|
||
{
|
||
if (isIndented)
|
||
return Newtonsoft.Json.JsonConvert.SerializeObject(item, Newtonsoft.Json.Formatting.Indented);
|
||
else
|
||
return Newtonsoft.Json.JsonConvert.SerializeObject(item);
|
||
}
|
||
#endregion Json序列化和反序列化
|
||
|
||
} |