I'm totally new to C#. I have to write a xml file which similarly looks like.
<DATA_SET SampleSize="5">
<DATA SampleID="1" IW="0.889" SL="24.24" PO="117" />
<DATA SampleID="2" IW="0.896" SL="24.41" PO="119" />
<DATA SampleID="3" IW="0.922" SL="24.3" PO="125" />
<DATA SampleID="4" IW="0.94" SL="24.24" PO="129" />
<DATA SampleID="5" IW="0.987" SL="24.32" PO="127" />
</DATA_SET>
What I have to tried is,
if (oneSet.Length == 5)
{
qtm.SampleID = oneSet[0];//ROD
qtm.SL = oneSet[1];//SIZEmmL
qtm.SY = oneSet[2];//OVALmm
qtm.RP = oneSet[3];//ROUND%
qtm.VN = oneSet[4];//VENT%
lstQTM.Add(qtm);
isSet = true;
}
Here QTM is a class, through this class I have made list. SampleID,SL,SY,RP,VN are the methods of QTM class file.
By using above code I added those into a list.
using (FileStream fs = new FileStream("D:\\B.xml", FileMode.Create))
{
new XmlSerializer(typeof(List<QTM>)).Serialize(fs, lstQTM);
}
My out put is
<QTM>
<SampleID>ROD</SampleID>
<SL>WTg</SL>
<SY>SIZEmmL</SY>
<RP>OVALmm</RP>
<VN>PDmm</VN>
</QTM>
<QTM>
<SampleID>1</SampleID>
<SL>0.740</SL>
<SY>23.94</SY>
<RP>0.28</RP>
<VN>357</VN>
</QTM>
<QTM>
<SampleID>2</SampleID>
<SL>0.751</SL>
<SY>23.98</SY>
<RP>0.29</RP>
<VN>368</VN>
</QTM>
<QTM>
<SampleID>3</SampleID>
<SL>0.733</SL>
<SY>23.95</SY>
<RP>0.39</RP>
<VN>351</VN>
</QTM>
<QTM>
<SampleID>4</SampleID>
<SL>0.747</SL>
<SY>23.99</SY>
<RP>0.32</RP>
<VN>363</VN>
</QTM>
<QTM>
<SampleID>5</SampleID>
<SL>0.734</SL>
<SY>23.96</SY>
<RP>0.23</RP>
<VN>356</VN>
</QTM>
<QTM>
<SampleID>6</SampleID>
<SL>0.742</SL>
<SY>23.89</SY>
<RP>0.64</RP>
<VN>365</VN>
</QTM>
</ArrayOfQTM>
How can I do this. could you please give me any idea.
Here's an example class structure which preserves the structure of the QTM class you already have, but still gives the XML that you want to get.
[XmlRoot("DATA_SET")]
public class QTMCollection
{
[XmlElement("DATA")]
public List<QTM> QTMs { get; set; }
[XmlAttribute("SampleSize")]
public int SampleSize { get { return QTMs.Count; } set { return; } }
}
public class QTM
{
[XmlAttribute]
public int SampleId { get; set; }
[XmlAttribute]
public decimal IW { get; set; }
[XmlAttribute]
public decimal SL { get; set; }
[XmlAttribute]
public int PO { get; set; }
}
We need an outer class structure here - mainly driven by the SampleSize attribute on the outer DATA_SET element, otherwise we wouldn't have to have it.
There are some quirks here - XmlSerializer will only serialize properties that have a getter and setter, which is why I have the otherwise unnecessary setter on SampleSize. The XmlRoot, XmlAttribute and XmlElement serve to tell the serializer what to call your classes and properties in the XML.
Here is an example of how to invoke the serializer to get an xml exactly like your example:
QTMCollection collection = new ConsoleApplication135.QTMCollection()
{
QTMs = new List<QTM>
{
new QTM() { SampleId = 1, IW = 0.0889M, SL = 24.24M, PO = 117 },
new QTM() { SampleId = 2, IW = 0.896M, SL = 24.41M, PO = 119 },
new QTM() { SampleId = 3, IW = 0.922M, SL = 24.3M, PO = 125 },
new QTM() { SampleId = 4, IW = 0.94M, SL = 24.24M, PO = 129 },
new QTM() { SampleId = 5, IW = 0.987M, SL = 24.32M, PO = 127 }
}
};
using (FileStream fileStream = new FileStream(#"c:\temp\B.xml", FileMode.Create))
{
using (var writer = XmlWriter.Create(fileStream, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true }))
{
var serializer = new XmlSerializer(typeof(QTMCollection));
serializer.Serialize(writer, collection, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
}
}
The reason for using XmlWriterSettings (and so the XmlWriter) here is to omit the Xml declaration at the top of the XML that would otherwise appear:
<?xml version="1.0" encoding="utf-8"?>
And the purpose of this:
new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })
Is to avoid the default namespace declaration on the root element that would otherwise appear:
<DATA_SET xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SampleSize="5">
Whereas with both those things, the output will be an unadorned XML like this:
<DATA_SET SampleSize="5">
<DATA SampleId="1" IW="0.0889" SL="24.24" PO="117" />
<DATA SampleId="2" IW="0.896" SL="24.41" PO="119" />
<DATA SampleId="3" IW="0.922" SL="24.3" PO="125" />
<DATA SampleId="4" IW="0.94" SL="24.24" PO="129" />
<DATA SampleId="5" IW="0.987" SL="24.32" PO="127" />
</DATA_SET>
In your C# classes you can add attributes to your member variables that will change how XmlSerializer will behave. For example, the following will make the SampleID be serialised as an attribute rather than an element:
public class QTM {
[XmlAttribute("SampleID")]
public int SampleID;
}
See the documentation for more information here
Update
As noted by Rand Random, I misread the original question. Therefore, be awate of it. I quote the comment for future reference.
As note by the comment, the OP is indeed aware of the mechanism, but
didn't know that he needs a root object and that he can change a
XmlElement to XmlAttribute by declaring it with attributes
If you want to read an XML document without dirtying your hands, you can use XmlSerializer.
It is super easy. First you create POCO (classes with only properties) that mimick the XML file you want to read. Start from the root:
[XmlRoot("DATA_SET ")]
public sealed class MyRoot
{
[XmlElement("sampleSize")]
public int SampleSize { get; set; }
[XmlArrayItem("data")]
public List<MyData> Data { get; set; }
}
The above code models the root. It is as verbose as possible, in order to understand what you are effectively doing.
Then, you model the inner node:
[Serializable]
public sealed class MyData
{
[XmlAttribute("SampleID")]
public int SampleId { get; set; }
[XmlAttribute("IW")]
public double WhateverThisIs1 { get; set; }
[XmlAttribute("SL")]
public double WhateverThisIs2 { get; set; }
[XmlAttribute("PO")]
public int WhateverThisIs3 { get; set; }
}
The above code declares the properties with the names you want in C#, mapped to the names you expect in your xml file. As you can see they differ.
Finally, you can read your file in this way:
var serializer = new XmlSerializer(typeof(MyRoot));
using (var reader = new StreamReader(fileName))
{
var root = (MyRoot)serializer.Deserialize(reader);
// do something with root.
}
Note: You might have to adjust the root node to properly handle its children node, in case the hierarchy is more complex.
You can read more at MSDN
Related
I have one single configuration XML file which can be deserialised into different instances, each of which takes only a portion of this XML.
class A
{
public string A { get; set; }
}
class B
{
public string B { get; set; }
}
public static T Xml2Cls<T>(string filename)
{
XDocument doc = XDocument.Load(filename);
var root = new XMLRootAttribte(doc.Root.Name.LocalName);
var serializer = new XMLSerializer(typeof(T), root);
using (var reader = doc.Root.CreateReader())
{
return (T)serializer .Deserialize(reader);
}
}
// if I keep calling the following for say 1000 times
// all these instances don't seem to get garbage collected
var a = Xml2Cls<A>("a.xml");
var b = Xml2Cls<B>("a.xml");
<root>
<a>...</a>
<b>...</b>
</root>
Any ideas why those instantiated objects are not garbage collocted? I tried moving the return out of the using block but it doesn't make a difference.
I have XML file which have some tags with dot(.), now i am using "StringWriter"
to Map XML data with C#, but i am not able to handle XML tags which have dot(.) in tag name like:- "Customer.Name", how can i map this with C# class.
I had give XmlElement with my class model, but still i am not getting values map with my class.
Can any one give me suggestion.
[XmlElement(ElementName = "PARENTNAME")]
public string PARENTNAME { get; set; } //This is perfect mapped
[XmlElement(ElementName = "DISPLAYCONTACT.CONTACTNAME")]
public string DISPLAYCONTACTCONTACTNAME { get; set; } // This is not mapped
[XmlElement(ElementName = "DISPLAYCONTACT.COMPANYNAME")]
public string DISPLAYCONTACTCOMPANYNAME { get; set; }
Convert XML to C#
XmlDocument doc = new XmlDocument();
doc.LoadXml(customerString);
StringWriter sw = new StringWriter();
XmlTextWriter xw = new XmlTextWriter(sw);
doc.WriteTo(xw);
String XmlString = sw.ToString();
string xmlToJson = JsonConvert.SerializeXmlNode(doc);
var deserialized = JsonConvert.SerializeXmlNode(doc);
var customer = new CusGetResIn();
customer= JsonConvert.DeserializeObject<CusGetResIn>(deserialized);
Also Tried:-
XmlSerializer serializer = new XmlSerializer(typeof(CusGetResIn));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(XmlString));
CusGetResIn resultingMessage = (CusGetResIn)serializer.Deserialize(memStream);
XML:-
<?xml version="1.0" encoding="UTF-8"?>
<response>
<control>
<status>success</status>
<senderid>Intacct_ISB</senderid>
<controlid>17/12/2018</controlid>
<uniqueid>false</uniqueid>
<dtdversion>3.0</dtdversion>
</control>
<operation>
<authentication>
<status>success</status>
<userid>vinit1</userid>
<companyid>FASTMORE-trial</companyid>
<locationid></locationid>
<sessiontimestamp>2018-12-19T00:41:15-08:00</sessiontimestamp>
</authentication>
<result>
<status>success</status>
<function>readByQuery</function>
<controlid>testFunctionId</controlid>
<data listtype="customer" count="31" totalcount="31" numremaining="0" resultId="">
<customer>
<RECORDNO>5</RECORDNO>
<CUSTOMERID>CUST-00101</CUSTOMERID>
<NAME>Sun Microsystems - EBC</NAME>
<ENTITY>CCUST-00101</ENTITY>
<PARENTKEY></PARENTKEY>
<PARENTID></PARENTID>
<PARENTNAME></PARENTNAME>
<DISPLAYCONTACT.CONTACTNAME>Sun Microsystems - EBC(CCUST-00101)</DISPLAYCONTACT.CONTACTNAME>
<DISPLAYCONTACT.COMPANYNAME>Sun Microsystems - EBC</DISPLAYCONTACT.COMPANYNAME>
<DISPLAYCONTACT.PREFIX></DISPLAYCONTACT.PREFIX>
<DISPLAYCONTACT.FIRSTNAME></DISPLAYCONTACT.FIRSTNAME>
<DISPLAYCONTACT.LASTNAME></DISPLAYCONTACT.LASTNAME>
<DISPLAYCONTACT.INITIAL></DISPLAYCONTACT.INITIAL>
<DISPLAYCONTACT.PRINTAS>Sun Microsystems - Executive Briefing Center</DISPLAYCONTACT.PRINTAS>
<DISPLAYCONTACT.TAXABLE>true</DISPLAYCONTACT.TAXABLE>
<DISPLAYCONTACT.TAXGROUP></DISPLAYCONTACT.TAXGROUP>
<DISPLAYCONTACT.PHONE1></DISPLAYCONTACT.PHONE1>
<DISPLAYCONTACT.PHONE2></DISPLAYCONTACT.PHONE2>
<DISPLAYCONTACT.CELLPHONE></DISPLAYCONTACT.CELLPHONE>
<DISPLAYCONTACT.PAGER></DISPLAYCONTACT.PAGER>
<DISPLAYCONTACT.FAX></DISPLAYCONTACT.FAX>
<DISPLAYCONTACT.EMAIL1>sevans#intacct.com</DISPLAYCONTACT.EMAIL1>
<DISPLAYCONTACT.EMAIL2></DISPLAYCONTACT.EMAIL2>
<DISPLAYCONTACT.URL1></DISPLAYCONTACT.URL1>
<DISPLAYCONTACT.URL2></DISPLAYCONTACT.URL2>
<DISPLAYCONTACT.VISIBLE>true</DISPLAYCONTACT.VISIBLE>
<DISPLAYCONTACT.MAILADDRESS.ADDRESS1>1245 Williams Lane</DISPLAYCONTACT.MAILADDRESS.ADDRESS1>
<DISPLAYCONTACT.MAILADDRESS.ADDRESS2></DISPLAYCONTACT.MAILADDRESS.ADDRESS2>
<DISPLAYCONTACT.MAILADDRESS.CITY>San Jose</DISPLAYCONTACT.MAILADDRESS.CITY>
<DISPLAYCONTACT.MAILADDRESS.STATE>CA</DISPLAYCONTACT.MAILADDRESS.STATE>
<DISPLAYCONTACT.MAILADDRESS.ZIP>95112</DISPLAYCONTACT.MAILADDRESS.ZIP>
<DISPLAYCONTACT.MAILADDRESS.COUNTRY>USA</DISPLAYCONTACT.MAILADDRESS.COUNTRY>
<DISPLAYCONTACT.MAILADDRESS.COUNTRYCODE></DISPLAYCONTACT.MAILADDRESS.COUNTRYCODE>
<DISPLAYCONTACT.MAILADDRESS.LATITUDE></DISPLAYCONTACT.MAILADDRESS.LATITUDE>
<DISPLAYCONTACT.MAILADDRESS.LONGITUDE></DISPLAYCONTACT.MAILADDRESS.LONGITUDE>
<DISPLAYCONTACT.STATUS>active</DISPLAYCONTACT.STATUS>
<TERMNAME>2/10 Net30</TERMNAME>
<TERMVALUE>2:10:1#30#1%:W:</TERMVALUE>
<CUSTREPID>EMP-002</CUSTREPID>
<CUSTREPNAME>Joanna Drake</CUSTREPNAME>
<RESALENO></RESALENO>
<TAXID></TAXID>
<CREDITLIMIT></CREDITLIMIT>
<TOTALDUE>3525172.72</TOTALDUE>
<COMMENTS></COMMENTS>
<ACCOUNTLABEL></ACCOUNTLABEL>
<ARACCOUNT>4000</ARACCOUNT>
<ARACCOUNTTITLE>Sales</ARACCOUNTTITLE>
<LAST_INVOICEDATE>10/01/2012</LAST_INVOICEDATE>
<LAST_STATEMENTDATE></LAST_STATEMENTDATE>
<DELIVERY_OPTIONS>Print#~#E-Mail</DELIVERY_OPTIONS>
<TERRITORYID></TERRITORYID>
<SHIPPINGMETHOD>Delivery</SHIPPINGMETHOD>
<CUSTTYPE>Corporate</CUSTTYPE>
<GLGRPKEY></GLGRPKEY>
<GLGROUP></GLGROUP>
<PRICESCHEDULE></PRICESCHEDULE>
<DISCOUNT></DISCOUNT>
<PRICELIST></PRICELIST>
<VSOEPRICELIST></VSOEPRICELIST>
<CURRENCY></CURRENCY>
<CONTACTINFO.CONTACTNAME></CONTACTINFO.CONTACTNAME>
<CONTACTINFO.PREFIX></CONTACTINFO.PREFIX>
<CONTACTINFO.FIRSTNAME></CONTACTINFO.FIRSTNAME>
<CONTACTINFO.INITIAL></CONTACTINFO.INITIAL>
<CONTACTINFO.LASTNAME></CONTACTINFO.LASTNAME>
<CONTACTINFO.COMPANYNAME></CONTACTINFO.COMPANYNAME>
<CONTACTINFO.PRINTAS></CONTACTINFO.PRINTAS>
<CONTACTINFO.PHONE1></CONTACTINFO.PHONE1>
<CONTACTINFO.PHONE2></CONTACTINFO.PHONE2>
<CONTACTINFO.CELLPHONE></CONTACTINFO.CELLPHONE>
<CONTACTINFO.PAGER></CONTACTINFO.PAGER>
<CONTACTINFO.FAX></CONTACTINFO.FAX>
<CONTACTINFO.EMAIL1></CONTACTINFO.EMAIL1>
<CONTACTINFO.EMAIL2></CONTACTINFO.EMAIL2>
<CONTACTINFO.URL1></CONTACTINFO.URL1>
<CONTACTINFO.URL2></CONTACTINFO.URL2>
<CONTACTINFO.VISIBLE></CONTACTINFO.VISIBLE>
<CONTACTINFO.MAILADDRESS.ADDRESS1></CONTACTINFO.MAILADDRESS.ADDRESS1>
<CONTACTINFO.MAILADDRESS.ADDRESS2></CONTACTINFO.MAILADDRESS.ADDRESS2>
<CONTACTINFO.MAILADDRESS.CITY></CONTACTINFO.MAILADDRESS.CITY>
<CONTACTINFO.MAILADDRESS.STATE></CONTACTINFO.MAILADDRESS.STATE>
<CONTACTINFO.MAILADDRESS.ZIP></CONTACTINFO.MAILADDRESS.ZIP>
<CONTACTINFO.MAILADDRESS.COUNTRY></CONTACTINFO.MAILADDRESS.COUNTRY>
<CONTACTINFO.MAILADDRESS.COUNTRYCODE></CONTACTINFO.MAILADDRESS.COUNTRYCODE>
<SHIPTO.CONTACTNAME></SHIPTO.CONTACTNAME>
<SHIPTO.PREFIX></SHIPTO.PREFIX>
<SHIPTO.FIRSTNAME></SHIPTO.FIRSTNAME>
<SHIPTO.INITIAL></SHIPTO.INITIAL>
<SHIPTO.LASTNAME></SHIPTO.LASTNAME>
<SHIPTO.COMPANYNAME></SHIPTO.COMPANYNAME>
<SHIPTO.PRINTAS></SHIPTO.PRINTAS>
<SHIPTO.TAXABLE></SHIPTO.TAXABLE>
<SHIPTO.TAXGROUP></SHIPTO.TAXGROUP>
<SHIPTO.PHONE1></SHIPTO.PHONE1>
<SHIPTO.PHONE2></SHIPTO.PHONE2>
<SHIPTO.CELLPHONE></SHIPTO.CELLPHONE>
<SHIPTO.PAGER></SHIPTO.PAGER>
<SHIPTO.FAX></SHIPTO.FAX>
<SHIPTO.EMAIL1></SHIPTO.EMAIL1>
<SHIPTO.EMAIL2></SHIPTO.EMAIL2>
<SHIPTO.URL1></SHIPTO.URL1>
<SHIPTO.URL2></SHIPTO.URL2>
<SHIPTO.VISIBLE></SHIPTO.VISIBLE>
<SHIPTO.MAILADDRESS.ADDRESS1></SHIPTO.MAILADDRESS.ADDRESS1>
<SHIPTO.MAILADDRESS.ADDRESS2></SHIPTO.MAILADDRESS.ADDRESS2>
<SHIPTO.MAILADDRESS.CITY></SHIPTO.MAILADDRESS.CITY>
<SHIPTO.MAILADDRESS.STATE></SHIPTO.MAILADDRESS.STATE>
<SHIPTO.MAILADDRESS.ZIP></SHIPTO.MAILADDRESS.ZIP>
<SHIPTO.MAILADDRESS.COUNTRY></SHIPTO.MAILADDRESS.COUNTRY>
<SHIPTO.MAILADDRESS.COUNTRYCODE></SHIPTO.MAILADDRESS.COUNTRYCODE>
<BILLTO.CONTACTNAME></BILLTO.CONTACTNAME>
<BILLTO.PREFIX></BILLTO.PREFIX>
<BILLTO.FIRSTNAME></BILLTO.FIRSTNAME>
<BILLTO.INITIAL></BILLTO.INITIAL>
<BILLTO.LASTNAME></BILLTO.LASTNAME>
<BILLTO.COMPANYNAME></BILLTO.COMPANYNAME>
<BILLTO.PRINTAS></BILLTO.PRINTAS>
<BILLTO.TAXABLE></BILLTO.TAXABLE>
<BILLTO.TAXGROUP></BILLTO.TAXGROUP>
<BILLTO.PHONE1></BILLTO.PHONE1>
<BILLTO.PHONE2></BILLTO.PHONE2>
<BILLTO.CELLPHONE></BILLTO.CELLPHONE>
<BILLTO.PAGER></BILLTO.PAGER>
<BILLTO.FAX></BILLTO.FAX>
<BILLTO.EMAIL1></BILLTO.EMAIL1>
<BILLTO.EMAIL2></BILLTO.EMAIL2>
<BILLTO.URL1></BILLTO.URL1>
<BILLTO.URL2></BILLTO.URL2>
<BILLTO.VISIBLE></BILLTO.VISIBLE>
<BILLTO.MAILADDRESS.ADDRESS1></BILLTO.MAILADDRESS.ADDRESS1>
<BILLTO.MAILADDRESS.ADDRESS2></BILLTO.MAILADDRESS.ADDRESS2>
<BILLTO.MAILADDRESS.CITY></BILLTO.MAILADDRESS.CITY>
<BILLTO.MAILADDRESS.STATE></BILLTO.MAILADDRESS.STATE>
<BILLTO.MAILADDRESS.ZIP></BILLTO.MAILADDRESS.ZIP>
<BILLTO.MAILADDRESS.COUNTRY></BILLTO.MAILADDRESS.COUNTRY>
<BILLTO.MAILADDRESS.COUNTRYCODE></BILLTO.MAILADDRESS.COUNTRYCODE>
<STATUS>active</STATUS>
<ONETIME>false</ONETIME>
<CUSTMESSAGEID></CUSTMESSAGEID>
<ONHOLD>false</ONHOLD>
<PRCLST_OVERRIDE>C</PRCLST_OVERRIDE>
<OEPRCLSTKEY></OEPRCLSTKEY>
<OEPRICESCHEDKEY></OEPRICESCHEDKEY>
<ENABLEONLINECARDPAYMENT>true</ENABLEONLINECARDPAYMENT>
<ENABLEONLINEACHPAYMENT>true</ENABLEONLINEACHPAYMENT>
<VSOEPRCLSTKEY></VSOEPRCLSTKEY>
<WHENMODIFIED>12/18/2018 16:07:40</WHENMODIFIED>
<ARINVOICEPRINTTEMPLATEID></ARINVOICEPRINTTEMPLATEID>
<OEQUOTEPRINTTEMPLATEID></OEQUOTEPRINTTEMPLATEID>
<OEORDERPRINTTEMPLATEID></OEORDERPRINTTEMPLATEID>
<OELISTPRINTTEMPLATEID></OELISTPRINTTEMPLATEID>
<OEINVOICEPRINTTEMPLATEID></OEINVOICEPRINTTEMPLATEID>
<OEADJPRINTTEMPLATEID></OEADJPRINTTEMPLATEID>
<OEOTHERPRINTTEMPLATEID></OEOTHERPRINTTEMPLATEID>
<WHENCREATED>01/01/1970 00:00:00</WHENCREATED>
<CREATEDBY></CREATEDBY>
<MODIFIEDBY>1</MODIFIEDBY>
<OBJECTRESTRICTION>Unrestricted</OBJECTRESTRICTION>
<DISPLAYCONTACTKEY>38</DISPLAYCONTACTKEY>
<CONTACTKEY></CONTACTKEY>
<SHIPTOKEY></SHIPTOKEY>
<BILLTOKEY></BILLTOKEY>
<CUSTREPKEY>2</CUSTREPKEY>
<SHIPVIAKEY>1</SHIPVIAKEY>
<TERRITORYKEY></TERRITORYKEY>
<TERMSKEY>1</TERMSKEY>
<ACCOUNTLABELKEY></ACCOUNTLABELKEY>
<ACCOUNTKEY>25</ACCOUNTKEY>
<CUSTTYPEKEY>1</CUSTTYPEKEY>
<PRICESCHEDULEKEY></PRICESCHEDULEKEY>
<OFFSETGLACCOUNTNO></OFFSETGLACCOUNTNO>
<OFFSETGLACCOUNTNOTITLE></OFFSETGLACCOUNTNOTITLE>
<ADVBILLBY></ADVBILLBY>
<ADVBILLBYTYPE></ADVBILLBYTYPE>
<SUPDOCID></SUPDOCID>
<MEGAENTITYKEY></MEGAENTITYKEY>
<MEGAENTITYID></MEGAENTITYID>
<MEGAENTITYNAME></MEGAENTITYNAME>
<RESTRICTEDLOCATIONS></RESTRICTEDLOCATIONS>
<RESTRICTEDDEPARTMENTS></RESTRICTEDDEPARTMENTS>
</customer></data>
</result>
</operation>
</response>
Please help me.
Quick test shows XmlSerializer can handle this pretty easily
Test class:
[XmlRoot]
public class Test
{
[XmlElement(ElementName="Foo.Alpha")]
public string Alpha {get;set;}
[XmlElement(ElementName="Foo.Beta")]
public string Beta {get;set;}
}
Example method:
private static void Main()
{
var src = #"<Test>
<Foo.Alpha>value 1</Foo.Alpha>
<Foo.Beta>value 2</Foo.Beta>
</Test>";
using (var sreader = new StringReader(src))
using (var reader = XmlReader.Create(sreader))
{
var serializer = new XmlSerializer(typeof(Test));
var test = (Test)serializer.Deserialize(reader);
Console.WriteLine(test.Alpha);
Console.WriteLine(test.Beta);
}
}
Update: since the XML document you are processing is very large, you should consider what you actually need to do. If you need to manipulate the entire document as objects then the approach taken in JP Hellemons's answer may be the way to go. If you are only interested in certain fields, then it may be better to load the XML into an XDocument or XmlDocument and extract the fields you are interested in from that, or even write a forward-only parser using XmlReader to do the same thing.
I have pasted your XML in an XMLFile1.xml and pasted it in Visual Studio to generate classes, so this will be a lot of autogenerated code... warning
could not fit auto gen code...
Body is limited to 30000 characters; you entered 93977
Full code here:
https://pastebin.com/VxzNUjsv
Smaller version:
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<RECORDNO>5</RECORDNO>
<CUSTOMERID>CUST-00101</CUSTOMERID>
<PARENTNAME>parent</PARENTNAME>
<DISPLAYCONTACT.CONTACTNAME>Sun Microsystems - EBC(CCUST-00101)</DISPLAYCONTACT.CONTACTNAME>
<DISPLAYCONTACT.COMPANYNAME>Sun Microsystems - EBC</DISPLAYCONTACT.COMPANYNAME>
</customer>
and C# code:
class Program
{
static void Main(string[] args)
{
using (var sreader = new StringReader(File.ReadAllText(#"C:\Users\JP\source\repos\soXmlParsing\soXmlParsing\XMLFile1.xml")))
using (var reader = XmlReader.Create(sreader))
{
var serializer = new XmlSerializer(typeof(customer));
var test = (customer)serializer.Deserialize(reader);
Console.WriteLine(test.PARENTNAME);
Console.WriteLine(test.DISPLAYCONTACTCONTACTNAME);
}
}
}
// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class customer
{
private byte rECORDNOField;
private string cUSTOMERIDField;
private string pARENTNAMEField;
private string dISPLAYCONTACTCONTACTNAMEField;
private string dISPLAYCONTACTCOMPANYNAMEField;
/// <remarks/>
public byte RECORDNO
{
get
{
return this.rECORDNOField;
}
set
{
this.rECORDNOField = value;
}
}
/// <remarks/>
public string CUSTOMERID
{
get
{
return this.cUSTOMERIDField;
}
set
{
this.cUSTOMERIDField = value;
}
}
/// <remarks/>
public string PARENTNAME
{
get
{
return this.pARENTNAMEField;
}
set
{
this.pARENTNAMEField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("DISPLAYCONTACT.CONTACTNAME")]
public string DISPLAYCONTACTCONTACTNAME
{
get
{
return this.dISPLAYCONTACTCONTACTNAMEField;
}
set
{
this.dISPLAYCONTACTCONTACTNAMEField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("DISPLAYCONTACT.COMPANYNAME")]
public string DISPLAYCONTACTCOMPANYNAME
{
get
{
return this.dISPLAYCONTACTCOMPANYNAMEField;
}
set
{
this.dISPLAYCONTACTCOMPANYNAMEField = value;
}
}
}
I searched and tried some attributes but none of them worked for my below scenario:
public class ObjSer
{
[XmlElement("Name")]
public string Name
{
get; set;
}
}
//Code to serialize
var obj = new ObjSer();
obj.Name = "<tag1>Value</tag1>";
var stringwriter = new System.IO.StringWriter();
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
serializer.Serialize(stringwriter, obj);
Output would be as follows:
<ObjSer><Name><tag1>Value</tag1></Name></ObjSer>
But I need output as:
<ObjSer><Name><tag1>Value</tag1></Name></ObjSer>
Scenario 2: In some cases I need to set:
obj.Name = "Value";
Is there any attribute or method I can override to make it possible?
You can't with default serializer. XmlSerializer does encoding of all values during serialization.
If you want your member to hold xml value, it must be XmlElement. Here is how you can accomplish it
public class ObjSer
{
[XmlElement("Name")]
public XmlElement Name
{
get; set;
}
}
var obj = new ObjSer();
// <-- load xml
var doc = new XmlDocument();
doc.LoadXml("<tag1>Value</tag1>");
obj.Name = doc.DocumentElement;
// --> assign the element
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
serializer.Serialize(Console.Out, obj);
Output:
<?xml version="1.0" encoding="IBM437"?>
<ObjSer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>
<tag1>Value</tag1>
</Name>
</ObjSer>
UPDATE:
In case if you want to use XElement instead of XmlElement, here is sample on how to do it
public class ObjSer
{
[XmlElement("Name")]
public XElement Name
{
get; set;
}
}
static void Main(string[] args)
{
//Code to serialize
var obj = new ObjSer();
obj.Name = XDocument.Parse("<tag1>Value</tag1>").Document.FirstNode as XElement;
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
serializer.Serialize(Console.Out, obj);
}
No, you can't. It is the natural and usual behaviour of the xml serializer. The serializer doesn't have to handle within the XML strings. So, it escapes the xml as expected.
You should decode the escaped string again while deserializing it.
If you want to add dynamically elements in the XML I suggest you to use Linq to XML and you can create tag1 or another kind of elements easily.
I would suggest serializing to an XDocument then converting that to a string and manually unescaping the desired part and writing it to a file. I would say this would give you the least headache it shouldn't be more than a couple lines of code. If you need it I can provide some code example if needed.
I found one more way of changing the type
public class NameNode
{
public string tag1
{
get; set;
}
[XmlText]
public string Value
{
get; set;
}
}
public class ObjSer
{
[XmlElement("Name")]
public NameNode Name
{
get; set;
}
}
To set value of Name:
var obj = new ObjSer();
var valueToSet = "<tag1>Value</tag1>";
//or var valueToSet = "Value";
//With XML tag:
if (valueToSet.Contains("</"))
{
var doc = new XmlDocument();
doc.LoadXml(valueToSet);
obj.Name.tag1 = doc.InnerText;
}
else //Without XML Tags
{
obj.Name.Value = senderRecipient.Name;
}
This solution will work in both cases, but has limitation. It will work only for predefined tags (ex. tag1)
I have a bunch of C# classes, which are auto generated from an XSD. Then I generate XML files based on those C# classes. Nothing existing so far.
The problem:
The generated XML files are going through validation and the validation requires an extra attribute to all XML tags with xsi:nil="true". Basically the tags should look like : <testTag.01 xsi:nil="true" NV="123123" />, but I can't achieve that in C#. My code is:
if (myObject.TestTag.HasValue)
{
t.testTag01 = new testTag01();
t.testTag01.Value = myObject.TestTag.Value;
}
//else
//{
// t.testTag01 = new testTag01();
// t.testTag01.NV = "123123";//Not Recorded
//}
This code generates <testTag.01>SomeValue</testTag.01> or <testTag.01 xsi:nil="true"/>.
If I uncomment the ELSE, the result would be: <testTag.01>SomeValue</testTag.01> or <testTag.01 NV="123123" />.
So I have no idea how to get to the format, which is required by the validation tool. Any ideas ?
P.S.
Here is the auto-generated C# class:
/// [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd",
"4.0.30319.33440")] [System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true,
Namespace="http://www.blabla.org")]
public partial class testTag01 {
private string nvField;
private SomeEnum valueField;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string NV {
get {
return this.nvField;
}
set {
this.nvField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public SomeEnum Value {
get {
return this.valueField;
}
set {
this.valueField = value;
}
} }
I wouldn't like to alter that part, but I understand it is impossible without doing it. Also I have tried to set SomeEnum to be Nullable. public SomeEnum? Value, but is throwing an exception:
Cannot serialize member 'Value' of type System.Nullable`1[]. XmlAttribute/XmlText cannot be used to encode complex types.
XmlSerializer doesn't directly support binding to elements that simultaneously have xsi:nil="true" along with other attribute values; see Xsi:nil Attribute Binding Support: The nil attribute and other attributes.
Thus, you need to emit the attribute manually.
If you want to be able to generate an element with no content and two attributes, one named NV and the other always being xsi:nil="true", you can modify your testTag01 class to have the NV property as well as a synthetic property having the correct namespace and name:
public class testTag01
{
[XmlAttribute]
public string NV { get; set; }
[XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Nil { get { return "true"; } set { } }
}
If you sometimes want to have xsi:nil="true" but at other times want the element to have content corresponding to your SomeEnum, you need to do something a bit more complicated, since the xsi:nil="true" must be suppressed when the element has content:
public class testTag01
{
[XmlAttribute]
public string NV { get; set; }
[XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Nil { get { return SomeEnum == null ? "true" : null; } set { } }
public bool ShouldSerializeNil() { return SomeEnum == null; }
[XmlIgnore]
public SomeEnum? SomeEnum { get; set; }
[XmlText]
public string SomeEnumText
{
get
{
if (SomeEnum == null)
return null;
return SomeEnum.Value.ToString();
}
set
{
// See here if one needs to parse XmlEnumAttribute attributes
// http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
value = value.Trim();
if (string.IsNullOrEmpty(value))
SomeEnum = null;
else
{
try
{
SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, false);
}
catch (Exception)
{
SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, true);
}
}
}
}
}
(An element that simultaneously has both xsi:nil="true" and content would be a violation of the XML standard; hopefully you don't have that.)
Then use it like:
public class TestClass
{
[XmlElement("testTag.01")]
public testTag01 TestTag { get; set; }
public static void Test()
{
Test(new TestClass { TestTag = new testTag01 { NV = "123123" } });
Test(new TestClass { TestTag = new testTag01 { NV = "123123", SomeEnum = SomeEnum.SomeValue } });
}
private static void Test(TestClass test)
{
var xml = test.GetXml();
var test2 = xml.LoadFromXML<TestClass>();
Console.WriteLine(test2.GetXml());
Debug.WriteLine(test2.GetXml());
if (test2.TestTag.NV != test.TestTag.NV)
{
throw new InvalidOperationException("test2.TestTag.NV != test.TestTag.NV");
}
}
}
The XML output looks like:
<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<testTag.01 NV="123123" xsi:nil="true" />
</TestClass>
Or
<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<testTag.01 NV="123123">SomeValue</testTag.01>
</TestClass>
Prototype fiddle using these extension methods:
public static class XmlSerializationHelper
{
public static T LoadFromXML<T>(this string xmlString, XmlSerializer serializer = null)
{
T returnValue = default(T);
using (StringReader reader = new StringReader(xmlString))
{
object result = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
if (result is T)
{
returnValue = (T)result;
}
}
return returnValue;
}
public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns = null, XmlWriterSettings settings = null, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
settings = settings ?? new XmlWriterSettings() { Indent = true, IndentChars = " " }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(typeof(T))).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
}
}
}
As expected there is no solution for that case out of the box, so I improvise a bit and achieved my goal in a post processing logic.
I am parsing the generated XML and if I am looking for a node with xsi:nil attribute, but without NV attribute - I add NV attribute with default value.
Same for the nodes with NV attribute, but no xsi:nil.
Here is the code:
XmlDocument doc = new XmlDocument();// instantiate XmlDocument and load XML from file
doc.Load("somepath.xml");
//Get the nodes with NV attribute(using XPath) and add xsi:nill to that nodes
XmlNodeList nodes = doc.SelectNodes("//*[#NV]");
foreach (XmlNode node in nodes)
{
XmlAttribute nilAttr = doc.CreateAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance");
nilAttr.Value = "true";
node.Attributes.Append(nilAttr);
}
//Get the nodes with xsi:nill attribute(using XPath) and add NV with default value to that nodes
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlNodeList nilNodes = doc.SelectNodes("//*[#xsi:nil]", nsManager);
foreach (XmlNode node in nilNodes)
{
XmlAttribute nvAttr = doc.CreateAttribute("NV");
nvAttr.Value = "7701003";
node.Attributes.Append(nvAttr);
}
doc.Save("somepath.xml");
The upper answer makes totally sense, but since these classes are auto-generated I will do it my way with the post processing, cause if the provider changes the XSD schema, my solution doesn't need any extra work. Thanks anyway.
I am just putting the finishing touches to my Zthes format deserializer (System.Xml.Serialization) which uses the namespace "dc" in the element "thes". All "term" elements are deserializing fine because they have no namespace but I cannot figure out how to tell the deserializer that the "thes" elements have a namespace.
Here is what I am trying to do (which isn't working) so hopefully someone could give me the proper syntax.
[XmlElement("namespace:someElement")]
public string SomeElement;
Here's a quick sample for you...
[XmlRoot("myObject")]
public class MyObject
{
[XmlElement("myProp", Namespace = "http://www.whited.us")]
public string MyProp { get; set; }
[XmlAttribute("myOther", Namespace = "http://www.whited.us")]
public string MyOther { get; set; }
}
class Program
{
static void Main(string[] args)
{
var xnames = new XmlSerializerNamespaces();
xnames.Add("w", "http://www.whited.us");
var xser = new XmlSerializer(typeof(MyObject));
using (var ms = new MemoryStream())
{
var myObj = new MyObject()
{
MyProp = "Hello",
MyOther = "World"
};
xser.Serialize(ms, myObj, xnames);
var res = Encoding.ASCII.GetString(ms.ToArray());
/*
<?xml version="1.0"?>
<myObject xmlns:w="http://www.whited.us" w:myOther="World">
<w:myProp>Hello</w:myProp>
</myObject>
*/
}
}
}
[XmlElement("someElement", Namespace="namespace")]
public string SomeElement;
Addendum: Make sure "namespace" is the full URI of the namespace, not just the prefix.