From 59ace918b76de030051b7b77f3fa9a89d466f009 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 18 Jun 2021 21:20:34 +0200 Subject: [PATCH] . --- Directory.Build.props | 6 +- XPath2.Net.sln | 21 +++ .../FunctionTableExtensions.cs | 138 +++++++++++++++ .../Properties/AssemblyInfo.cs | 22 +++ .../XPath2.Extensions.Core.csproj | 72 ++++++++ .../FunctionTableExtensions.cs | 49 ++++++ .../Json2XmlUtils.cs | 0 .../Properties/AssemblyInfo.cs | 22 +++ .../XPath2.Extensions.NewtonsoftJson.csproj | 77 +++++++++ .../FunctionTableExtensions.cs | 49 ++++++ .../Json2XmlUtils.cs | 123 +++++++++++++ .../Properties/AssemblyInfo.cs | 22 +++ .../XPath2.Extensions.SystemTextJson.csproj | 72 ++++++++ .../FunctionTableExtensions.cs | 161 +----------------- .../XPath2.Extensions.csproj | 18 +- src/XQTSRunConsole/XQTSRunConsole.csproj | 2 +- 16 files changed, 677 insertions(+), 177 deletions(-) create mode 100644 src/XPath2.Extensions.Core/FunctionTableExtensions.cs create mode 100644 src/XPath2.Extensions.Core/Properties/AssemblyInfo.cs create mode 100644 src/XPath2.Extensions.Core/XPath2.Extensions.Core.csproj create mode 100644 src/XPath2.Extensions.NewtonsoftJson/FunctionTableExtensions.cs rename src/{XPath2.Extensions => XPath2.Extensions.NewtonsoftJson}/Json2XmlUtils.cs (100%) create mode 100644 src/XPath2.Extensions.NewtonsoftJson/Properties/AssemblyInfo.cs create mode 100644 src/XPath2.Extensions.NewtonsoftJson/XPath2.Extensions.NewtonsoftJson.csproj create mode 100644 src/XPath2.Extensions.SystemTextJson/FunctionTableExtensions.cs create mode 100644 src/XPath2.Extensions.SystemTextJson/Json2XmlUtils.cs create mode 100644 src/XPath2.Extensions.SystemTextJson/Properties/AssemblyInfo.cs create mode 100644 src/XPath2.Extensions.SystemTextJson/XPath2.Extensions.SystemTextJson.csproj diff --git a/Directory.Build.props b/Directory.Build.props index 5b4c5bc..38b48f7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,9 +3,9 @@ $(MsBuildAllProjects);$(MsBuildThisFileFullPath) - + + 1.2.0.0 + diff --git a/XPath2.Net.sln b/XPath2.Net.sln index 7ae9ca9..5882607 100644 --- a/XPath2.Net.sln +++ b/XPath2.Net.sln @@ -41,6 +41,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XQTSRunConsole", "src\XQTSR EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XPath2.Tests", "tests\XPath2.Tests\XPath2.Tests.csproj", "{31DC2EF8-C3FE-467D-84BE-FB5D956E6100}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XPath2.Extensions.Core", "src\XPath2.Extensions.Core\XPath2.Extensions.Core.csproj", "{1C326CF6-DEC2-4538-B46E-B045D3F7AFC3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XPath2.Extensions.NewtonsoftJson", "src\XPath2.Extensions.NewtonsoftJson\XPath2.Extensions.NewtonsoftJson.csproj", "{D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XPath2.Extensions.SystemTextJson", "src\XPath2.Extensions.SystemTextJson\XPath2.Extensions.SystemTextJson.csproj", "{28876979-CB85-44E4-96F1-537845257964}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +73,18 @@ Global {31DC2EF8-C3FE-467D-84BE-FB5D956E6100}.Debug|Any CPU.Build.0 = Debug|Any CPU {31DC2EF8-C3FE-467D-84BE-FB5D956E6100}.Release|Any CPU.ActiveCfg = Release|Any CPU {31DC2EF8-C3FE-467D-84BE-FB5D956E6100}.Release|Any CPU.Build.0 = Release|Any CPU + {1C326CF6-DEC2-4538-B46E-B045D3F7AFC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C326CF6-DEC2-4538-B46E-B045D3F7AFC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C326CF6-DEC2-4538-B46E-B045D3F7AFC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C326CF6-DEC2-4538-B46E-B045D3F7AFC3}.Release|Any CPU.Build.0 = Release|Any CPU + {D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2}.Release|Any CPU.Build.0 = Release|Any CPU + {28876979-CB85-44E4-96F1-537845257964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28876979-CB85-44E4-96F1-537845257964}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28876979-CB85-44E4-96F1-537845257964}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28876979-CB85-44E4-96F1-537845257964}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -78,6 +96,9 @@ Global {D3804228-91F4-4502-9595-39584EBB0000} = {0C331956-D83C-4A5C-8A73-6B948ADEA559} {D439F305-067F-4ABE-808A-D6832BF3F291} = {E2D9AE26-4F0F-4D09-BFD2-434DE9BDF433} {31DC2EF8-C3FE-467D-84BE-FB5D956E6100} = {E2D9AE26-4F0F-4D09-BFD2-434DE9BDF433} + {1C326CF6-DEC2-4538-B46E-B045D3F7AFC3} = {0C331956-D83C-4A5C-8A73-6B948ADEA559} + {D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2} = {0C331956-D83C-4A5C-8A73-6B948ADEA559} + {28876979-CB85-44E4-96F1-537845257964} = {0C331956-D83C-4A5C-8A73-6B948ADEA559} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {66C0CAE3-D093-4276-BCAC-BC3749408CE9} diff --git a/src/XPath2.Extensions.Core/FunctionTableExtensions.cs b/src/XPath2.Extensions.Core/FunctionTableExtensions.cs new file mode 100644 index 0000000..5e3868e --- /dev/null +++ b/src/XPath2.Extensions.Core/FunctionTableExtensions.cs @@ -0,0 +1,138 @@ +using System; +using System.Text; +using Wmhelp.XPath2.MS; + +namespace Wmhelp.XPath2.Extensions.Core +{ + public static class FunctionTableExtensions + { + /// + /// Extend the XPath2 FunctionTable with: + /// - generate-id + /// - base64encode + /// - base64decode + /// + /// The function table. + public static void AddCoreExtensions(this FunctionTable functionTable) + { + functionTable.AddGenerateId(); + functionTable.AddBase64Encode(); + functionTable.AddBase64Decode(); + } + + /// + /// Extend the XPath2 FunctionTable with 'generate-id' function to generate a Guid (http://www.w3schools.com/xsl/func_generateid.asp) + /// + /// The function table. + public static void AddGenerateId(this FunctionTable functionTable) + { + functionTable.Add(XmlReservedNs.NsXQueryFunc, "generate-id", 0, XPath2ResultType.String, (context, provider, args) => Guid.NewGuid().ToString().ToLower()); + } + + /// + /// Extend the XPath2 FunctionTable with 'base64encode' function to encode a string to base64 string. + /// + /// The function table. + public static void AddBase64Encode(this FunctionTable functionTable) + { + string Base64EncodeDelegate(XPath2Context context, IContextProvider provider, object[] args) + { + string value = CoreFuncs.CastToStringExactOne(context, args[0]); + Encoding encoding = args.Length == 2 ? ParseEncodingFromArg(context, args[1]) : Encoding.UTF8; + + try + { + return Convert.ToBase64String(encoding.GetBytes(value)); + } + catch (Exception ex) + { + throw new XPath2Exception("InvalidFormat", ex); + } + } + + // base64encode with default UTF-8 encoding + functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64encode", 1, XPath2ResultType.String, Base64EncodeDelegate); + + // base64encode with specified encoding + functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64encode", 2, XPath2ResultType.String, Base64EncodeDelegate); + } + + /// + /// Extend the XPath2 FunctionTable with 'base64decode' function to decode a base64 string to a string. + /// + /// The function table. + public static void AddBase64Decode(this FunctionTable functionTable) + { + string Base64DecodeDelegate(XPath2Context context, IContextProvider provider, object[] args) + { + bool fixPadding = true; + Encoding encoding = Encoding.UTF8; + string value = CoreFuncs.CastToStringExactOne(context, args[0]); + + if (args.Length == 2) + { + try + { + // first try to cast to bool + fixPadding = CoreFuncs.GetBooleanValue(args[1]); + } + catch (Exception) + { + // else parse as encoding + encoding = ParseEncodingFromArg(context, args[1]); + } + } + + if (args.Length == 3) + { + encoding = ParseEncodingFromArg(context, args[1]); + fixPadding = CoreFuncs.GetBooleanValue(args[2]); + } + + if (fixPadding) + { + value = value.Trim('='); + int mod = value.Length % 4; + if (mod != 0) + { + value = string.Concat(value, new string('=', 4 - mod)); + } + } + + try + { + return encoding.GetString(Convert.FromBase64String(value)); + } + catch (Exception ex) + { + throw new XPath2Exception("InvalidFormat", ex.Message); + } + } + + // base64decode with default UTF-8 encoding + functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64decode", 1, XPath2ResultType.String, Base64DecodeDelegate); + + // base64decode with specified encoding (string) or fixPadding (bool) + functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64decode", 2, XPath2ResultType.String, Base64DecodeDelegate); + + // base64decode with specified encoding (string) and fixPadding (bool) + functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64decode", 3, XPath2ResultType.String, Base64DecodeDelegate); + } + + #region private helper methods + private static Encoding ParseEncodingFromArg(XPath2Context context, object arg) + { + string name = CoreFuncs.CastToStringOptional(context, arg); + + try + { + return Encoding.GetEncoding(name); + } + catch (Exception) + { + throw new XPath2Exception("FORG0001", Properties.Resources.FORG0001, name, "Encoding.GetEncoding()"); + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/XPath2.Extensions.Core/Properties/AssemblyInfo.cs b/src/XPath2.Extensions.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4e3bc41 --- /dev/null +++ b/src/XPath2.Extensions.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("XPath2.Extensions.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("XPath2.Extensions.Core")] +[assembly: AssemblyCopyright("Copyright © Stef Heyenrath 2021-2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("A2279454-fc88-44fe-b037-b514ab23c2b0")] diff --git a/src/XPath2.Extensions.Core/XPath2.Extensions.Core.csproj b/src/XPath2.Extensions.Core/XPath2.Extensions.Core.csproj new file mode 100644 index 0000000..6a43070 --- /dev/null +++ b/src/XPath2.Extensions.Core/XPath2.Extensions.Core.csproj @@ -0,0 +1,72 @@ + + + + + Non-official Newtonsoft.Json extensions for XPath2.dll (generate-id, base64encode and base64decode) + Stef Heyenrath + Non-official Newtonsoft.Json extensions for XPath2.dll + Stef Heyenrath + net35;net40;net452;netstandard2.0;netstandard2.1 + XPath2.Extensions.Core + XPath2.Extensions.Core + XPath;XPath2;XPath2.0;Xml;W3C;XQuery;XQTS;Extensions + See ReleaseNotes.md + https://raw.githubusercontent.com/StefH/XPath2.Net/master/resources/XPath2ex-icon-64x64.png + https://github.com/StefH/XPath2.Net + MIT + false + false + false + false + false + false + Wmhelp.XPath2.Extensions.Core + full + ../XPath2.snk + true + {A1326CF6-DEC2-4538-B46E-B045D3F7AFC3} + true + + + + net40;net452;netstandard2.0;netstandard2.1 + + + + true + + + + + + + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2 + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/XPath2.Extensions.NewtonsoftJson/FunctionTableExtensions.cs b/src/XPath2.Extensions.NewtonsoftJson/FunctionTableExtensions.cs new file mode 100644 index 0000000..9105e0c --- /dev/null +++ b/src/XPath2.Extensions.NewtonsoftJson/FunctionTableExtensions.cs @@ -0,0 +1,49 @@ +using System.Xml; +using System.Xml.XPath; +using JetBrains.Annotations; +using Wmhelp.XPath2.MS; + +namespace Wmhelp.XPath2.Extensions +{ + public static class FunctionTableExtensions + { + /// + /// Extend the XPath2 FunctionTable with: + /// - json-to-xml + /// - json-to-xmlstring + /// + /// The function table. + public static void AddJsonToXml([NotNull] this FunctionTable functionTable) + { + XPathNavigator JsonStringToXPathNavigator(XPath2Context context, IContextProvider provider, object[] args) + { + string value = CoreFuncs.CastToStringExactOne(context, args[0]); + string root = args.Length == 2 ? CoreFuncs.CastToStringOptional(context, args[1]) : null; + + string dynamicRootObject; + XmlNode xmlDoc = Json2XmlUtils.Json2XmlNode(value, out dynamicRootObject, root); + + return xmlDoc?.CreateNavigator(); + } + + string JsonStringToXmlString(XPath2Context context, IContextProvider provider, object[] args) + { + var nav = JsonStringToXPathNavigator(context, provider, args); + + return nav != null ? nav.InnerXml : string.Empty; + } + + // json-to-xml with no root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xml", 1, XPath2ResultType.Navigator, JsonStringToXPathNavigator); + + // json-to-xml with specified root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xml", 2, XPath2ResultType.Navigator, JsonStringToXPathNavigator); + + // json-to-xmlstring with no root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xmlstring", 1, XPath2ResultType.String, JsonStringToXmlString); + + // json-to-xmlstring with specified root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xmlstring", 2, XPath2ResultType.String, JsonStringToXmlString); + } + } +} \ No newline at end of file diff --git a/src/XPath2.Extensions/Json2XmlUtils.cs b/src/XPath2.Extensions.NewtonsoftJson/Json2XmlUtils.cs similarity index 100% rename from src/XPath2.Extensions/Json2XmlUtils.cs rename to src/XPath2.Extensions.NewtonsoftJson/Json2XmlUtils.cs diff --git a/src/XPath2.Extensions.NewtonsoftJson/Properties/AssemblyInfo.cs b/src/XPath2.Extensions.NewtonsoftJson/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d54a6a9 --- /dev/null +++ b/src/XPath2.Extensions.NewtonsoftJson/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("XPath2.Extensions.NewtonsoftJson")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("XPath2.Extensions.NewtonsoftJson")] +[assembly: AssemblyCopyright("Copyright © Stef Heyenrath 2021-2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("12279454-fc88-44fe-b037-b514ab23c2bf")] diff --git a/src/XPath2.Extensions.NewtonsoftJson/XPath2.Extensions.NewtonsoftJson.csproj b/src/XPath2.Extensions.NewtonsoftJson/XPath2.Extensions.NewtonsoftJson.csproj new file mode 100644 index 0000000..55b30f6 --- /dev/null +++ b/src/XPath2.Extensions.NewtonsoftJson/XPath2.Extensions.NewtonsoftJson.csproj @@ -0,0 +1,77 @@ + + + + + Non-official Newtonsoft.Json extensions for XPath2.dll (json-to-xml and json-to-xmlstring) + Stef Heyenrath + Non-official Newtonsoft.Json extensions for XPath2.dll + Stef Heyenrath + net35;net40;net452;netstandard2.0;netstandard2.1 + XPath2.Extensions.NewtonsoftJson + XPath2.Extensions.NewtonsoftJson + XPath;XPath2;XPath2.0;Xml;W3C;XQuery;XQTS;Extensions + See ReleaseNotes.md + https://raw.githubusercontent.com/StefH/XPath2.Net/master/resources/XPath2ex-icon-64x64.png + https://github.com/StefH/XPath2.Net + MIT + false + false + false + false + false + false + XPath2.Extensions.NewtonsoftJson + full + ../XPath2.snk + true + {D267CE1F-60E1-47F4-82EE-6FF3CBED9BA2} + true + + + + net40;net452;netstandard2.0;netstandard2.1 + + + + true + + + + + + + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2 + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/XPath2.Extensions.SystemTextJson/FunctionTableExtensions.cs b/src/XPath2.Extensions.SystemTextJson/FunctionTableExtensions.cs new file mode 100644 index 0000000..9105e0c --- /dev/null +++ b/src/XPath2.Extensions.SystemTextJson/FunctionTableExtensions.cs @@ -0,0 +1,49 @@ +using System.Xml; +using System.Xml.XPath; +using JetBrains.Annotations; +using Wmhelp.XPath2.MS; + +namespace Wmhelp.XPath2.Extensions +{ + public static class FunctionTableExtensions + { + /// + /// Extend the XPath2 FunctionTable with: + /// - json-to-xml + /// - json-to-xmlstring + /// + /// The function table. + public static void AddJsonToXml([NotNull] this FunctionTable functionTable) + { + XPathNavigator JsonStringToXPathNavigator(XPath2Context context, IContextProvider provider, object[] args) + { + string value = CoreFuncs.CastToStringExactOne(context, args[0]); + string root = args.Length == 2 ? CoreFuncs.CastToStringOptional(context, args[1]) : null; + + string dynamicRootObject; + XmlNode xmlDoc = Json2XmlUtils.Json2XmlNode(value, out dynamicRootObject, root); + + return xmlDoc?.CreateNavigator(); + } + + string JsonStringToXmlString(XPath2Context context, IContextProvider provider, object[] args) + { + var nav = JsonStringToXPathNavigator(context, provider, args); + + return nav != null ? nav.InnerXml : string.Empty; + } + + // json-to-xml with no root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xml", 1, XPath2ResultType.Navigator, JsonStringToXPathNavigator); + + // json-to-xml with specified root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xml", 2, XPath2ResultType.Navigator, JsonStringToXPathNavigator); + + // json-to-xmlstring with no root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xmlstring", 1, XPath2ResultType.String, JsonStringToXmlString); + + // json-to-xmlstring with specified root element + functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xmlstring", 2, XPath2ResultType.String, JsonStringToXmlString); + } + } +} \ No newline at end of file diff --git a/src/XPath2.Extensions.SystemTextJson/Json2XmlUtils.cs b/src/XPath2.Extensions.SystemTextJson/Json2XmlUtils.cs new file mode 100644 index 0000000..d8cbaeb --- /dev/null +++ b/src/XPath2.Extensions.SystemTextJson/Json2XmlUtils.cs @@ -0,0 +1,123 @@ +using System.Xml; + +namespace Wmhelp.XPath2.Extensions +{ + public static class Json2XmlUtils + { + private const string DefaultDynamicArray = "DynamicArray"; + private const string DefaultDynamicObject = "DynamicObject"; + + /// + /// Converts Json string to a XmlNode. + /// + /// The json. + /// Name of the root object (default null). + /// XmlNode + public static XmlNode Json2XmlNode(string json, string rootObjectName = null) + { + string dynamicRootObject; + return Json2XmlNode(json, out dynamicRootObject, rootObjectName); + } + + /// + /// Converts Json string to a XmlNode. + /// + /// The json. + /// The value for the dynamicRootObject which is used. + /// Name of the root object (default null). + /// XmlNode + public static XmlNode Json2XmlNode(string json, out string dynamicRootObject, string rootObjectName = null) + { + dynamicRootObject = null; + if (string.IsNullOrEmpty(json)) + { + return null; + } + + // Trim json string + json = json.Trim(); + + // In case the json response is an array, wrap the array in a fake RootObject to avoid + // the exception : XmlNodeConverter can only convert JSON that begins with an object. + if (json.StartsWith("[") && json.EndsWith("]")) + { + json = $"{{\"{DefaultDynamicObject}\":{json}}}"; + + if (string.IsNullOrEmpty(rootObjectName)) + { + rootObjectName = DefaultDynamicArray; + dynamicRootObject = rootObjectName; + } + } + + XmlNode node; + + // Try to convert the Json to a XmlNode + if (TryDeserializeJsonToXmlNode(json, rootObjectName, out node)) + { + return node; + } + + // If there is an error like : "JSON root object has multiple properties.", use a default rootname + if (string.IsNullOrEmpty(rootObjectName) && TryDeserializeJsonToXmlNode(json, DefaultDynamicObject, out node)) + { + dynamicRootObject = DefaultDynamicObject; + return node; + } + + // If this also fails, just return null + return null; + } + + /// + /// Tries the deserialize json to XmlNode. + /// + /// The json. + /// Name of the root object. + /// The node. + /// true if success, else false + public static bool TryDeserializeJsonToXmlNode(string json, string rootObjectName, out XmlNode node) + { + node = null; + + try + { + // If rootObjectName is specified, use that name. Else use no rootObjectName + node = !string.IsNullOrEmpty(rootObjectName) ? DeserializeXmlNode(json, rootObjectName) : DeserializeXmlNode(json); + } + catch + { + return false; + } + + return true; + } + + /// + /// Deserializes the XmlNode from a JSON string nested in a root elment specified by . + /// Note that DateParseHandling is set to DateParseHandling.None to avoid issues with DateTime strings when converting json to xml. + /// + /// The JSON string. + /// The name of the root element to append when deserializing. + /// The deserialized XmlNode + private static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName = null) + { + var nodeConvertor = new XmlNodeConverter + { + DeserializeRootElementName = deserializeRootElementName, + WriteArrayAttribute = false + }; + + var serializerSettings = new JsonSerializerOptions + { + Converters = new[] + { + (JsonConverter) nodeConvertor + }, + DateParseHandling = DateParseHandling.None + }; + + return (XmlDocument)JsonSe.DeserializeObject(value, typeof(XmlDocument), serializerSettings); + } + } +} \ No newline at end of file diff --git a/src/XPath2.Extensions.SystemTextJson/Properties/AssemblyInfo.cs b/src/XPath2.Extensions.SystemTextJson/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2230ebd --- /dev/null +++ b/src/XPath2.Extensions.SystemTextJson/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("XPath2.Extensions")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("XPath2.Extensions")] +[assembly: AssemblyCopyright("Copyright © Stef Heyenrath 2021-2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("AAA79454-fc88-44fe-b037-b514ab23c2b0")] diff --git a/src/XPath2.Extensions.SystemTextJson/XPath2.Extensions.SystemTextJson.csproj b/src/XPath2.Extensions.SystemTextJson/XPath2.Extensions.SystemTextJson.csproj new file mode 100644 index 0000000..25848af --- /dev/null +++ b/src/XPath2.Extensions.SystemTextJson/XPath2.Extensions.SystemTextJson.csproj @@ -0,0 +1,72 @@ + + + + + Non-official System.Text.Json extensions for XPath2.dll (json-to-xml and json-to-xmlstring) + Stef Heyenrath + Non-official System.Text.Json extensions for XPath2.dll + Stef Heyenrath + net461;netstandard2.0;netstandard2.1 + XPath2.Extensions.SystemTextJson + XPath2.Extensions.SystemTextJson + XPath;XPath2;XPath2.0;Xml;W3C;XQuery;XQTS;Extensions + See ReleaseNotes.md + https://raw.githubusercontent.com/StefH/XPath2.Net/master/resources/XPath2ex-icon-64x64.png + https://github.com/StefH/XPath2.Net + MIT + false + false + false + false + false + false + XPath2.Extensions.SystemTextJson + full + ../XPath2.snk + true + {28876979-CB85-44E4-96F1-537845257964} + true + + + + net40;net452;netstandard2.0;netstandard2.1 + + + + true + + + + + + + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2 + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/XPath2.Extensions/FunctionTableExtensions.cs b/src/XPath2.Extensions/FunctionTableExtensions.cs index d1cb963..13bbb96 100644 --- a/src/XPath2.Extensions/FunctionTableExtensions.cs +++ b/src/XPath2.Extensions/FunctionTableExtensions.cs @@ -1,9 +1,4 @@ -using System; -using System.Text; -using System.Xml; -using System.Xml.XPath; -using JetBrains.Annotations; -using Wmhelp.XPath2.MS; +using Wmhelp.XPath2.Extensions.Core; namespace Wmhelp.XPath2.Extensions { @@ -20,160 +15,8 @@ public static class FunctionTableExtensions /// The function table. public static void AddAllExtensions(this FunctionTable functionTable) { - functionTable.AddGenerateId(); - functionTable.AddBase64Encode(); - functionTable.AddBase64Decode(); + functionTable.AddCoreExtensions(); functionTable.AddJsonToXml(); } - - /// - /// Extend the XPath2 FunctionTable with 'generate-id' function to generate a Guid (http://www.w3schools.com/xsl/func_generateid.asp) - /// - /// The function table. - public static void AddGenerateId(this FunctionTable functionTable) - { - functionTable.Add(XmlReservedNs.NsXQueryFunc, "generate-id", 0, XPath2ResultType.String, (context, provider, args) => Guid.NewGuid().ToString().ToLower()); - } - - /// - /// Extend the XPath2 FunctionTable with 'base64encode' function to encode a string to base64 string. - /// - /// The function table. - public static void AddBase64Encode(this FunctionTable functionTable) - { - string Base64EncodeDelegate(XPath2Context context, IContextProvider provider, object[] args) - { - string value = CoreFuncs.CastToStringExactOne(context, args[0]); - Encoding encoding = args.Length == 2 ? ParseEncodingFromArg(context, args[1]) : Encoding.UTF8; - - try - { - return Convert.ToBase64String(encoding.GetBytes(value)); - } - catch (Exception ex) - { - throw new XPath2Exception("InvalidFormat", ex); - } - } - - // base64encode with default UTF-8 encoding - functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64encode", 1, XPath2ResultType.String, Base64EncodeDelegate); - - // base64encode with specified encoding - functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64encode", 2, XPath2ResultType.String, Base64EncodeDelegate); - } - - /// - /// Extend the XPath2 FunctionTable with 'base64decode' function to decode a base64 string to a string. - /// - /// The function table. - public static void AddBase64Decode(this FunctionTable functionTable) - { - string Base64DecodeDelegate(XPath2Context context, IContextProvider provider, object[] args) - { - bool fixPadding = true; - Encoding encoding = Encoding.UTF8; - string value = CoreFuncs.CastToStringExactOne(context, args[0]); - - if (args.Length == 2) - { - try - { - // first try to cast to bool - fixPadding = CoreFuncs.GetBooleanValue(args[1]); - } - catch (Exception) - { - // else parse as encoding - encoding = ParseEncodingFromArg(context, args[1]); - } - } - - if (args.Length == 3) - { - encoding = ParseEncodingFromArg(context, args[1]); - fixPadding = CoreFuncs.GetBooleanValue(args[2]); - } - - if (fixPadding) - { - value = value.Trim('='); - int mod = value.Length % 4; - if (mod != 0) - value = string.Concat(value, new string('=', 4 - mod)); - } - - try - { - return encoding.GetString(Convert.FromBase64String(value)); - } - catch (Exception ex) - { - throw new XPath2Exception("InvalidFormat", ex.Message); - } - } - - // base64decode with default UTF-8 encoding - functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64decode", 1, XPath2ResultType.String, Base64DecodeDelegate); - - // base64decode with specified encoding (string) or fixPadding (bool) - functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64decode", 2, XPath2ResultType.String, Base64DecodeDelegate); - - // base64decode with specified encoding (string) and fixPadding (bool) - functionTable.Add(XmlReservedNs.NsXQueryFunc, "base64decode", 3, XPath2ResultType.String, Base64DecodeDelegate); - } - - /// - /// Extend the XPath2 FunctionTable with 'json-to-xml' functions - /// - /// The function table. - public static void AddJsonToXml([NotNull] this FunctionTable functionTable) - { - XPathNavigator JsonStringToXPathNavigator(XPath2Context context, IContextProvider provider, object[] args) - { - string value = CoreFuncs.CastToStringExactOne(context, args[0]); - string root = args.Length == 2 ? CoreFuncs.CastToStringOptional(context, args[1]) : null; - - string dynamicRootObject; - XmlNode xmlDoc = Json2XmlUtils.Json2XmlNode(value, out dynamicRootObject, root); - - return xmlDoc?.CreateNavigator(); - } - - string JsonStringToXmlString(XPath2Context context, IContextProvider provider, object[] args) - { - var nav = JsonStringToXPathNavigator(context, provider, args); - - return nav != null ? nav.InnerXml : string.Empty; - } - - // json-to-xml with no root element - functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xml", 1, XPath2ResultType.Navigator, JsonStringToXPathNavigator); - - // json-to-xml with specified root element - functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xml", 2, XPath2ResultType.Navigator, JsonStringToXPathNavigator); - - // json-to-xmlstring with no root element - functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xmlstring", 1, XPath2ResultType.String, JsonStringToXmlString); - - // json-to-xmlstring with specified root element - functionTable.Add(XmlReservedNs.NsXQueryFunc, "json-to-xmlstring", 2, XPath2ResultType.String, JsonStringToXmlString); - } - - #region private helper methods - private static Encoding ParseEncodingFromArg(XPath2Context context, object arg) - { - string name = CoreFuncs.CastToStringOptional(context, arg); - - try - { - return Encoding.GetEncoding(name); - } - catch (Exception) - { - throw new XPath2Exception("FORG0001", Properties.Resources.FORG0001, name, "Encoding.GetEncoding()"); - } - } - #endregion } } \ No newline at end of file diff --git a/src/XPath2.Extensions/XPath2.Extensions.csproj b/src/XPath2.Extensions/XPath2.Extensions.csproj index 3ebb6a5..1b4e0a9 100644 --- a/src/XPath2.Extensions/XPath2.Extensions.csproj +++ b/src/XPath2.Extensions/XPath2.Extensions.csproj @@ -2,7 +2,7 @@ 1.1.0.0 - Non-official extensions for XPath2.dll + Non-official extensions for XPath2.dll (generate-id, base64encode, base64decode, json-to-xml and json-to-xmlstring) Stef Heyenrath Non-official extensions for XPath2.dll Stef Heyenrath @@ -51,6 +51,8 @@ + + @@ -61,23 +63,11 @@ - - + - - - - - - - - - - - \ No newline at end of file diff --git a/src/XQTSRunConsole/XQTSRunConsole.csproj b/src/XQTSRunConsole/XQTSRunConsole.csproj index 7ff3ee8..413b82d 100644 --- a/src/XQTSRunConsole/XQTSRunConsole.csproj +++ b/src/XQTSRunConsole/XQTSRunConsole.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp3.1