ExtendedXmlSerializer / home

A configurable and eXtensible Xml serializer for .NET.
https://extendedxmlserializer.github.io/
MIT License
336 stars 47 forks source link

XmlArray Deserialize failed #540

Closed gsw945 closed 3 years ago

gsw945 commented 3 years ago

xml (file test.xml) content:

<?xml version="1.0" encoding="UTF-8"?>
<log>
<logentry
   revision="455">
<author>xxx</author>
<date>2021-02-14T08:34:31.679386Z</date>
<paths>
<path
   prop-mods="false"
   text-mods="true"
   kind="file"
   action="M">/Program/XXX/ViewerMain/Program.cs</path>
</paths>
<msg>some msg</msg>
</logentry>
<logentry
   revision="453">
<author>xxx</author>
<date>2021-02-14T08:15:18.507814Z</date>
<paths>
<path
   prop-mods="false"
   text-mods="true"
   kind="file"
   action="M">/Program/XXX/XXX.sln</path>
<path
   prop-mods="false"
   text-mods="true"
   kind="file"
   action="A">/Program/XXX/README.md</path>
<path
   prop-mods="false"
   text-mods="true"
   kind="file"
   action="M">/Program/XXX/ViewerMain/BdcLog.cs</path>
<path
   prop-mods="false"
   text-mods="true"
   kind="file"
   action="M">/Program/XXX/ViewerMain/Program.cs</path>
<path
   prop-mods="false"
   text-mods="true"
   kind="file"
   action="M">/Program/XXX/ViewerMain/ViewerMain.csproj</path>
</paths>
<msg>modify gui</msg>
</logentry>
</log>

core C# code:

using ExtendedXmlSerializer;
using ExtendedXmlSerializer.Configuration;
using ExtendedXmlSerializer.ContentModel;
using ExtendedXmlSerializer.ContentModel.Format;

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;

namespace Demo
{
   public class Test
   {
      [XmlType("log"), XmlRoot]
      public class SvnLog
      {
         [XmlArray]
         public LogEntry[] Entries { get; set; }
      }

      [XmlType("logentry")]
      public class LogEntry
      {
         [XmlAttribute("revision")]
         public string Revision { get; set; }

         [XmlElement("author")]
         public string Author { get; set; }

         [XmlElement("date")]
         public string Date { get; set; }

         [XmlElement("paths")]
         public LogPath[] Paths { get; set; }

         [XmlElement("msg")]
         public dynamic Message { get; set; }
      }

      [XmlType("path")]
      public class LogPath
      {
         [XmlAttribute("kind")]
         public string Kind { get; set; }

         [XmlAttribute("action")]
         public string Action { get; set; }

         [XmlAttribute("prop-mods")]
         public string PropMods { get; set; }

         [XmlAttribute("text-mods")]
         public string TextMods { get; set; }

         [XmlText]
         public string Path { get; set; }
      }

      static void Main(string[] args)
      {
         IExtendedXmlSerializer serializer = new ConfigurationContainer()
            .EnableImplicitTyping(typeof(SvnLog), typeof(LogEntry), typeof(LogPath))
            .WithUnknownContent().Continue()
            .Create();
         var xml = File.ReadAllText("@./test.xml", System.Text.Encoding.UTF8);
         var obj = serializer.Deserialize<SvnLog>(xml);
         Console.WriteLine(obj);
         Console.WriteLine($"obj.Entries is null: {obj.Entries == null}");
      }
   }
}

the output is:

Demo.Test+SvnLog
obj.Entries is null: True

I want read all logentry into obj.Entries.

@Mike-E-angelo need your help

Mike-E-angelo commented 3 years ago

Hi @gsw945 thank you for writing in with this. Unfortunately, this is a known issue with classic serialization, and can further be described in these issues for your review: #501, #461

I've tried my best to figure out a good way to solve this problem, but could not find a way to do it that involves rewriting the deserializer.

The best recommendation I can provide is to use XSLT to send the classic XML document through the transformation that produces the document that ExtendedXmlSerializer can process and then send that to ExtendedXmlSerializer. I know that is not ideal but given the circumstances and constraints (please see #383), that is the best I can offer.

Please do let me know if you have any questions/issues implementing the above and I will do my best to assist you.

gsw945 commented 3 years ago

I'm so sorry to give up ExtendedXmlSerializer temporary. I could only to use Newtonsoft.Json and quicktype:

// load xml content from file
var xml = File.ReadAllText("@./test.xml", System.Text.Encoding.UTF8);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);

// remove `<?xml version="1.0" encoding="UTF-8"?>`
if (xmlDoc.FirstChild?.NodeType == XmlNodeType.XmlDeclaration)
{
    xmlDoc.RemoveChild(xmlDoc.FirstChild);
}

// convert xml to json string
var jsonString = JsonConvert.SerializeXmlNode(xmlDoc, Newtonsoft.Json.Formatting.Indented, true);

// deserialization from json to SvnLog (SvnLog is generated via quicktype, input content is the jsonString)
var objLog = SvnLog.FromJson(jsonString);

quicktype usage screenshot as below: image

image

reference