C# XmlSerializer define namespace with prefix in a child node - c#

I need to create an XML document with C# that is like this:
<?xml version="1.0" encoding="utf-8"?>
<Container>
<Info>
<request xmlns:a="http://www.UKMail.com/Services/Contracts/DataContracts">
<a:AuthenticationToken>token</a:AuthenticationToken>
<a:Username>username</a:Username>
<a:ConsignmentNumber>12345</a:ConsignmentNumber>
</request>
</Info>
</Container>
The critical part is the namespace definition with a prefix (xmlns:a=...) is in a child node, not the root node. I have only been able to produce this document so far:
<?xml version="1.0" encoding="utf-8"?>
<Container xmlns:a="http://www.UKMail.com/Services/Contracts/DataContracts">
<Info>
<a:request>
<a:AuthenticationToken>token</a:AuthenticationToken>
<a:Username>username</a:Username>
<a:ConsignmentNumber>12345</a:ConsignmentNumber>
</a:request>
</Info>
</Container>
This is rejected by the web service - if you move the xmlns:a.. part to the request node the web service is happy with it.
This is how I am generating the XML at the moment:
class Program
{
static void Main(string[] args)
{
SerializeObject("XmlNamespaces.xml");
}
public static void SerializeObject(string filename)
{
var mySerializer = new XmlSerializer(typeof(Container));
// Writing a file requires a TextWriter.
TextWriter myWriter = new StreamWriter(filename);
// Creates an XmlSerializerNamespaces and adds two
// prefix-namespace pairs.
var myNamespaces = new XmlSerializerNamespaces();
myNamespaces.Add("a", "http://www.UKMail.com/Services/Contracts/DataContracts");
Container container = new Container
{
Info = new CancelConsignmentRequest
{
request = new CancelConsignmentRequestInfo
{
AuthenticationToken = "token",
ConsignmentNumber = "12345",
Username = "username"
}
}
};
mySerializer.Serialize(myWriter, container, myNamespaces);
myWriter.Close();
}
}
public class Container
{
public CancelConsignmentRequest Info { get; set; } = new CancelConsignmentRequest();
}
[XmlRoot(Namespace = "http://www.UKMail.com/Services/Contracts/ServiceContracts")]
public class CancelConsignmentRequest
{
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts")]
public CancelConsignmentRequestInfo request { get; set; } = new CancelConsignmentRequestInfo();
}
public class CancelConsignmentRequestInfo
{
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 0)]
public string AuthenticationToken { get; set; }
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 1)]
public string Username { get; set; }
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 2)]
public string ConsignmentNumber { get; set; }
}
I have not been able to work out how to place the namespace definition with a prefix in one of the child nodes. Does anyone know how to do this in C# please? Thanks.

This is possible. The code below does what you are asking for.
class Program
{
static void Main(string[] args)
{
SerializeObject("XmlNamespaces.xml");
}
public static void SerializeObject(string filename)
{
var mySerializer = new XmlSerializer(typeof(Container));
// Writing a file requires a TextWriter.
TextWriter myWriter = new StreamWriter(filename);
// Creates an XmlSerializerNamespaces and adds two
// prefix-namespace pairs.
var myNamespaces = new XmlSerializerNamespaces();
//myNamespaces.Add("a", "http://www.UKMail.com/Services/Contracts/DataContracts");
Container container = new Container
{
Info = new CancelConsignmentRequest
{
request = new CancelConsignmentRequestInfo
{
AuthenticationToken = "token",
ConsignmentNumber = "12345",
Username = "username"
}
}
};
mySerializer.Serialize(myWriter, container, myNamespaces);
myWriter.Close();
}
}
public class Container
{
public CancelConsignmentRequest Info { get; set; } = new CancelConsignmentRequest();
}
public class CancelConsignmentRequest
{
public CancelConsignmentRequestInfo request { get; set; } = new CancelConsignmentRequestInfo();
}
[XmlRoot(Namespace = "http://www.UKMail.com/Services/Contracts/ServiceContracts")]
public class CancelConsignmentRequestInfo
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces(
new[] { new XmlQualifiedName("a", "http://www.UKMail.com/Services/Contracts/DataContracts"), });
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 0)]
public string AuthenticationToken { get; set; }
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 1)]
public string Username { get; set; }
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 2)]
public string ConsignmentNumber { get; set; }
}

Related

XmlSerlializer is not serializing all properties of a class

