I have a web service that is returning some xml. There is no corresponding xsd.
I used the Paste Special -> Paste XML as classes functionality in visual studio to generate the classes to use with XmlSerializer
:
When the code executes the line
--> XmlSerializer xmlSerialize = new XmlSerializer(typeof(table)); <--
table t = (table)xmlSerialize.Deserialize(new StringReader(soapResult));
it throws an exception:
System.InvalidOperationException: 'Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'string[]' to 'string'
error CS0029: Cannot implicitly convert type 'string' to 'string[]'
The generated classes look like so:
// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class table
{
private string[] labelField;
private string[] classnameField;
private string[] datatypeField;
private string[][] rowField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("d", IsNullable = false)]
public string[] label
{
get
{
return this.labelField;
}
set
{
this.labelField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("d", IsNullable = false)]
public string[] classname
{
get
{
return this.classnameField;
}
set
{
this.classnameField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("d", IsNullable = false)]
public string[] datatype
{
get
{
return this.datatypeField;
}
set
{
this.datatypeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("d", typeof(string), IsNullable = true)]
public string[][] row
{
get
{
return this.rowField;
}
set
{
this.rowField = value;
}
}
}
The problem is with the row field, as the others work ok. If I change
[System.Xml.Serialization.XmlArrayItemAttribute("d", typeof(string), IsNullable = true)]
to
[System.Xml.Serialization.XmlArrayItemAttribute("d", typeof(string[]), IsNullable = true)]
the error goes away, but my object just has an array of empty string arrays.
The XML data being deserialized (condensed for simplicity) looks like this
<?xml version="1.0" encoding="UTF-8"?>
<table>
<label>
<d>JobDefinition.SearchName</d>
<d>Job.JobDefinition</d>
</label>
<classname>
<d>JobDefinition.SearchName</d>
<d>Job.JobDefinition</d>
</classname>
<datatype>
<d>String</d>
<d>obj.JobDefinition</d>
</datatype>
<row>
<d>AB_DEFG_QA_RUN</d>
<d>A_JOB_Run</d>
</row>
<row>
<d>AB_DEFG_QA_RUN</d>
<d>B_JOB_Run</d>
</row>
</table>
Your problem looks identical to the one described in the Final Update of this answer to How to serialize List<List<object>>
?, namely that xsd.exe
(and thus Paste XML as Classes) is having trouble inferring a correct data model for XML containing a repeating element that contains nested repeating elements, here <row>
and <d>
:
<table>
<row>
<d>Value of repeating element inside a repeating element.</d>
<d>Value of repeating element inside a repeating element.</d>
</row>
<row>
<d>Value of repeating element inside a repeating element.</d>
<d>Value of repeating element inside a repeating element.</d>
</row>
</table>
The recommendation in that answer is to use a different code generation tool or construct the classes manually. I uploaded your XML to https://xmltocsharp.azurewebsites.net/ and, after merging duplicate classes, obtained the following data model:
[XmlRoot(ElementName = "row")]
public class Row
{
[XmlElement(ElementName = "d")]
public List<string> D { get; set; }
}
[XmlRoot(ElementName = "table")]
public class Table
{
[XmlElement(ElementName = "label")]
public Row Label { get; set; }
[XmlElement(ElementName = "classname")]
public Row Classname { get; set; }
[XmlElement(ElementName = "datatype")]
public Row Datatype { get; set; }
[XmlElement(ElementName = "row")]
public List<Row> Row { get; set; }
}
Using this I am able to deserialize and re-serialize your XML successfully without data loss. Notes:
Label
, Classname
, Datatype
and Row
. I decided to merge them all into a single Row
type, and use it for all the relevant members of Table
.Sample fiddle here.