diff --git a/Implab.Test/JsonTests.cs b/Implab.Test/JsonTests.cs --- a/Implab.Test/JsonTests.cs +++ b/Implab.Test/JsonTests.cs @@ -6,6 +6,7 @@ using System.Xml; using Implab.Formats; using Implab.Formats.Json; using System.IO; +using Implab.Test.Model; namespace Implab.Test { public class JsonTests { @@ -114,6 +115,44 @@ namespace Implab.Test { DumpJsonFlatParse("[1,2,\"\",[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]"); } + [Fact] + public void XmlToJsonTransform() { + var person = new Person { + FirstName = "Charlie", + LastName = "Brown", + Age = 19, + AgeSpecified = true + }; + + var doc = SerializationHelpers.SerializeAsXmlDocument(person); + + using (var writer = new StringWriter()) { + XmlToJson.Default.Transform(doc,null, writer); + Console.WriteLine(writer.ToString()); + } + } + + [Fact] + public void JsonSerialization() { + var person = new Person { + FirstName = "Charlie", + LastName = "Brown", + Age = 19, + AgeSpecified = true, + Tags = new [] { "brave", "stupid" } + }; + + var data = SerializationHelpers.SerializeJsonAsString(person); + Console.WriteLine(data); + var clone = SerializationHelpers.DeserializeJsonFromString(data); + + Assert.Equal(person.FirstName, clone.FirstName); + Assert.Equal(person.LastName, clone.LastName); + Assert.Equal(person.Age, clone.Age); + Assert.Equal(person.AgeSpecified, clone.AgeSpecified); + Assert.Equal(person.Tags, person.Tags); + } + void AssertRead(XmlReader reader, XmlNodeType expected) { Assert.True(reader.Read()); Console.WriteLine($"{new string(' ', reader.Depth * 2)}{reader}"); diff --git a/Implab.Test/Model/Person.cs b/Implab.Test/Model/Person.cs new file mode 100644 --- /dev/null +++ b/Implab.Test/Model/Person.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace Implab.Test.Model { + + [XmlRoot(Namespace="urn:implab:test:model")] + public class Person { + public string FirstName { get; set; } + + public string LastName { get; set; } + + public int Age { get; set; } + + [XmlIgnore] + public bool AgeSpecified { get; set; } + + + [XmlElement("Tag")] + public string[] Tags { get; set; } + } +} \ No newline at end of file diff --git a/Implab/Components/LazyAndWeak.cs b/Implab/Components/LazyAndWeak.cs --- a/Implab/Components/LazyAndWeak.cs +++ b/Implab/Components/LazyAndWeak.cs @@ -8,6 +8,7 @@ namespace Implab.Components { /// /// Usefull when dealing with memory-intensive objects which are frequently used. /// This class is similar to except it is a singleton. + /// This class can't be used to hold diposable objects. /// public class LazyAndWeak where T : class { diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj --- a/Implab/Implab.csproj +++ b/Implab/Implab.csproj @@ -19,4 +19,8 @@ NETFX_TRACE_BUG;$(DefineConstants) + + + + diff --git a/Implab/Xml/JsonXmlReader.cs b/Implab/Xml/JsonXmlReader.cs --- a/Implab/Xml/JsonXmlReader.cs +++ b/Implab/Xml/JsonXmlReader.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Xml; @@ -588,6 +589,12 @@ namespace Implab.Xml { return !skip; } + protected override void Dispose(bool disposing) { + if (disposing) + Safe.Dispose(m_parser); + base.Dispose(true); + } + public override string ToString() { switch (NodeType) { case XmlNodeType.Element: @@ -606,5 +613,24 @@ namespace Implab.Xml { return $".{NodeType} {Name} {Value}"; } } + + #region static methods + + public static JsonXmlReader CreateJsonXmlReader(TextReader textReader, JsonXmlReaderOptions options = null) { + var jsonReader = JsonReader.Create(textReader); + return new JsonXmlReader(jsonReader, options); + } + + public static JsonXmlReader CreateJsonXmlReader(Stream stream, JsonXmlReaderOptions options = null) { + var jsonReader = JsonReader.Create(stream); + return new JsonXmlReader(jsonReader, options); + } + + public static JsonXmlReader CreateJsonXmlReader(string file, JsonXmlReaderOptions options = null) { + var jsonReader = JsonReader.Create(file); + return new JsonXmlReader(jsonReader, options); + } + + #endregion } } diff --git a/Implab/Xml/SerializationHelpers.cs b/Implab/Xml/SerializationHelpers.cs --- a/Implab/Xml/SerializationHelpers.cs +++ b/Implab/Xml/SerializationHelpers.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; +using System.Xml.Serialization; namespace Implab.Xml { public static class SerializationHelpers { @@ -61,5 +63,34 @@ namespace Implab.Xml { using (var reader = node.CreateNavigator().ReadSubtree()) return SerializersPool.Instance.Deserialize(reader); } + + public static T DeserializeJson(TextReader textReader) { + var options = new JsonXmlReaderOptions { + NamespaceUri = typeof(T).GetCustomAttribute()?.Namespace, + RootName = typeof(T).Name, + FlattenArrays = true + }; + + using(var reader = JsonXmlReader.CreateJsonXmlReader(textReader, options)) + return Deserialize(reader); + } + + public static T DeserializeJsonFromString(string data) { + using(var reader = new StringReader(data)) { + return DeserializeJson(reader); + } + } + + public static void SerializeJson(TextWriter writer, T obj) { + var doc = SerializeAsXmlDocument(obj); + XmlToJson.Default.Transform(doc, null, writer); + } + + public static string SerializeJsonAsString(T obj) { + using(var writer = new StringWriter()) { + SerializeJson(writer, obj); + return writer.ToString(); + } + } } } diff --git a/Implab/Xml/XmlToJson.cs b/Implab/Xml/XmlToJson.cs new file mode 100644 --- /dev/null +++ b/Implab/Xml/XmlToJson.cs @@ -0,0 +1,33 @@ +using System; +using System.IO; +using System.Reflection; +using System.Xml; +using System.Xml.Xsl; +using Implab.Components; +using Implab.Formats.Json; + +namespace Implab.Xml { + public class XmlToJson { + const string XmlToJsonTransformId = "Implab.Xml.json.xsl"; + + static LazyAndWeak m_default = new LazyAndWeak(CreateTransform, true); + + public static XslCompiledTransform Default { + get { return m_default.Value; } + } + + protected static XslCompiledTransform CreateTransform() { + var transform = new XslCompiledTransform(); + using(var reader = XmlReader.Create(GetDefaultTransform())) { + transform.Load(reader); + } + return transform; + } + + protected static Stream GetDefaultTransform() { + return Assembly.GetExecutingAssembly().GetManifestResourceStream(XmlToJsonTransformId); + } + + + } +} \ No newline at end of file diff --git a/Implab/Xml/json.xsl b/Implab/Xml/json.xsl new file mode 100644 --- /dev/null +++ b/Implab/Xml/json.xsl @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + true + + + + false + + + + + + + + + + + + + + + + + + null + + + + + + + + + + + + + + + + : + + + + + + + + + + : + + + + + + + + + + + + : + + + + + + + , + + + + + + + " + + + + " + + + + + { + + } + + + + + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Implab/Xml/readme.txt b/Implab/Xml/readme.txt new file mode 100644 --- /dev/null +++ b/Implab/Xml/readme.txt @@ -0,0 +1,4 @@ +XML to JSON transform is taken from different project https://hg.implab.org/pub/ModelGenerator/ +run: + wget https://hg.implab.org/pub/ModelGenerator/raw-file/tip/xslt/json.xsl +to update to the latest version \ No newline at end of file