I wrote a generic method for Object to XML string using XMLSerializer class.
Below is my class
public class SampleJson
{
public string fname { get; set; }
public string lname { get; set; }
public int age { get; set; }
public AdditionalInformation AdditionalInformation { get; set; }
}
public class AdditionalInformation
{
public string firstlane { get; set; }
public string secondlane { get; set; }
public decimal? cityCode { get; set; }
public int? countryCode { get; set; }
public bool? isValid { get; set; }
public DateTime enteredDate { get; set; }
}
And below is Generic Method
public class QAZ
{
public static string Foo<T>(T dataToSerialize)
{
var stringWriter = new StringWriter();
XmlTextWriter xmlTextWriter = null;
var serializer = new XmlSerializer(dataToSerialize.GetType());
xmlTextWriter = new XmlTextWriter(stringWriter);
serializer.Serialize(xmlTextWriter, dataToSerialize);
return stringWriter.ToString();
}
}
class Bar
{
static void Main(string[] args)
{
var sampleJson = typeof(SampleJson);
var fooMethod = typeof(QAZ).GetMethod("Foo");
var fooOfBarMethod = fooMethod.MakeGenericMethod(new[] {sampleJson});
string xml= fooOfBarMethod.Invoke(new QAZ(), new object[] {new SampleJson()}).ToString();
Console.ReadKey();
}
}
But I'm getting the output is
<?xml version="1.0" encoding="UTF-16"?>
-<SampleJson xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<age>0</age>
</SampleJson>
I don't understand why XmlSerializer serializes only int property.
Can anyone please tell me the issue that I'm doing.
The main agenda here is I want to generate an xsd for SampleJson class. In order to do that I am trying to convert the class to xml. From xml to xsd. Is there a way to generate xsd from a class?
I think this might help you to understand better, I wrote an example please do like or dislike if it has or hasn't helped.
public class Vehicle
{
public string VRM;
}
class Program
{
static void Main(string[] args)
{
var Reg = new Vehicle { VRM = "LP65 UGT" };
var writer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicle));
var wfile = new System.IO.StreamWriter(#"C:\Myexample\NewVehicle.xml");
writer.Serialize(wfile, Reg);
wfile.Close();
Console.WriteLine("Vehicle Reg is now written in xml format ");
Console.ReadKey();
}
}
The above example will write successfully to XML file ensure you create the folder first on your C drive My example and then run the above to see the result for yourself and see if it can point you to the correct direction hopefully.

My nested Class collection XMLRoot name is not being used when serializing to xml

