How to create constructor to fill xmlelement and attribute? - c#

I have complex class which I want to serialize to XML format using costum attributes. I am stucked at XMLelement which is List and I would like to generate new items with constructor, where I can fill attribute name and text value.
Now I have to create seperate objects and those I can add to the List. I want to simplify this.
class to be serialized:
[XmlElement("Cfg")]
public ElCfg Cfg = new ElCfg();
public class ElCfg
{
[XmlAttribute("Name")] public string CfgName { get; set; } = "Default";
[XmlElement("Content")] public ElCont Content = new ElCont();
}
public class ElCont
{
[XmlAttribute("ver")] public string ContentVer { get; set; }
[XmlElement("Prop")] public List<ElProp> Properties = new List<ElProp>();
}
public class ElProp
{
[XmlAttribute("Name")]
public string PropertyName { get; set; }
[XmlText]
public string PropertyVal { get; set; }
}
usage in main:
static void Main(string[] args)
{
//build promotic object
PromoticXML xmlDoc = new PromoticXML();
xmlDoc.Cfg.Content.ContentVer = "80323";
PromoticXML.ElProp prop1 = new PromoticXML.ElProp();
prop1.PropertyName = "neco";
prop1.PropertyVal = "necojineho";
PromoticXML.ElProp prop2 = new PromoticXML.ElProp();
prop2.PropertyName = "neco";
prop2.PropertyVal = "necojineho";
xmlDoc.Cfg.Content.Properties.Add(prop1);
xmlDoc.Cfg.Content.Properties.Add(prop2);
//serialize promotic object
XmlWriterSettings xmlSet = new XmlWriterSettings();
xmlSet.Encoding = Encoding.Unicode;
xmlSet.Indent = true;
xmlSet.IndentChars = " ";
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializer serializer = new XmlSerializer(typeof(PromoticXML));
using (XmlWriter writer = XmlWriter.Create("promotic.xml", xmlSet))
{
serializer.Serialize(writer, xmlDoc);
}
Process.Start("notepad.exe", "promotic.xml");
}
What my goal is:
xmlDoc.Cfg.Content.Properties.Add(new PromoticXML.ElProp("someName", "someText"));
instead of:
PromoticXML.ElProp prop1 = new PromoticXML.ElProp();
prop1.PropertyName = "neco";
prop1.PropertyVal = "necojineho";
xmlDoc.Cfg.Content.Properties.Add(prop1);

Related

Class with nested classes throws InvalidOperationException: Token StartElement in state Epilog would result in an invalid XML document

I am trying to Serialize a simple class with a single property for a SOAP request using System.Xml.Serialization.XmlSerializer which works fine, but as soon as I add another property to my class and the property type is another class I receive this error message when executing XmlSerializer.Serialize(StringWriter, myclass):
InvalidOperationException: Token StartElement in state Epilog would result in an invalid XML document.
The two classes are dead-simple:
[XmlRoot(Namespace = "http://example.org/", ElementName = "Foo")]
public class Foo
{
public string Id { get; set; }
public Bar Bar { get; set; }
}
public class Bar
{
public string Id { get; set; }
}
This is how I perform the serialization:
var foo = new Foo(Id = "foo-id", Bar = new Bar { Id = "bar-id" });
var soapReflectionImporter = new SoapReflectionImporter("http://example.org");
var xmlTypeMapping = soapReflectionImporter.ImportTypeMapping(typeof(Foo));
var serializer = new XmlSerializer(xmlTypeMapping);
using (var writer = new StringWriter())
{
serializer.Serialize(writer, foo);
}
If I remove the Bar property from Foo, everything works as expected. I already looked through this and this without it solving the issue. I also cannot simply call the constructor for XmlSerializer with a type parameter because I need the XmlTypeMapping for the SOAP request. Can someone point out where the issue is or if I am missing some additional configuration?
The output XML needs a root element. Using XmlWriter along with XmlWriterSettings can help, like below.
[XmlRoot(Namespace = "http://example.org/", ElementName = "Foo")]
public class Foo
{
public string Id { get; set; }
public Bar Bar { get; set; }
}
public class Bar
{
public string Id { get; set; }
}
public class Program
{
static void Main(string[] args)
{
var foo = new Foo() { Id = "foo-id", Bar = new Bar { Id = "bar-id" } };
var soapReflectionImporter = new SoapReflectionImporter("http://example.org");
var xmlTypeMapping = soapReflectionImporter.ImportTypeMapping(typeof(Foo));
var serializer = new XmlSerializer(xmlTypeMapping);
//using (var writer = new StringWriter())
//{
// serializer.Serialize(writer, foo);
//}
Stream st = new MemoryStream();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.WriteEndDocumentOnClose = true;
XmlWriter writer = XmlWriter.Create(st, settings);
writer.WriteStartElement("base");
serializer.Serialize(writer, foo);
writer.Close(); //will write the final closing tag
st.Position = 0;
StreamReader sr = new StreamReader(st);
string data = sr.ReadToEnd();
}
}

By pass XmlElement serilization inside a Property with XmlText attribute

I have a class with a string property.
[Serializable]
public class Gather
{
[XmlAttribute("action")]
public string Action { get; set; }
[XmlAttribute("method")]
public string Method { get; set; }
[XmlAttribute("timeout")]
public string Timeout { get; set; }
[XmlAttribute("finishOnKey")]
public string FinishOnKey { get; set; }
[XmlElement]
public Say Say;
}
[Serializable]
public class Say
{
[XmlText]
public string Value;
}
I was doing xml serilization successfully from the following code then i got to know that inside Value property of Say class i need to pass plain xml some time
private string GetSpeechwithGatherXml(string value)
{
Say speechToText = new Say { Value = value };
Gather gather = new Gather
{
Action = txtCallback.Text,
Method = "Get",
Timeout = Convert.ToInt32(numericMaxTime.Value).ToString(),
FinishOnKey = "#",
Say = speechToText
};
GatherResponse response = new GatherResponse { Gather = gather };
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(response.GetType());
var settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, response, emptyNamespaces);
return stream.ToString();
}
}
But xml tags are changing to < and > understandingly.
Any way I can by-pass this behavior in one propery (Value of Say class)
I wanted to send something like
<Response>
<Say>John’s phone number is, <say-as interpret-as="telephone">1234</say-as></Say>
</Response>
which is a valid xml

