Xml declaration for deserialization - c#

Among other data, I have the following XML being sent to me:
<jx:Agency xsi:type="nc:OrganizationType1">
<nc:OrganizationAbbreviationText>ABC</nc:OrganizationAbbreviationText>
</jx:Agency>
In my code, I have Agency declared as follows (I also have the class Agency with a single XmlAttribute OrganizationAbbreviationText):
[XmlElement("Agency", Namespace = jx)]
public Agency Agency { get; set; }
But when I attempt to deserialize, I get "The specified type was not recognized: name='OrganizationType1'" along with the namespace=url
Does anyone know how to properly describe the Agency in my structure?
I am not serializing the structure... the file is being sent to me and I'm deserializing it using the following:
Document doc;
using (FileStream fs = new FileStream(pathName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
XmlSerializer ser = new XmlSerializer(typeof(Document));
doc = (Document)ser.Deserialize(fs);
fs.Close();
}
This is why the xml file needs to be described properly in the Document class.
mho, Here's the code for the Agency class:
[XmlElement(Namespace = jx)]
public class Agency
{
[XmlAttribute("OrganizationAbbreviationText", Namespace = nc)]
public string OrganizationAbbreviationText { get; set; }
}
I don't believe OrganizationType1 really comes into play except that I cannot de-serialize the file I'm being sent without addressing it. jx and nc are constant strings containging URLs. I very much appreciate your help.
Thanks

Clearly, you're missing a type that corresponds to nc:OrganizationType1. In this case you can simply reuse Agency class for nc:OrganizationType1 (if Agency is either default type or nc:OrganizationType1 only).
Also OrganizationAbbreviationText in Agency is an XmlElement and not XmlAttribute.
I have simplified your case and created a sample code that works. Please note [XmlType(TypeName = "OrganizationType1", Namespace = "some-name-space")] on the top of Agency class. Hope it helps, happy to explain
[XmlRoot("Agency")]
[XmlType(TypeName = "OrganizationType1", Namespace = "some-name-space")]
public class Agency
{
[XmlElement("OrganizationAbbreviationText", Namespace = "some-name-space")]
public string OrganizationAbbreviationText { get; set; }
}
public class Program
{
[STAThread]
public static void Main()
{
string xml = "<Agency xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+ " xmlns:nc=\"some-name-space\" xsi:type=\"nc:OrganizationType1\">"
+ "<nc:OrganizationAbbreviationText>ABC</nc:OrganizationAbbreviationText>"
+ "</Agency>";
using (StringReader reader = new StringReader(xml))
{
XmlSerializer ser = new XmlSerializer(typeof(Agency));
var agency = (Agency)ser.Deserialize(reader);
Console.WriteLine(agency.OrganizationAbbreviationText);
}
}
}

Related

XmlSerializer serializes but doesn't deserialize

I'm using the XmlSerializer class from System.Xml.Serialization
My datatypes are marked with the appropriate attributes
e.g.
[XmlRoot(ElementName = "XMLFile")]
public class OrderXml
{
[XmlArray(ElementName = "SalesOrders")]
[XmlArrayItem(ElementName = "SalesOrder")]
public List<SalesOrder> SalesOrders { get; set; }
public OrderXml()
{
}
}
When serializing, there are no problems.
using (FileStream fs = new FileStream(save_to_path + $"Orders_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.xml", FileMode.Create))
{
xs.Serialize(fs, new OrderXml() { SalesOrders = order_resp.results });
}
However, when attempting to read the files that this program has written,
there are no exceptions but all of the fields have default values:
OrderXml ox = null;
using(Stream s = new FileStream(file, FileMode.Open))
{
ox = (OrderXml)xs.Deserialize(s);
}
What have I missed that allows serialize to work, but prevents deserialize from working properly?
I've found the problem.
And it has nothing to do with XmlSerilizer.
Up until recently, this program was being used only to write files.
Many (most) of the properties written have getters, but no setters because of the above.
The object's fields are written from deserializing a JSON body of a web request
and the properties written to the xml file are calculated from these.
For example:
[XmlElement(ElementName = "DeliveryNet")]
public decimal DeliveryNet { get { return Math.Round((100M * price_delivery) / (fee.vat_rate + 100M), 2); } set { } }
I just need to make these blank setters actually do something, then it should work fine.

XmlSerializer not deserializing XML to IEnumerable

While referencing one of the Stack Overflow posts, XmlSerializer won't serialize IEnumerable, I have the following code that would serialize to XML correctly but when deserialized back, the IEnumerable comes back empty.
using System.Xml.Linq;
using System.Xml.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
public class Hello{
public static void Main(){
// <!--- Serializing part -->
Glossary glossary1 = new Glossary();
glossary1.Term = "Test1";
glossary1.Definition = "Test1";
Glossary glossary2 = new Glossary();
glossary2.Term = "Test2";
glossary2.Definition = "Test2";
List<Glossary> glossaryList = new List<Glossary>();
glossaryList.Add(glossary1);
glossaryList.Add(glossary2);
GlossaryCollection glossary = new GlossaryCollection(glossaryList);
XDocument doc = new XDocument();
XmlSerializer xmlSerializer = new XmlSerializer(typeof(GlossaryCollection));
using (var writer = doc.CreateWriter()) {
xmlSerializer.Serialize(writer, glossary);
}
doc.Save("test.xml");
XDocument doc2 = XDocument.Load("test.xml");
Console.WriteLine(glossary.glossaryList.Count());
Console.WriteLine(doc2.ToString());
//So far looks good - serializing works fine!
// </!--- Serializing part -->
// <!--- De-Serializing part -->
GlossaryCollection temp2;
xmlSerializer = new XmlSerializer(typeof(GlossaryCollection));
using (var reader = doc2.Root.CreateReader()) {
var temp = xmlSerializer.Deserialize(reader);
temp2 = (GlossaryCollection) temp;
}
Console.WriteLine(temp2.glossaryList.Count()); // Results in 0, should be 2... :(
// </!--- De-Serializing part -->
}
[XmlRoot]
public class GlossaryCollection {
[XmlIgnore]
public IEnumerable<Glossary> glossaryList;
[XmlElement]
public List<Glossary> GlossarySurrogate { get { return glossaryList.ToList(); } set { glossaryList = value; } } // https://stackoverflow.com/questions/9102234/xmlserializer-wont-serialize-ienumerable
public GlossaryCollection() {
glossaryList = new List<Glossary>();
}
public GlossaryCollection(IEnumerable<Glossary> glossaryList) {
this.glossaryList = glossaryList;
}
}
[XmlType("Glossary")]
public class Glossary
{
public string Id { get; set; }
public string Term { get; set; }
public string Definition { get; set; }
}
}
Update: Based on Iridium's answer, it does not seem possible to use IEnumerable with XmlSerializer since it was returning a new list everytime, so went with the approach of converting to a List. However if there is a solution (even if hacky) with keeping glossaryList an IEnumerable, do let me know - even if simply for pure curiosity.
When your XML-serialized type has a property of type List<T>, XmlSerializer will get the value of the property, then call .Add(...) to add the deserialized elements (i.e. it does not set the property).
Since the getter for the GlossarySurrogate property returns a new list every time you get it, the changes the XML serializer makes to the result are lost.
If you want this to work correctly, you're going to need to convert your glossaryList field to a List<Glossary> and return it directly from the GlossarySurrogate getter, without calling .ToList() on it.

Modify data during Serialization - C# - Json.Net

I have one seializable class in C# as below
namespace DataRequest
{
[Serializable]
public class BaseData
{
[JsonProperty(PropertyName = "u_additional_info")]
public string DeskNumber { get; set; }
}
}
I am fetching data from Database and mapping to this class.I have requirement
DeskNumber will contain data in following format
Format1.
<AdditionalInfo><Number>164</Number></AdditionalInfo>
Format2
AdditionalInfo><Code>GLW51</Code><Lang>GLW51</LangCode><TzCode>GLW51</TzCode></AdditionalInfo>
During serialization if data is 1st fromat i need to return value under tag (ie .164).Value under Number tag will be different at different time.So need a logic find value under Number tag .If data is in any other format other than "Format1" then return it as blank .
Or
I am okay on applying ths logic even if its during setting value rather than during serialisation
Can anyone help on this
if Format1 and Format2 are same file contents coming in at different
times you can be spesitifcly serialized XmlContent this code
Try this
// Generic DeSerialization metod.
public T DeSerialization<T>(string xmlStrig) where T : class
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringReader sReader = new StringReader(xmlStrig))
{
return (T)xmlSerializer.Deserialize(sReader);
}
}
// Accepted class
[Serializable]
public class AdditionalInfo
{
[XmlElement]
public string Number { get; set; }
}
// DeSerialize to Object code
// if you have Xml-string you can send parameter XmlString directly
// string xmlString = System.IO.File.ReadAllText(#"..\\XMLFile1.xml");
AdditionalInfo ast = DeSerialization<AdditionalInfo>(yourXmlString);
You can check www.bilisim.io for detailed information
Use the Following code, You will get Value under the Number Tag. resultingMessage.Number contains the required result
string name = YourXmlNodes;
XmlSerializer serializer = new XmlSerializer(typeof(AdditionalInfo));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(name));
AdditionalInfo resultingMessage= (AdditionalInfo)serializer.Deserialize(memStream);
namespace ConsoleApplication1
{
[XmlRoot(ElementName = "AdditionalInfo")]
public class AdditionalInfo
{
[XmlElement(ElementName = "Number")]
public string Number { get; set; }
}
}

