I have an XML document I'm trying to deseralize that has a attribute that is ref which in C# can not be used to declare a variable hence the below doesn't work
[XmlAttribute()]
public string ref;
Anyway to get this to deseralize properly? I know it is case sensitive so Ref wouldn't work.
You can provide a name in the attribute:
[XmlAttribute("ref")]
public string anynameyouwant;
You can change the attribute name in the xml file, by using the AttributeName, such as in the following example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace soans
{
public class Test
{
//problematic attribute (ref is reserved)
[XmlAttribute(AttributeName="ref")]
public string RefAttr {get;set;}
//other attributes as well
[XmlAttribute()]
public string Field { get; set; }
}
class Program
{
static void Main(string[] args)
{
string filename = ""; //use your path here
Test original = new Test()
{
RefAttr = "ref",
Field = "test"
};
//serialiser
XmlSerializer ser = new XmlSerializer(typeof(Test));
//save to file
TextWriter writer = new StreamWriter(filename);
ser.Serialize(writer, original);
writer.Close();
//read from file
TextReader reader = new StreamReader(filename);
var fromfile = ser.Deserialize(reader) as Test;
if(fromfile!=null)
{
Console.WriteLine(fromfile.RefAttr);
}
reader.Close();
Console.ReadKey();
}
}
}
Related
Trying to create an XML file of the following structure:
<Objects>
<ArrayOfObject1>
<Object1>
<Object1>
</ArrayOfObject1>
<ArrayOfObject2>
<Object2>
<Object2>
</ArrayOfObject2>
</Objects>
Is there any way to achieve this using the XmlSerializer? I'm aware that the following code snippet can be used to generate an XML file that has a root node of ArrayOfObject1 and elements corresponding to every object in the list; I'd just like to extend this to have a different root node, and an array of each object within it.
XmlSerializer serializer = new XmlSerializer(typeof(List<Object1>));
Of course, it may be best practice to have two different XML files, but I'm just trying to find out if there's an acceptable/sensible way to have two arrays of objects represented in a single file.
Thanks!
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication2
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(FILENAME, settings);
XmlSerializer serializer = new XmlSerializer(typeof(Objects));
Objects objects = new Objects()
{
objects1 = new List<Object1>()
{
new Object1(), new Object1()
},
objects2 = new List<Object2>()
{
new Object2(), new Object2()
}
};
serializer.Serialize(writer, objects);
}
}
public class Objects
{
[XmlArray("ArrayOfObject1")]
[XmlArrayItem("Object1")]
public List<Object1> objects1 { get; set; }
[XmlArray("ArrayOfObject2")]
[XmlArrayItem("Object2")]
public List<Object2> objects2 { get; set; }
}
public class Object1
{
}
public class Object2
{
}
}
I want to put a data from simple csv file into the records containing custom made class.
Here is my code:
using System;
using CsvHelper;
using System.IO; // for accessing the files
using System.Globalization;
using System.Linq; // to call a list enumerable
using CsvHelper.Configuration;
using CsvHelper.Configuration.Attributes;
namespace Reading_CSV_Files
{
class Program
{
static void Main(string[] args)
{
ReadCSVFile(#"C:\path_to_my_file\file.csv");
}
public static void ReadCSVFile(String filePath)
{
if (filePath == null)
{
return;
}
using (var streamReader = new StreamReader(filePath) )
{
using (var foodFileCSVReader = new CsvReader(streamReader,
CultureInfo.InvariantCulture))
{
//var records = foodFileCSVReader.GetRecords<dynamic>().ToList();
var records = foodFileCSVReader.GetRecords<Pizza>().ToList();
// replace dynamic type argument on our records
}
}
}
}
public class Pizza
{
// attributes
[Name("Name")]
public String Name { get; set; }
[Name("PLN_Cost")]
public double Price { get; set; }
}
}
The csv file looks like this:
Screenshot from csv file
The file was saved as comma separated. I found some advices with manual setting it up, but currently it says, this field is read-only.
CsvHelper.HeaderValidationException: Header with name 'Name'[0] was not found.
Header with name 'PLN_Cost'[0] was not found.
If the program is going to be using CSV files which might have a comma or semi-colon as the separator, you could read the first line and set the separator to either of those, like this:
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.Configuration.Attributes;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
public class Pizza
{
// attributes
[Name("Name")]
public String Name { get; set; }
[Name("PLN_Cost")]
public decimal Price { get; set; }
public override string ToString()
{
return $"{Name} - {Price}";
}
}
public static List<Pizza> ReadCSVFile(String filePath)
{
if (!File.Exists(filePath))
{
return new List<Pizza>();
}
var sep = ";";
/* Check the header for the separator character to use. */
string headerLine = File.ReadLines(filePath).First();
if (headerLine?.IndexOf(',') >= 0) { sep = ","; }
using (var sr = new StreamReader(filePath))
{
var config = new CsvConfiguration(CultureInfo.CurrentCulture)
{
Delimiter = sep,
Encoding = Encoding.UTF8
};
using (var foodFileCSVReader = new CsvReader(sr, config))
{
return foodFileCSVReader.GetRecords<Pizza>().ToList();
}
}
}
static void Main(string[] args)
{
var pp = ReadCSVFile(#"C:\temp\PizzaPrices.csv");
Console.WriteLine(string.Join("\r\n", pp));
Console.ReadLine();
}
}
}
Note that it is better to use the decimal type for money instead of the double type.
You might need additional code to set the decimal separator to be used.
I can't deserialize this XML to an object, I don't know what is wrong with this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ProcessOneWayEvent xmlns="http://schemas.microsoft.com/sharepoint/remoteapp/">
<properties xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CultureLCID>1033</CultureLCID>
</properties>
</ProcessOneWayEvent>
</s:Body>
</s:Envelope>
Here is a ready sample for this, is there any workaround, because I can't modify in the request, so is there any thing wrong with my models? And is there any solution to deserialize the XML without using XmlSerializer
https://dotnetfiddle.net/RfQMSD
Body and SPRemoteEventProperties need to be in the "http://schemas.microsoft.com/sharepoint/remoteapp/" namespace:
[DataContract(Name = "Body", Namespace = "http://schemas.microsoft.com/sharepoint/remoteapp/")]
public class Body
{
[DataMember(Name = "ProcessOneWayEvent")]
public ProcessOneWayEvent ProcessOneWayEvent;
}
[DataContract(Name = "properties", Namespace = "http://schemas.microsoft.com/sharepoint/remoteapp/")]
public class SPRemoteEventProperties
{
[DataMember(Name = "CultureLCID") ]
public int CultureLCID { get; set; }
}
The DataContractAttribute.Namespace controls the namespace that the data contract object's data member elements are serialized to, as well as the namespace of the root element when the data contract object is the root element. Since the element <ProcessOneWayEvent xmlns="http://schemas.microsoft.com/sharepoint/remoteapp/"> declares a new default XML namespace, the element itself, as well as its children, are in this namespace. Thus, the containing data contract object Body must set its data member namespace accordingly. As for <properties xmlns:i="http://www.w3.org/2001/XMLSchema-instance">, the i: namespace is not a default namespace, so no elements actually get assigned to this namespace and the SPRemoteEventProperties type should not not assign itself to it.
Fixed fiddle here.
I don't immediately see why it doesn't work, but one alternative is to use System.Xml.Serialization.XmlSerializer.
Start by creating the appropriate Envelope classes by copying the XML into a new class (Edit → Paste Special → Paste XML as Classes)
Then deserialize using this as an example:
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(request);
using (var stream = new MemoryStream(byteArray))
{
var serializer = new XmlSerializer(typeof(Envelope));
Envelope response = (Envelope)serializer.Deserialize(stream);
Console.WriteLine(JsonConvert.SerializeObject(response));
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringReader sReader = new StringReader(xml);
XmlReader reader = XmlReader.Create(sReader);
XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
Envelope envelope = (Envelope)serializer.Deserialize(reader);
}
}
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
}
public class Body
{
[XmlElement(ElementName = "ProcessOneWayEvent", Namespace = "http://schemas.microsoft.com/sharepoint/remoteapp/")]
public ProcessOneWayEvent ProcessOneWayEvent { get; set; }
}
public class ProcessOneWayEvent
{
public Properties properties { get; set; }
}
public class Properties
{
public string CultureLCID { get; set; }
}
}
Using Xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
XDocument doc = XDocument.Parse(xml);
string CultureLCID = (string)doc.Descendants().Where(x => x.Name.LocalName == "CultureLCID").FirstOrDefault();
}
}
}
How to create a C# class which must be used to deserialize the XML as given below
<?xml version="1.0" encoding="utf-8"?>
<XML>
<StatusCode>-2</StatusCode>
<Warnings />
<Errors>
<Error> Debtor #2 Invalid Postal Code</Error>
<Error>Invalid lien term</Error>
</Errors>
</XML>
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication110
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test.xml";
const string OUTPUT_FILENAME = #"c:\temp\test1.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(INPUT_FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(XML));
XML xml = (XML)serializer.Deserialize(reader);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(OUTPUT_FILENAME, settings);
serializer.Serialize(writer, xml);
}
}
public class XML
{
public int StatusCode { get; set; }
public string Warnings { get; set; }
[XmlArray("Errors")]
[XmlArrayItem("Error")]
public List<string> errors { get; set; }
}
}
To create classes based on XML, copy the xml to the clipboard, then in Visual Studio 2017, choose the menu option: Edit/Paste Special/Paste XML as classes.
Your Class should look like:
public class ErrorClass
{
struct Error
{
public String message;
}
struct Warning
{
public String message;
}
int StatusCode;
List<Error> Errors;
List<Warning> Warnings;
}
Error and Warning struct could contain more items that are not used in the example you posted.
[XmlRoot("Class1")]
class Class1
{
[(XmlElement("Product")]
public string Product{get;set;}
[(XmlElement("Price")]
public string Price{get;set;}
}
This is my class. In this the price contains the '£' symbol. after serializing it to XML I get the '?' instead of '£'.
what I need to do to get the '£' in XML? OR How can I pass the data in price as CDATA?
Your problem must be to do with how the XML is written to the file.
I've written a program that uses the information that you've given me so far, and it when I print the XML string out, it is correct.
I conclude that the error is happening either when the data is written to the XML file, or when it is read back in from the XML file.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
new Program().Run();
}
void Run()
{
Class1 test = new Class1();
test.Product = "Product";
test.Price = "£100";
Test(test);
}
void Test<T>(T obj)
{
XmlSerializerNamespaces Xsn = new XmlSerializerNamespaces();
Xsn.Add("", "");
XmlSerializer submit = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
XmlWriter writer = XmlWriter.Create(stringWriter);
submit.Serialize(writer, obj, Xsn);
var xml = stringWriter.ToString(); // Your xml This is the serialization code. In this Obj is the object to serialize
Console.WriteLine(xml); // £ sign is fine in this output.
}
}
[XmlRoot("Class1")]
public class Class1
{
[XmlElement("Product")]
public string Product
{
get;
set;
}
[XmlElement("Price")]
public string Price
{
get;
set;
}
}
}