Why Can't I Deserialize This xml? - c#

I am currently trying to deserialize some XML in the following format:
<content:encoded>![CDATA[...
And I have an object which has a property which looks like:
[XmlElementAttribute("content")]
public string Content { get; set; }
However despite the XML always having a value the property in the code is always null?

content is a namespace in your example. Your element name is actually encoded so you will need to use the attribute marking your property as such:
[XmlElement("encoded", Namespace => "custom-content-namespace")]
public string Content { get; set; }
Note that you will need to declare the namespace in your containing XML:
<content:encoded xmlns:content="custom-content-namespace">![CDATA[...
This also means any child nodes would be prefixed with the same namespace. Not so much an issue for CDATA content, but just in case you have other elements you are trying to deserialize.
For a related questions to this, see Deserializing child nodes outside of parent's namespace using XmlSerializer.Deserialize() in C#

content is the namespace - encoded is the element name. So your XmlElementAttribute should be:
[XmlElement(Name="encoded", Namespace="<whatever namespace 'content' refers to in your XML>")]
public string Content { get; set; }

Related

How to change xml attribute while deserialization with xmlserializer c#?

Is there any way of modifying attribute value when deserializing xml using XmlSerializer?
For instance, I have such xml:
<chunkList>
<chunk id="ch1" type="p">
<sentence id="s1">
<tok>
<orth>XXX</orth>
<lex disamb="1">
<base>XXX</base>
<ctag>subst:sg:nom:f</ctag>
</lex>
</tok>
</sentence>
</chunk>
</chunkList>
I want to deserialize chunk element into Chunk class and set attribute id="ch1" to Id property - is there any way of trimming this ch substring and asigning number 1 to property of type int?
[XmlAttribute("id")] //maybe there is some attribute to achive this?
public int Id { get; set; }
I have read some of MSDN documentation but didn't found any solution.
There is no elegant way to achieve this using a single attribute. The only way I know to achieve the desired result is to make use of [XmlIgnore] and to create a second property specifically for the stringified xml ID, and a localized converter property for your internal integer value. Some along the lines of:
[XmlAttribute("id")]
public string _id_xml {get; set;}
[XmlIgnore]
public int Id {
// convert local copy of xml attribute value to/from int.
get => int.Parse(_id_xml.Replace("ch",""));
set => _id_xml = $"ch{value}";
}
My converter here is very basic and clearly you will need to improve it and consider error handling.
The serializer will operate against the [XmlAttribute] as normal, but pass over the [XmlIgnore]. Your c# code could use either.
Unfortunately, the XmlSerializer requires public properties, so you can not hide the _id_xml property from your code, but you could use [Obsolete] to signal a warning in the compiler.
You could do the conversion to/from int with the _id_xml getter & setter, but doing this could be problematic when managing errors during serialization.

Deserializing XML in C# where a property could be either an attribute or an element

I'm writing a C# library that, as one of its functions, needs to be able to accept XML of the following forms from a web service and deserialize them.
Form 1:
<results>
<sample>
<status>status message</status>
<name>sample name</name>
<igsn>unique identifier for this sample</igsn>
</sample>
</results>
Form 2:
<results>
<sample name="sample name">
<valid code="InvalidSample">no</valid>
<status>Not Saved</status>
<error>error message</error>
</sample>
</results>
Here's my class that I'm deserializing to:
namespace MyNamespace
{
[XmlRoot(ElementName = "results")]
public class SampleSubmissionResponse
{
[XmlElement("sample")]
public List<SampleSubmissionSampleResultRecord> SampleList { get; set; }
...
}
public class SampleSubmissionSampleResultRecord
{
...
/* RELEVANT PROPERTY RIGHT HERE */
[XmlAttribute(Attribute = "name")]
[XmlElement(ElementName = "name")]
public string Name { get; set; }
...
}
public class SampleSubmissionValidRecord
{
...
}
}
The problem is that in one XML sample, the name attribute of the Sample element is an element, and in the other it's an attribute. If I decorate the property of my class with both XmlAttribute and XmlElement, I get an exception thrown when creating an instance of XmlSerializer.
I've been googling for a good while now, and I can't find any docs that deal with this situation. I assume, but don't know for sure, that this is because when creating an XML schema, you're not supposed to use the same name for an attribute and a child element of the same element.
So, what do I do here?
One solution might be to have two totally separate models for the different types. That would probably work, but doesn't seem very elegant.
Another option might be to implement IXmlSerializable and write some elaborate code to handle this in the deserialize method. That would be an awfully verbose solution to a simple problem.
Third option I'm hoping for: some way of applying both XmlAttribute and XmlElement to the same property, or an equivalent "either-or" attribute.
Fourth option: Change the web service the XML comes from to use one form consistently. Unfortunately, the folks who own it may not be willing to do this.
Specify only one attribute to Name property. This will correctly parse out the first xml form.
public class SampleSubmissionSampleResultRecord
{
[XmlElement(ElementName = "name")]
public string Name { get; set; }
}
To parse the second xml form, subscribe the XmlSerializer to the UnknownAttribute event.
var xs = new XmlSerializer(typeof(SampleSubmissionResponse));
xs.UnknownAttribute += Xs_UnknownAttribute;
In the event handler, we get the desired value.
private void Xs_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
var record = (SampleSubmissionSampleResultRecord)e.ObjectBeingDeserialized;
record.Name = e.Attr.Value;
}

How can I update the property value in xml file which was serialized by custom object?

I have a serialized class which each property has the SerializableAttribute attribute applied.I can get the object deserilized from xml file and changing the content of properties in application.I want to save the content of changed object to orignal xml which deserilized from.Is there any simple way to update changing object content to xml file without resaving the whole file?
[Serializable]
public class Product
{
[XmlAttribute]
public double Name {get; set;}
[XmlAttribute]
public double Value { get; set; }
}
Do the following:
Deserialize the object.
Modify the value.
Serialize it again.

Get name of XmlElementAttribute after deserialization

I haven't found any information on this, maybe someone could help.
I have an XML (simplified for convenience):
<content>
<field1>value</field1>
<field2>
<field3>value</field3>
</field2>
</content>
I try to deserialize it using such classes:
[XmlRoot("content")]
public class Content
{
[XmlElement]
public List<Item> Fields { get; set; }
}
public class Item
{
[XmlElement]
public List<Item> Fields { get; set; }
[XmlText]
public String Value { get; set; }
}
I have two questions:
Can I get the actual name of the field? Like [XmlName] string name; in the Item class? Or some kind of an attribute for the class itself? It is not possible to set the node name to "field" and add "type" attribute, for some reasons ;-) While the actual class and serialization process is really complicated, I'd prefer not to implement my own serializer.
Can I add a wildcard like [XmlElement("field*")]? I can't test it until I know the answer to the first question, so if there is a better option, I'd love to know it as well.
Thanks.
You can set the name of the matching XMl- Element or Attribute in the Constructor of the Attribute
[XmlAttribute("FieldAsAttribute")]
--> Will Serialize / Deserialize the Property to the Xml Attribute FieldAsAttribute
or
[XmlElement("FieldAsElement")]
--> Will Serialize / Deserialize the Property to the Xml Element FieldAsElement
The only answer here is that it's, unfortunately, not possible.
As a result we have written our own serialization routine.

Duplicate values when deserializing xml from external api using built in xml deserialization in C#

I'm using the built in XML deserialization (not because it was my choice, but legacy code) to deserialize xml to a strong typed object.
NOTE: I have no control over the xml, it is an external api
The problem is an xml node has been extended to include a child node of the same name and it's breaking the serialization.
For example, the xml as follows:
<people>
<person>
<id>1234</id>
<person>
<name>This is my name</name>
<person>
</person>
</people>
With the following objects
[XmlType("person")]
public class Person {
[XmlElement("id")]
public int Id { get; set; }
[XmlElement("person")]
public PersonTitle Title{ get; set; }
}
[XmlType("person")]
pulic class PersonTitle
{
[XmlElement("name")]
public string Name { get; set; }
}
This is throwing an error when calling (T)xmlserializer.Deserialize(stream) due to the duplicate names even though the xml is valid. Personally I would not have gone to the trouble to replicate the xml layout in objects just to automatically deserialize it when manually deserializing is easier to maintain (especially when it's never serialized by .net in the first place).
However, I'd like to know if there's a way I can get around this even if it means flattenting the child object out.
I know this doesn't work, but as example:
[XmlType("person")]
public class Person {
[XmlElement("id")]
public int Id { get; set; }
[XmlElement("person/name")]
public string Title{ get; set; }
}
Any help is appreciated.
The easiest method might be to run it through an XSLT transform before deserializing it- match the person/person/name elements and output just the person/name part. Then deserialize the result.
Here's a SO post on applying XSLT within C#: How to apply an XSLT Stylesheet in C#
And here is one on using XSLT to replace elements: http://cvalcarcel.wordpress.com/2008/09/06/replacing-arbitrary-xml-located-within-an-xml-document-using-xslt/
In a worst case scenario you could write the class however you like (don't compromise due to serialization) and then implement IXmlSerializable. Implement ReadXml, throw NotImplementedException for WriteXml if you like.

Categories