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