Null value on xml deserialization using [XmlAttribute]
In the example XML file org_name
is an XML element, not an XML attribute. Changing
to
[XmlAttribute("org_name")][XmlElement("org_name")]
at the Organisation
property will deserialize it as an element:
[XmlElement("org_name")]
public string Organisation { get; set; }
Deserialize XML element returning null value
The missing setter for textChoiceList
property in the Text
class that leads to the text
was null
as the only property in the class is unable to set value.
So adding the missing setter to the property will solve the issue.
[XmlRoot("text")]
public class Text
{
[XmlElement("textChoiceList")]
public TextChoiceList textChoiceList { get; set; }
}
Sample .NET Fiddle
XML Deserialization is returning null for an xml attribute but is returning the correct Xml text
I ended up fixing it with the Nil property like @GeorgeBirbilis said and used it with @dbc's solution to manually naming the namespaces the z: and c: are from. I was only doing one or the other, not both combined. Thank you guys for the help.
[XmlAttribute(Namespace = "http://schemas.microsoft.com/2003/10/Serialization/")]
public int Id { get; set; }
[XmlAttribute(Namespace = "http://schemas.microsoft.com/2003/10/Serialization/")]
public int Ref { get; set; }
private bool _nil;
[XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public bool Nil
{
get
{
return _nil;
}
set
{
_nil = value;
}
}
Deserializing empty xml attribute value into nullable int property using XmlSerializer
I solved this problem by implementing IXmlSerializable interface. I did not found easier way.
Here is the test code sample:
[XmlRoot("root")]
public class DeserializeMe {
[XmlArray("elements"), XmlArrayItem("element")]
public List<Element> Element { get; set; }
}
public class Element : IXmlSerializable {
public int? Value1 { get; private set; }
public float? Value2 { get; private set; }
public void ReadXml(XmlReader reader) {
string attr1 = reader.GetAttribute("attr");
string attr2 = reader.GetAttribute("attr2");
reader.Read();
Value1 = ConvertToNullable<int>(attr1);
Value2 = ConvertToNullable<float>(attr2);
}
private static T? ConvertToNullable<T>(string inputValue) where T : struct {
if ( string.IsNullOrEmpty(inputValue) || inputValue.Trim().Length == 0 ) {
return null;
}
try {
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
return (T)conv.ConvertFrom(inputValue);
}
catch ( NotSupportedException ) {
// The conversion cannot be performed
return null;
}
}
public XmlSchema GetSchema() { return null; }
public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); }
}
class TestProgram {
public static void Main(string[] args) {
string xml = @"<root><elements><element attr='11' attr2='11.3'/><element attr='' attr2=''/></elements></root>";
XmlSerializer deserializer = new XmlSerializer(typeof(DeserializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (DeserializeMe)deserializer.Deserialize(xmlStream);
}
}
XML Deserialization: Use XmlAttribute and XmlText on a single property
Why do you won't use separated properties for node value and attribute value?
public class ArrayItem
{
[XmlAttribute("Value")]
public string ValueAttribute { get; set; }
[XmlText]
public string Value { get; set; }
}
With this example:
static void Main(string[] args)
{
ArrayTest arrayTest = new ArrayTest
{
Items = new ArrayItem[]
{
new ArrayItem{ Value = "Item1" },
new ArrayItem{ ValueAttribute = "Item2" }
}
};
XmlSerializer serializer = new XmlSerializer(typeof(ArrayTest));
using FileStream fs = new FileStream("MyFile.xml", FileMode.OpenOrCreate);
serializer.Serialize(fs, arrayTest);
}
It will give you desired output:
<?xml version="1.0"?>
<ArrayTest>
<ArrayItem>Item1</ArrayItem>
<ArrayItem Value="Item2" />
</ArrayTest>
Deserialization back from file works fine too:
using (FileStream fs = new FileStream("H:\\MyFile2.xml", FileMode.OpenOrCreate))
{
ArrayTest deserializedArrayTest = formatter.Deserialize(fs) as ArrayTest;
foreach (ArrayItem arrayItem in deserializedArrayTest.Items)
Console.WriteLine("Array item value: " + arrayItem.Value + "\n" +
"Array \"Value\" attribute value: " + arrayItem.ValueAttribute);
}
I think this approach and same namings will simply misle you sooner or later.
How to fix values being null when deserializing XML
You can deserialize your XML with the following data model:
[XmlRoot(ElementName = "model", Namespace = "http://www.archimatetool.com/archimate")]
[XmlType(Namespace = "http://www.archimatetool.com/archimate")]
public class Model
{
[XmlElement(ElementName = "folder", Form = XmlSchemaForm.Unqualified)]
public List<Folder> Folders { get; set; }
[XmlElement(ElementName = "purpose", Form = XmlSchemaForm.Unqualified)]
public string Purpose { get; set; }
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
[XmlAttribute(AttributeName = "version")]
public string Version { get; set; }
}
[XmlType(Namespace = "http://www.archimatetool.com/archimate")]
public class Folder
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
[XmlAttribute(AttributeName = "type")]
public string Type { get; set; }
[XmlElement(ElementName = "folder", Form = XmlSchemaForm.Unqualified)]
public List<Folder> Folders { get; set; }
[XmlElement(ElementName = "element", Form = XmlSchemaForm.Unqualified)]
public List<Element> Element { get; set; }
}
[XmlType(Namespace = "http://www.archimatetool.com/archimate")]
[XmlInclude(typeof(BusinessInterface))]
public abstract class Element
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}
[XmlType(TypeName = "BusinessInterface", Namespace = "http://www.archimatetool.com/archimate")]
public class BusinessInterface : Element
{
}
Notes:
The root element
<archimate:model>
is in thearchimate:
namespace, but its child elements are not in any namespace, since thearchimate:
namespace is not the default namespace. Thus it's necessary to indicate toXmlSerializer
that these child elements are in a different namespace from their parent. SettingXmlElementAttribute.Form = XmlSchemaForm.Unqualified
accomplishes this.(It is not necessary to specify that attributes are in the default namespace, since all XML attributes are assumed to be unqualified unless otherwise specified.)
The presence of the
xsi:type="archimate:BusinessInterface"
attribute indicates the<element>
attribute is part of a polymorphic type hierarchy. Thexsi:type
attribute is a standard w3c attribute that allows an element to explicitly assert its type.XmlSerializer
supports this attribute and in fact requires the presence of a subtype corresponding to thexsi:type
and declared through the[XmlInclude]
attribute.For details see How to: Control Serialization of Derived Classes.
Here I made an arbitrary choice of properties to include in the base class
Element
and the derived classBusinessInterface
. You may need to adjust this choice given a more complete XML sample.
Sample fiddle here.
Why do some attributes in Xml deserialization always return null?
Change
[XmlElement("arguments")]
public List<Argument> Arguments { get; set; }
to
[XmlArray("arguments")]
[XmlArrayItem("argument")]
public List<Argument> Arguments { get; set; }
Getting null in nested elements when deserializing xml
The easiest way to diagnose problems in XML deserialization is to serialize to XML and compare the observed XML with the required XML. Usually the problem will be immediately apparent.
If I create and serialize an instance of VideoGames
as follows:
var root = new VideoGames
{
Types = new []
{
new GameType
{
Name = "RPG",
Code = new []
{
new Code { Text = "TestingData" },
}
},
},
Platform = new Platform { Compressed = 3.2876m, },
};
var xml = root.GetXml(omitStandardNamespaces: true);
Console.WriteLine(xml);
Using the following extension method:
public static string GetXml<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = false)
{
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
{
ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
}
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
}
}
Then the output is:
<VideoGames>
<Types xmlns="http://www.specifiedcompany.com/API">
<Data Name="RPG">
<Code>
<Category Text="TestingData" />
</Code>
</Data>
</Types>
<Platform Compressed="3.2876" xmlns="http://www.specifiedcompany.com/API" />
</VideoGames>
Demo fiddle here.
As you can see, the child elements <Types>
and <Platform>
are all serialized in an XML namespace, specifically http://www.specifiedcompany.com/API
.
Your deserialization fails because, in the sample XML, these elements are not in any namespace.
Why is this happening? It's because all your classes including VideoGames
have an XmlTypeAttribute
attribute applied that specifies a Namespace
:
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.specifiedcompany.com/API")]
public partial class VideoGames
{
}
What this attribute does is to specify that by default, all properties of the type should be serialized into the specified namespace. (Compare with XmlRootAttribute
which specifies how the root element <VideoGames>
itself, rather than just its children, is to be serialized.)
If you don't want that, remove the XmlTypeAttribute.Namespace
setting from your c# classes VideoGames
, Platform
, GameType
and Code
(demo fiddle #2 here). If you do want that, modify your XML to include the required namespace as shown in the output XML in this answer.
XML attribute with namespace other than its parent's is deserialized as null
You are applying your namespace "http://sub.com"
element Child
, not to its value
attribute. In your XML, you specifically apply "http://main.com"
to both, Parent
and Child
. You can fix your namespaces like this:
[XmlRoot(ElementName = "Parent", Namespace = "http://main.com")]
public class Parent
{
[XmlElement(ElementName = "Child")]
public Child Child{ get; set; }
}
[XmlType(Namespace = "http://main.com")]
public class Child
{
[XmlAttribute(AttributeName = "value", Namespace = "http://sub.com")]
public string Value { get; set; }
}
Related Topics
Add Client Certificate to .Net Core Httpclient
Get All Column Names of a Datatable into String Array Using (Linq/Predicate)
How to Implement Async Task to Fetch Data from Database Using Async and Await
401 Unauthorized on Second Httpclient/Httpwebrequest Call
How to Set Value of Wpf Combobox Item from C# Code
How to Create a Dynamic Email Template That Can Be Modified Without Changing Code in C# .Net MVC
Instantiating an Iformfile from a Physical File
How to Delete All Files in an Azure File Storage Folder
Get and Post Methods With the Same Action Name in the Same Controller
How to Generate Unique Number of 8 Digits
How to Set the Query Timeout from SQL Connection String
How to Autosize the Height and the Width of C# Windows Form
Getting User Input and Adding It to an Array At C#
How to Iterate Through the Following Json Using C#
How to Acces an Instance of a Class from Another Class
Create Global Variable in .Net Core 2.0 to Use in Razor Views