diff --git a/Frends.JSON.ConvertXMLStringToJToken/CHANGELOG.md b/Frends.JSON.ConvertXMLStringToJToken/CHANGELOG.md
index 20be4d0..c0835d4 100644
--- a/Frends.JSON.ConvertXMLStringToJToken/CHANGELOG.md
+++ b/Frends.JSON.ConvertXMLStringToJToken/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## [1.2.0] - 2026-05-07
+### Added
+- Added optional XSD input support to ensure consistent array/object mapping
+
## [1.1.0] - 2024-08-20
### Updated
- Updated Newtonsoft.Json library to the latest version 13.0.3.
@@ -10,4 +14,4 @@
## [1.0.0] - 2023-02-13
### Added
-- Initial implementation
\ No newline at end of file
+- Initial implementation
diff --git a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.Tests/UnitTests.cs b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.Tests/UnitTests.cs
index 77a4a9a..9149b9f 100644
--- a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.Tests/UnitTests.cs
+++ b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.Tests/UnitTests.cs
@@ -29,4 +29,48 @@ public void ShouldConvertXmlStringToJToken()
Assert.IsTrue(result.Success);
Assert.IsInstanceOfType(result.Jtoken, typeof(JObject));
}
-}
\ No newline at end of file
+
+ [TestMethod]
+ public void ShouldUseXsdToMapSingleElementAsArray()
+ {
+ var input = new Input()
+ {
+ XML = @"
+
+
+ Alan
+
+ ",
+ XSD = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "
+ };
+
+ var result = JSON.ConvertXMLStringToJToken(input);
+ var root = ((JObject)result.Jtoken)["root"];
+
+ Assert.IsTrue(result.Success);
+ Assert.IsNotNull(root);
+ Assert.IsInstanceOfType(root["person"], typeof(JArray));
+
+ var persons = root["person"] as JArray;
+
+ Assert.IsNotNull(persons);
+
+ Assert.AreEqual(1, persons.Count);
+ Assert.AreEqual("Alan", persons[0]["name"]?.ToString());
+ }
+}
diff --git a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/ConvertXMLStringToJToken.cs b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/ConvertXMLStringToJToken.cs
index d03892e..e9731f4 100644
--- a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/ConvertXMLStringToJToken.cs
+++ b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/ConvertXMLStringToJToken.cs
@@ -1,8 +1,12 @@
-using Frends.JSON.ConvertXMLStringToJToken.Definitions;
+using Frends.JSON.ConvertXMLStringToJToken.Definitions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.ComponentModel;
+using System.IO;
+using System.Linq;
using System.Xml;
+using System.Xml.Linq;
+using System.Xml.Schema;
namespace Frends.JSON.ConvertXMLStringToJToken;
@@ -11,6 +15,8 @@ namespace Frends.JSON.ConvertXMLStringToJToken;
///
public class JSON
{
+ private const string JsonNamespace = "http://james.newtonking.com/projects/json";
+
///
/// Convert XML string to JToken.
/// [Documentation](https://tasks.frends.com/tasks/frends-tasks/Frends.JSON.ConvertXMLStringToJToken)
@@ -19,9 +25,85 @@ public class JSON
/// Object { bool Success, object Jtoken }
public static Result ConvertXMLStringToJToken([PropertyTab] Input input)
{
- var doc = new XmlDocument();
- doc.LoadXml(input.XML);
+ var doc = string.IsNullOrWhiteSpace(input.XSD)
+ ? LoadXmlDocument(input.XML)
+ : LoadXmlDocumentWithSchemaHints(input.XML, input.XSD);
+
var jsonString = JsonConvert.SerializeXmlNode(doc);
return new Result(true, JToken.Parse(jsonString));
}
-}
\ No newline at end of file
+
+ private static XmlDocument LoadXmlDocument(string xml)
+ {
+ var doc = new XmlDocument();
+ doc.LoadXml(xml);
+ return doc;
+ }
+
+ private static XmlDocument LoadXmlDocumentWithSchemaHints(string xml, string xsd)
+ {
+ var schemaSet = CreateSchemaSet(xsd);
+
+ var xDocument = XDocument.Parse(xml);
+
+ xDocument.Validate(
+ schemaSet,
+ (sender, args) =>
+ {
+ throw new XmlSchemaValidationException(
+ $"XML schema validation failed: {args.Message}",
+ args.Exception);
+ },
+ true);
+
+ AddJsonArrayAttributesFromSchema(xDocument);
+
+ var xmlDocument = new XmlDocument();
+
+ using var reader = xDocument.CreateReader();
+ xmlDocument.Load(reader);
+
+ return xmlDocument;
+ }
+
+ private static XmlSchemaSet CreateSchemaSet(string xsd)
+ {
+ var schemaSet = new XmlSchemaSet();
+ using var schemaReader = XmlReader.Create(new StringReader(xsd));
+ schemaSet.Add(null, schemaReader);
+ schemaSet.Compile();
+ return schemaSet;
+ }
+
+ private static void AddJsonArrayAttributesFromSchema(XDocument document)
+ {
+ if (document.Root == null)
+ return;
+
+ XNamespace jsonNs = JsonNamespace;
+ var hasArray = false;
+
+ foreach (var element in document.Root.DescendantsAndSelf())
+ {
+ var schemaElement = element.GetSchemaInfo()?.SchemaElement;
+
+ if (schemaElement?.MaxOccurs > 1m)
+ {
+ element.SetAttributeValue(jsonNs + "Array", "true");
+ hasArray = true;
+ }
+ }
+
+ var existing = document.Root.Attributes()
+ .FirstOrDefault(a =>
+ a.IsNamespaceDeclaration &&
+ a.Value == JsonNamespace);
+
+ if (hasArray && existing == null)
+ {
+ document.Root.SetAttributeValue(
+ XNamespace.Xmlns + "json",
+ JsonNamespace);
+ }
+ }
+}
diff --git a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Definitions/Input.cs b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Definitions/Input.cs
index bb92971..2f21d84 100644
--- a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Definitions/Input.cs
+++ b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Definitions/Input.cs
@@ -10,4 +10,13 @@ public class Input
///
/// <?xml version='1.0' standalone='no'?><root><foos id = '1' ><foo>bar</name></foos></root>
public string XML { get; set; }
-}
\ No newline at end of file
+
+ ///
+ /// Optional XSD schema used for XML validation and for determining
+ /// whether XML elements should be serialized as JSON arrays.
+ ///
+ ///
+ /// <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>...</xs:schema>
+ ///
+ public string XSD { get; set; }
+}
diff --git a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.csproj b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.csproj
index 6a0ddfb..a79bb1a 100644
--- a/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.csproj
+++ b/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken/Frends.JSON.ConvertXMLStringToJToken.csproj
@@ -2,7 +2,7 @@
net6.0
- 1.1.0
+ 1.2.0
Frends
Frends
Frends
@@ -24,4 +24,4 @@
-
\ No newline at end of file
+