Null Value on Xml Deserialization Using [Xmlattribute]

Null value on xml deserialization using [XmlAttribute]

In the example XML file org_name is an XML element, not an XML attribute. Changing
[XmlAttribute("org_name")]
to [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);
}

Sample Image

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 the archimate: namespace, but its child elements are not in any namespace, since the archimate: namespace is not the default namespace. Thus it's necessary to indicate to XmlSerializer that these child elements are in a different namespace from their parent. Setting XmlElementAttribute.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. The xsi: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 the xsi: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 class BusinessInterface. 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



Leave a reply



Submit