Serializing class adds prefixes automatically to XML elements

I have the following class that needs to be serialized:
[XmlRoot("Login", Namespace = "http://tempuri.org/Logon"), Serializable()]
public class Login
{
[XmlElement("programCode")]
public string ProgramCode { get; set; }
[XmlElement("contactType")]
public string ContactType { get; set; }
[XmlElement("email")]
public string Email { get; set; }
[XmlElement("password")]
public string Password { get; set; }
[XmlElement("projectName")]
public string ProjectName { get; set; }
}
When I serialize this class, I obtain the following XML:
<q1:Login xmlns:q1="http://tempuri.org/Logon"><q1:programCode>abc</q1:programCode><q1:contactType>P</q1:contactType><q1:email>ws#abc.com</q1:email><q1:password>abc</q1:password><q1:projectName>abc</q1:projectName></q1:Login>
I do not know where the prefix q1 is getting generated from. I want an XML like this:
<Login xmlns="http://tempuri.org/Logon">
<programCode>abc</programCode>
<contactType>P</contactType>
<email>ws#abc.com</email>
<password>abc</password>
<projectName>abc</projectName>
</Login>
Can anyone please help me out with this? Thank you.
Update:
Serialization code:
public string GetObjectInXML(object obj)
{
StringWriter sw = new StringWriter();
StringBuilder sb = new StringBuilder(_soapEnvelope);
XmlSerializer serializer = new XmlSerializer(obj.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlWriterSettings settings = new XmlWriterSettings
{
OmitXmlDeclaration = true
};
XmlWriter writer = XmlWriter.Create(sw, settings);
ns.Add(string.Empty, string.Empty);
serializer.Serialize(writer, obj, ns);
var str = sw.ToString();
return str;
}
For now this is a method which returns string just to check if my XML is built properly.
The XMLSerializer supports providing a default namespace e.g.
string defaultNamespace = "http://tempuri.org/Logon";
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, defaultNamespace);
XmlSerializer xs = new XmlSerializer(typeof(T), defaultNamespace);
Can you remove the name space?
[XmlRoot("Login", Namespace = ""), Serializable()]
public class Login {
[XmlElement("programCode")]
public string ProgramCode { get; set; }
[XmlElement("contactType")]
public string ContactType { get; set; }
[XmlElement("email")]
public string Email { get; set; }
[XmlElement("password")]
public string Password { get; set; }
[XmlElement("projectName")]
public string ProjectName { get; set; }
}
public static string SerializeXml<T>(T value)
{
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("q1", "http://tempuri.org/Logon");
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
using (var writer = XmlWriter.Create(stringWriter, settings))
{
xmlserializer.Serialize(writer, value, namespaces);
return stringWriter.ToString();
}
}
public static void Main(string[] args)
{
var login = new Login();
login.ContactType = "XMLType";
login.Email = "x#x.com";
var a = SerializeXml(login);
Console.WriteLine(a);
Console.ReadLine();
}
Result
<Login xmlns:q1="http://tempuri.org/Logon">
<contactType>XMLType</contactType>
<email>x#x.com</email>
</Login>

How to add namespace prefix to class element in c#

[XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.example.org/schema/SCRIPT")]
public class Identification
{
public string DEANumber { get; set; }
public uint NPI { get; set; }
}
<someprefix:Identification>
<someprefix:DEANumber>FF1234567</DEANumber>
<someprefix:NPI>1619967999</NPI>
</someprefix:Identification>
How to assign namespace prefix to class elements
Use a XmlSerializerNamespaces as such :
var id = new Identification()
{
DEANumber = "qwe",
NPI = 123,
};
var serializer = new XmlSerializer(typeof(Identification));
var xmlns = new XmlSerializerNamespaces();
xmlns.Add("someprefix", "http://www.example.org/schema/SCRIPT");
serializer.Serialize(Console.Out, id, xmlns);

Add schemaLocation to XML serializing List<T> using XmlSerializer

I'm trying to add schemaLocation attribute to XML root element when serializing List<T>. Code works fine if I'm serializing just one object but does not work on lists. My current code:
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
}
public class XmlListContainer<T> : List<T>
{
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
public class BuildXml
{
public static void GetXml()
{
var list = new XmlListContainer<SomeObject>()
{
new SomeObject() { Id = 1, Name = "One" },
new SomeObject() { Id = 2, Name = "Two" },
};
var objectToXml = list;
string output;
using (var writer = new StringWriter())
{
var xs = new XmlSerializer(objectToXml.GetType());
var nameSpaces = new XmlSerializerNamespaces();
nameSpaces.Add("xsi", "http :// www.w3.org/2001/XMLSchema-instance");
xs.Serialize(writer, objectToXml, nameSpaces);
output = writer.GetStringBuilder().ToString();
writer.Close();
}
Console.WriteLine(output);
}
}
XML root element appears without schemaLocation:
<ArrayOfSomeObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
If I'm changing code to
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
...
var objectToXml = new SomeObject() { Id = 1, Name = "One" };
...all looks fine but I need list list
<SingleObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost/someschema">
Is it possible to add schemaLocation attribute when serializing List<T>?

Categories