Can I avoid cluttering my class with repetitive XmlElement attributes even though the root node is in a different namespace than its children?

I am retrieving XML documents from a web service I have no control over. The XML is formatted similarly to the following:
<?xml version="1.0"?>
<ns:obj xmlns:ns="somenamespace">
<address>1313 Mockingbird Lane</address>
<residents>5</residents>
</ns:obj>
where the root node is in the "ns" namespace, but none of its child elements are.
After some trial and error, I found that I could deserialize the document to a C# object by doing the following:
[XmlRoot(Namespace="somenamespace", ElementName="obj")]
public class xmlObject
{
[XmlElement(Namespace = "")]
public string address { get; set; }
[XmlElement(Namespace = "")]
public int residents { get; set; }
}
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\"?>" +
"<ns:obj xmlns:ns=\"somenamespace\">" +
" <address>1313 Mockingbird Lane</address>" +
" <residents>5</residents>" +
"</ns:obj>";
var serializer = new XmlSerializer(typeof(xmlObject));
using (var reader = new StringReader(xml))
{
var result = serializer.Deserialize(reader) as xmlObject;
Console.WriteLine("{0} people live at {1}", result.residents, result.address);
// Output: "5 people live at 1313 Mockingbird lane"
}
}
}
If I omit the XmlElementAttribute on the individual members, I instead get an empty object. I.e. The output reads
0 people live at
(result.address is equal to null.)
I understand the rationale behind why the deserialization process works like this, but I'm wondering if there is a less verbose way to tell XmlSerializer that the child elements of the object are not in the same namespace as the root node.
The objects I'm working with in production have dozens of members and, for cleanliness sake, I'd like to avoid tagging all of them with [XmlElement(Namespace = "")] if it's easily avoidable.
You can combine XmlRootAttribute with XmlTypeAttribute to make it so the root element, and the root element's elements, have different namespaces:
[XmlRoot(Namespace="somenamespace", ElementName="obj")]
[XmlType(Namespace="")]
public class xmlObject
{
public string address { get; set; }
public int residents { get; set; }
}
Using the type above, if I deserialize and re-serialize your XML I get:
<q1:obj xmlns:q1="somenamespace">
<address>1313 Mockingbird Lane</address>
<residents>5</residents>
</q1:obj>
Sample fiddle.
If you know the contract with the web service, why not use a DataContractSerializer to deserialize the XML into the objects?

Error while serializing a class to XML

I am serializing Linq object to using XmlSerializer but I am getting
"There was an error reflecting type
'System.Collections.Generic.List`1"
I have extended the Linq object with Serilizable attributes, something that m I doing incorrect here?
[Serializable]
public partial class Customer
{
}
[Serializable]
public partial class Comment
{
}
[Serializable]
public class CustomerArchive
{
public Customer MyCustomer{ get; set; }
public Comment MyComment { get; set; }
}
internal static void Serialize(IEnumerable<CustomerArchive> archive, string fileName)
{
var serializer = new XmlSerializer(typeof(List<CustomerArchive>)); // Error
using (var stream = File.Create(fileName))
{
using (var sw = new StreamWriter(stream))
using (var writer = new XmlTextWriter(sw)
{
Indentation = 5,
Formatting = Formatting.Indented
})
serializer.Serialize(writer, new List<CustomerArchive>(archive));
}
}
I think you have some properties inside MyCustomer class that cannot be serialized by the XML Serializer. Like a generic Dictionary<> for example.
Put [XmlIgnore] attribute on those properties and try again. If after that your code works you will simply need to make some surrogate properties that would serialize to XML and back without any issues.

Categories

Resources