I have a Model populated and I wish to serlise to an xml document.
Due to naming conventions I have to over ride the class names for my XML document,
This is my Model(s):
[Serializable]
[XmlRoot("preferences")]
public class PreferencesModel
{
[XmlIgnore]
public string MessageToUser { get; set; }
[XmlElement(ElementName = "sectiondivider")]
public List<SectionDivider> SectionDivider { get; set; }
}
[Serializable]
[XmlRoot(ElementName = "sectiondivider")]
public class SectionDivider
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlElement("preference")]
public List<PreferenceModel> PreferenceModel { get; set; }
}
[Serializable]
[XmlRoot("preference")]
public class PreferenceModel
{
[XmlAttribute("type")]
public string Type { get; set; }
public string Name { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
[XmlElement("options")]
public List<Option> Options { get; set; }
}
this is how I serialize:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(ObjectToXmlString(obj, includeNameSpace, includeStartDocument, rootAttribute));
return xDoc;
public static string ObjectToXmlString(Object obj, bool includeNameSpace, bool includeStartDocument, XmlRootAttribute rootAttribute)
{
SpecialXmlWriter stWriter = null;
XmlSerializer xmlSerializer = default(XmlSerializer);
string buffer = null;
try
{
if (rootAttribute == null)
{
xmlSerializer = new XmlSerializer(obj.GetType());
}
else
{
xmlSerializer = new XmlSerializer(obj.GetType(), rootAttribute);
}
MemoryStream memStream = new MemoryStream();
StringWriter writer = new StringWriter();
stWriter = new SpecialXmlWriter(memStream, new UTF8Encoding(false), includeStartDocument);
if (!includeNameSpace)
{
System.Xml.Serialization.XmlSerializerNamespaces xs = new XmlSerializerNamespaces();
//To remove namespace and any other inline
//information tag
xs.Add("", "");
xmlSerializer.Serialize(stWriter, obj, xs);
}
else
{
xmlSerializer.Serialize(stWriter, obj);
}
buffer = Encoding.UTF8.GetString(memStream.ToArray());
}
catch (Exception e)
{
string msg = e.Message;
throw;
}
finally
{
if (stWriter != null)
stWriter.Close();
}
return buffer;
}
I call it like this:
XmlDocument preferencesxml = Codec.ObjectToXml(m.SectionDivider,false,
false, new XmlRootAttribute("preferences"));
My m value is:
and my resulting XML is this:
XmlRootAttribute, as the name suggests, only applies to the root element of the XML being serialised.
You need to use XmlTypeAttribute in this context:
[XmlType("sectiondivider")]`
public class SectionDivider
{
//...
}
As an aside, the [Serializable] attribute is not relevant to XmlSerializer - it can be removed unless you need it for some other purpose.

How to get value inside XML tag?

I have the follow XML structure:
<Document>
<Sectors>
<Sector>
SectorName1
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector>
SectorName2
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Also I have classes for deserialize:
public class MetaDataXML
{
public class SectorXML
{
[XmlArrayItem(ElementName = "Sector")]
string SectorName { get; set; }
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
public List<SectorXML> Sectors { get; set; }
}
And part of code which do deserialize:
var xRoot = new XmlRootAttribute { ElementName = "Document", IsNullable = true };
var reader = new XmlSerializer(typeof(MetaDataXML), xRoot);
var data = (MetaDataXML)reader.Deserialize(streamXML);
After deserialization I successfully get subsectors velues, but I didn't get values for SectorName. How I need to organize my structure of class that I'll get values "SectorName1" and "SectorName2" for my string SectorName property?
I found that that this case it's a "Mixed Content". How we can parse this text values?
Whilst I am not entirely sure what it is you're trying to achieve here, I've made a few modifications to your XML class and provided some sample code below that is able to retrieve all of the information about a sector, including its name and the name of all the subsectors inside it.
XML Class:
namespace DocumentXml
{
[XmlRoot("Document")]
public class Document
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlAttribute("SectorName")]
public string SectorName { get; set; }
[XmlArray("Subsectors")]
[XmlArrayItem("Subsector")]
public string[] Subsectors { get; set; }
}
}
Main Program Class:
namespace DocumentXml
{
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
var serializer = new XmlSerializer(typeof(Document));
var document = serializer.Deserialize(File.OpenRead(path)) as Document;
var sectors = document.Sectors;
foreach (var s in sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
Sample XML:
<Document>
<Sectors>
<Sector SectorName="SectorName1">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector SectorName="SectorName2">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Output:
EDIT
Since the XML structure cannot be changed, this new class will preserve the structure and also allow you to get the value in question. XmlText returns everything inside the value so a custom set had to be used to ensure that the whitespace was correctly trimmed from it.
[XmlRoot("Document")]
public class MetaDataXml
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlIgnore]
private string _sectorName;
[XmlText]
public string SectorName
{
get
{
return _sectorName;
}
set
{
_sectorName = value.Trim();
}
}
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
Sample Program:
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
using (var stream = File.OpenRead(path))
{
var deserializer = new XmlSerializer(typeof(MetaDataXml));
var data = (MetaDataXml)deserializer.Deserialize(stream);
foreach (var s in data.Sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
}
Console.ReadKey();
}
}

XmlSerializer with custom namespace

I want to consume a restful web service with xml. I have to create this template in order to create a valid request:
<WS_IN_GetAccountCredit xmlns="http://schemas.datacontract.org/2004/07/WcfWebService">
<GetAccountCreditParams>
<Password>String content</Password>
<UserName>String content</UserName>
</GetAccountCreditParams>
<WSIdentity>
<WS_PassWord>String content</WS_PassWord>
<WS_UserName>String content</WS_UserName>
</WSIdentity>
</WS_IN_GetAccountCredit>
My serializer method is like this:
XmlSerializerNamespaces xmlNameSpace = new XmlSerializerNamespaces();
xmlNameSpace.Add("", "http://schemas.datacontract.org/2004/07/WcfWebService");
XmlSerializer xmlSerializer = new XmlSerializer(instance.GetType());
using (StringWriter textWriter = new StringWriter())
{
xmlSerializer.Serialize(textWriter, instance, xmlNameSpace); ; return textWriter.ToString();
}
My output looks like this:
<?xml version="1.0" encoding="utf-16"?>
<WS_IN_GetAccountCredit xmlns:xmlns="http://schemas.datacontract.org/2004/07/WcfWebService">
<WSIdentity>
<WS_UserName>String content</WS_UserName>
<WS_PassWord>String content</WS_PassWord>
</WSIdentity>
<GetAccountCreditParams>
<UserName>String content</UserName>
<Password>String content</Password>
</GetAccountCreditParams>
</WS_IN_GetAccountCredit>
As you can see, the namespace and xml version is in wrong format. I also found this, this and this article but non of them could solve my problem.
How can create a valid request?
Here we go:
[XmlRoot(ElementName = "WS_IN_GetAccountCredit", Namespace = "http://schemas.datacontract.org/2004/07/WcfWebService")]
public class WS_IN_GetAccountCredit
{
private WS_IN_WebServiceIdentity wsIdentity;
private WS_IN_GetAccountCreditParams getAccountCreditParams;
public WS_IN_WebServiceIdentity WSIdentity { set { this.wsIdentity = value; } get { return this.wsIdentity; } }
public WS_IN_GetAccountCreditParams GetAccountCreditParams
{
set { this.getAccountCreditParams = value; }
get { return this.getAccountCreditParams; }
}
}
public class WS_IN_WebServiceIdentity
{
public string UserName { get; set; }
public string Password { get; set; }
}
public class WS_IN_GetAccountCreditParams
{
public string UserName { get; set; }
public string Password { get; set; }
}
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "http://schemas.datacontract.org/2004/07/WcfWebService");
var ser = new XmlSerializer(typeof(WS_IN_GetAccountCredit));
using (var writer = new StringWriter())
{
ser.Serialize(writer, new WS_IN_GetAccountCredit
{
GetAccountCreditParams = new WS_IN_GetAccountCreditParams { Password = "pass", UserName = "use" },
WSIdentity = new WS_IN_WebServiceIdentity { Password = "pass", UserName = "use" }
},
namespaces);
var xml = writer.ToString();
}
The result is:
<?xml version="1.0" encoding="utf-16"?>
<WS_IN_GetAccountCredit xmlns="http://schemas.datacontract.org/2004/07/WcfWebService">
<WSIdentity>
<UserName>use</UserName>
<Password>pass</Password>
</WSIdentity>
<GetAccountCreditParams>
<UserName>use</UserName>
<Password>pass</Password>
</GetAccountCreditParams>
</WS_IN_GetAccountCredit>

Serializing XML with strange namespaces?

Question: How does the class for the serialization of this XML content look ?
<?xml version="1.0" encoding="utf-8"?>
<vcc:CreateTextSearchResponse xmlns:vcc="urn:veloconnect:catalog-1.1" xmlns:vct="urn:veloconnect:transaction-1.0">
<vct:BuyersID>12345</vct:BuyersID>
<vct:ResponseCode>200</vct:ResponseCode>
<vct:TransactionID>225</vct:TransactionID>
<vct:StatusCode>2</vct:StatusCode>
<vct:IsTest>false</vct:IsTest>
<vcc:TotalCount>3876</vcc:TotalCount>
</vcc:CreateTextSearchResponse>
If I let it run through xsd.exe, it generates an error.
I have no problem generating this:
<?xml version="1.0" encoding="utf-8"?>
<CreateTextSearchResponse>
<BuyersID>15942</BuyersID>
<ResponseCode>200</ResponseCode>
<TransactionID>225</TransactionID>
<StatusCode>2</StatusCode>
<IsTest>false</IsTest>
<TotalCount>3876</TotalCount>
</CreateTextSearchResponse>
It's just that I need those namespaces to deserialize it (and later on reserialize), so I can't just leave it like this (it's needed by a 3rd party web-service)...
Like this:
[XmlRoot(Namespace = CreateTextSearchResponse.CatalogNamespace)]
public class CreateTextSearchResponse
{
public const string CatalogNamespace = "urn:veloconnect:catalog-1.1",
TransactionNamespace = "urn:veloconnect:transaction-1.0";
[XmlElement(Namespace=TransactionNamespace)]
public int BuyersId { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public int ResponseCode { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public int TransactionID { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public int StatusCode { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public bool IsTest { get; set; }
[XmlElement(Namespace = CatalogNamespace)]
public int TotalCount { get; set; }
}
public static void Main()
{
var ser = new XmlSerializer(typeof(CreateTextSearchResponse));
var obj = new CreateTextSearchResponse
{
BuyersId = 12345,
ResponseCode = 200,
TransactionID = 225,
StatusCode = 2,
IsTest = false,
TotalCount = 3876
};
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("vcc", CreateTextSearchResponse.CatalogNamespace);
ns.Add("vct", CreateTextSearchResponse.TransactionNamespace);
ser.Serialize(Console.Out, obj, ns);
}
unfortunately there are special characters in your namesapce that Xml can't handle

Categories

Resources