Here I have a scenario that Create xml file dynamically and it should be serialisable. xml is like:
<person>
<personaldata>
<name>gopi</name>
<lastname>ch</lastname>
</personaladata>
<Educationaladata>
<Graduation>b.tech</graduation>
<designation>Engineer</designation>
</educationaldata>
</person>
person class has name, lastname, designation, graduation and properties
I tried this
public string CreateXmlObject(Person objPerson)
{
var objXmlDocument = new XmlDocument();
var objXpath = objXmlDocument.CreateNavigator();
var objXmlSeialiser = new XmlSerializer(objPerson.GetType());
using (var xs = objXpath.AppendChild())
{
objXmlSeialiser.Serialize(xs, objPerson);
}
return objXmlDocument.OuterXml;
}
My Problem is I have to read Specific data from Xml And Update Specific data to Xml . I want to read only Personaldata when i update, update should only apply to Personaldata Not Otherdata
Try xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string name = "gopi";
string lastname = "ch";
string graduation = "b.tech";
string designation = "Engineer";
XElement personalData = new XElement("person", new XElement[] {
new XElement("personaldata", new XElement[] {
new XElement("name", name),
new XElement("lastname", lastname)
}),
new XElement("Educationadata", new XElement[] {
new XElement("Graduation", graduation),
new XElement("designation", designation)
})
});
}
}
}
Fisrt of all your XML is invalid, all the nodes should match their closing tags. Considering your person class looks something like this:-
public class Person
{
public string name { get; set; }
public string lastname { get; set; }
public string Graduation { get; set; }
public string designation { get; set; }
}
You can easily do it with LINQ-to-XML:-
Xdocument = XDocument.Load("XMLFilePath");
List<Person> persons = (from person in xdoc.Descendants("person")
let personaldata = person.Element("personaldata")
let Educationaladata = person.Element("Educationaladata")
select new Person
{
name = (string)personaldata.Element("name"),
lastname = (string)personaldata.Element("lastname"),
Graduation = (string)Educationaladata.Element("Graduation"),
designation = (string)Educationaladata.Element("designation")
}).ToList();
sSometing like -
var xml = XDocument.Load("xml path");
var personaldata = xml.Descendents("personaldata").FirstOrDefault();
if (data != null)
{
foreach (var t in data.Descendants())
{
t.Value = "test";
}
}
Related
I have written a simple webAPI program which returns JSON by default when running , I want the values in XML format so I tried multiple answers from this stackoverflow post but all of them returns String for me
Model class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace JsonToXML2.Models
{
public class Employee
{
public int EmployeeId
{
get;
set;
}
public string EmployeeName
{
get;
set;
}
public string Address
{
get;
set;
}
public string Department
{
get;
set;
}
}
}
Controller Class :
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using System.Xml;
using System.Xml.Serialization;
namespace JsonToXML2.Controllers
{
public class EmployeeController : ApiController
{
IList<Employee> employees = new List<Employee>()
{
new Employee()
{
EmployeeId = 1, EmployeeName = "Mukesh Kumar", Address = "New Delhi", Department = "IT"
},
new Employee()
{
EmployeeId = 2, EmployeeName = "Banky Chamber", Address = "London", Department = "HR"
},
new Employee()
{
EmployeeId = 3, EmployeeName = "Rahul Rathor", Address = "Laxmi Nagar", Department = "IT"
},
new Employee()
{
EmployeeId = 4, EmployeeName = "YaduVeer Singh", Address = "Goa", Department = "Sales"
},
new Employee()
{
EmployeeId = 5, EmployeeName = "Manish Sharma", Address = "New Delhi", Department = "HR"
},
};
public IList<Employee> GetAllEmployees()
{
//Return list of all employees
return employees;
}
public String GetEmployeeDetails(int id)
{
//Return a single employee detail
var employee = employees.FirstOrDefault(e => e.EmployeeId == id);
if (employee == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return (GenerateXmlResponse(employee));
}
// override StringWriter
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
private string GenerateXmlResponse(Object obj)
{
Type t = obj.GetType();
var xml = "";
using (StringWriter sww = new Utf8StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sww))
{
var ns = new XmlSerializerNamespaces();
// add empty namespace
ns.Add("", "");
XmlSerializer xsSubmit = new XmlSerializer(t);
xsSubmit.Serialize(writer, obj, ns);
xml = sww.ToString(); // Your XML
}
}
return xml;
}
}
}
To access the app I am simply hitting the URL as https://localhost:44379/api/employee/1 in postman, the problem is data is in String format within double quotes, How can I get the data in pure XML format?
Postman recognizes the response as JSON
As I Discussed above one of the solution was to ask clients to set request header "Accept: text/xml"
Since I couldn't force the client, what I can do at my end is to set my method return type as System.Net.Http.HttpResponseMessage and use the below code to return the XML.
public HttpResponseMessage Authenticate()
{
//process the request
.........
string XML="<note><body>Message content</body></note>";
return new HttpResponseMessage()
{
Content = new StringContent(XML, Encoding.UTF8, "application/xml")
};
}
Response :
I'm using Linq/Lambda to write output to an XML file, just in the standard way:
new XElement("Employees",
from emp in empList
select new XElement("Employee",
new XAttribute("ID", emp.ID),
new XElement("FName", emp.FName),
new XElement("LName", emp.LName),
new XElement("DOB", emp.DOB),
new XElement("Sex", emp.Sex)
));
The issue I'm running into in effect is that my emp class contains fields that don't implement the IEnumerable interface, but which themselves also contain fields (imagine, for example, the emp included a "WorkHistory" field, which itself contained a set of fields related to complaints, commendations, etc). These latter fields are optional (and non-repeating) in the XML schema.
Is there any way of checking whether they have been set (i.e., whether they are null or not) given the Linq/Lambda framework? If they are not set, then the equivalent XML node needs to be absent.
Hope that made sense. I'm new to Linq/Lambda stuff, so sorry if it sounds confused.
I wrote a simple driver. In future, follow this guide when posting.
You can do this several ways. Out of curiosity, I tried out linq:
using System;
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
var empList = new List<Employee>();
for (int i=0; i<10; i++) {
empList.Add(GenerateTestEmployee(i));
}
var xmlConverter = new XmlConverter();
var employeesNode = new XElement(
"Employees",
empList.Select(emp => xmlConverter.Convert(emp))
);
Console.WriteLine(employeesNode.ToString());
}
private static Employee GenerateTestEmployee(int seed) {
return new Employee() {
ID = Guid.NewGuid(),
FName = seed.ToString(),
LName = "Example",
DOB = DateTime.UtcNow.AddYears(-20).AddYears(-seed),
Sex = seed % 2 == 0 ? "Male" : "Female",
WorkHistory = GenerateTestWorkHistory(seed)
};
}
private static WorkHistory GenerateTestWorkHistory(int seed) {
if (seed % 7 == 0) {
return null;
}
return new WorkHistory() {
Complaints = Enumerable.Repeat("Complaint!", seed % 2).ToList(),
Commendations = Enumerable.Repeat("Commendation!", seed % 3).ToList()
};
}
}
public class Employee {
public Guid ID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public DateTime DOB { get; set; }
public string Sex { get; set; }
public WorkHistory WorkHistory { get; set; }
}
public class WorkHistory {
public List<string> Complaints { get; set; }
public List<string> Commendations { get; set; }
}
public class XmlConverter {
public XElement Convert(Employee emp) {
var attributes = new List<XAttribute> {
new XAttribute("ID", emp.ID)
};
var elements = new List<XElement> {
new XElement("FName", emp.FName),
new XElement("LName", emp.LName),
new XElement("DOB", emp.DOB),
new XElement("Sex", emp.Sex)
};
var workHistory = Convert(emp.WorkHistory);
if (workHistory != null) {
elements.Add(workHistory);
}
return new XElement("Employee", attributes, elements);
}
private XElement Convert(WorkHistory hist) {
if (hist == null) {
return null;
}
var elements = new List<XElement>();
if (hist.Complaints != null && hist.Complaints.Any()) {
var complaints = new XElement(
"Complaints",
hist.Complaints.Select(comp => new XElement("Complaint", comp))
);
elements.Add(complaints);
}
if (hist.Commendations != null && hist.Commendations.Any()) {
var commendations = new XElement(
"Commendations",
hist.Commendations.Select(comm => new XElement("Commendation",comm))
);
elements.Add(commendations);
}
return elements.Any() ? new XElement("WorkHistory", elements)
: null;
}
}
}
Good luck!
PS: I find this online IDE helpful for testing snippets.
Using method syntax, as opposed to query syntax, you can build Employee element gradually, adding optional child elements only when it should :
new XElement("Employees",
empList.Select(emp => {
var xe = new XElement("Employee",
new XAttribute("ID", emp.ID),
....
));
// do further checks and add optional child elements accordingly
if (emp.WorkHistory != null) xe.Add(new XElement(...));
// return the final result
return xe;
})
)
Let me explain, there is a database table which has 1 XML column named audits and other common types of column.
so is this possible to deserialize below XML into class.
<?xml version="1.0"?>
<entity type="Order">
<id type="System.Int64">146</id>
<ordernumber type="System.String">OD555</ordernumber>
<audits type='System.String'>
<audit>
<item>
<create timestamp='2017-07-19 10:02:13' userid='23' />
</item>
<invoice>
<create timestamp='2017-07-19 10:03:37' userid='45' />
</invoice>
</audit>
</audits>
</entity>
Class:
public class Order
{
public long id { get; set; }
public string ordernumber { get; set; }
public string audits { get; set; }
}
Modifying your model with the attributes XmlType and XmlAnyElement (requires XmlElement as type)
[XmlType("entity")]
public class Order
{
public long id { get; set; }
public string ordernumber { get; set; }
[XmlAnyElement]
public XmlElement audits { get; set; }
}
allows to deserialize the complete XML string like
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(xmlString);
writer.Flush();
stream.Position = 0;
XmlSerializer serializer = new XmlSerializer(typeof(Order));
Order o = (Order)serializer.Deserialize(stream);
}
Now you are able to get the audits as string like
string auditsString = o.audits.InnerXml;
You can also add a property to your model to simplify the access:
public string auditsString
{
get
{
return audits.InnerXml;
}
}
Try xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication68
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Order order = doc.Descendants("entity").Select(x => new Order()
{
id = (long)x.Element("id"),
ordernumber = (string)x.Element("ordernumber"),
audits = x.Descendants("create").Select(y => (DateTime)y.Attribute("timestamp")).ToList()
}).FirstOrDefault();
}
}
public class Order
{
public long id { get; set; }
public string ordernumber { get; set; }
public List<DateTime> audits { get; set; }
}
}
You can try like this
const string xmlString = #"<columns><column><c1>100</c1><c2>200</c2><cn>300</cn></column><column><c1>111</c1><c2>222</c2><cn>333</cn></column> <column> <c1>MAX Newsletter</c1><c2>OLS Application</c2> <cn>Total funded accounts</cn> </column></columns>";
XDocument doc = XDocument.Parse(xmlString);
if (doc.Root != null)
{
List<Row> items = (from r in doc.Root.Elements("column")
select new Row
{
C1 = (string)r.Element ("C1"),
C2 = (string)r.Element("C2"),
}).ToList();
I want to write university courses in an xml file and be sorted by departments. So if I add a course from different departments I will get something like:
<Departments>
<FST_Department>
<Course_Details>
<Course_Name >Networking</Course_Name>
<Course_Code >xx</Course_Code>
</Course_Details>
</FST_Department >
<Medicine_Department>
<Course_Details>
<Course_Name >General_Medicine</Course_Name>
<Course_Code >xxxxxxx</Course_Code>
</Course_Details>
</Medicine_Department>
</Departments
But instead all my courses go inside the last department I added a course to and the other department 'tags' disapear.Like below.
<Departments>
<Medicine_Department>
<Course_Details>
<Course_Name >Networking</Course_Name>
<Course_Code >xx</Course_Code>
</Course_Details>
<Course_Details>
<Course_Name >General Medicine</Course_Name>
<Course_Code >xxxxxxx</Course_Code>
</Course_Details>
</Medicine_Department>
</Departments
The code to create the xml file .
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (!Directory.Exists(path = "E:\\Sorting\\Directory"))
Directory.CreateDirectory(path = "E:\\Sorting\\Directory");
if (!File.Exists(path = "E:\\Sorting\\Directory\\Sort.xml"))
{
XmlTextWriter xW = new XmlTextWriter(path ="E:\\Sorting\\Directory\\Sort.xml", Encoding.UTF8);
xW.WriteStartElement("Departments");//my root
xW.WriteEndElement(); // Departments
xW.Close();
This is the code I use to add data to the xml file :
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
XmlDocument xDoc = new XmlDocument();
xDoc.Load("E:\\Sorting\\Directory\\Sort.xml");
XmlNode xNode = xDoc.SelectSingleNode("Departments");
xNode.RemoveAll();
if (combboBox.Text == "FST")
{
XmlNode xDepartmentNode = xDoc.CreateElement("FST_Department");
foreach (Course c in courses)
{
XmlNode xCourse_Details = xDoc.CreateElement("Course_Details");
XmlNode xCode = xDoc.CreateElement("Course_Code");
xCode.InnerText = c.courseCode;
xCourse_Details.AppendChild(xCode);
XmlNode xName = xDoc.CreateElement("Course_Name");
xName.InnerText = c.courseName;
xCourse_Details.AppendChild(xName);
xDepartmentNode.AppendChild(xCourse_Details);
xDoc.DocumentElement.AppendChild(xDepartmentNode);
xDoc.Save("E:\\Sorting\\Directory\\Sort.xml");
}
}
else if(combbobox.Text == "Medicine")
{
XmlNode xDepartmentNode = xDoc.CreateElement("Medicine_Department");
foreach (Course c in courses)
{
XmlNode xCourse_Details = xDoc.CreateElement("Course_Details");
XmlNode xCode = xDoc.CreateElement("Course_Code");
xCode.InnerText = c.courseCode;
xCourse_Details.AppendChild(xCode);
XmlNode xName = xDoc.CreateElement("Course_Name");
xName.InnerText = c.courseName;
xCourse_Details.AppendChild(xName);
xDepartmentNode.AppendChild(xCourse_Details);
xDoc.DocumentElement.AppendChild(xDepartmentNode);
xDoc.Save("E:\\Sorting\\Directory\\Sort.xml");
}
}
You clear all departments with this line. So anything that was there before is wiped from the file:
xNode.RemoveAll();
Second, with your foreach on courses, you will add all the courses to that department. Since you neither sort or filter the courses by department, you are getting them all into whatever department combobox.Text is selecting.
Scrap it and use XML Serialization lol
Departments Class
using System.Xml.Serialization;
namespace Serializer
{
public class Departments
{
public FST_Department FST_Department { get; set; }
public Medicine_Department Medicine_Department { get; set; }
}
}
FST_Department Class
using System.Collections.Generic;
namespace Serializer
{
public class FST_Department
{
public List<Course> Course_Details { get; set; }
}
}
Medicine_Department Class
using System.Collections.Generic;
namespace Serializer
{
public class Medicine_Department
{
public List<Course> Course_Details { get; set; }
}
}
Course Class
namespace Serializer
{
public class Course
{
public string Course_Name { get; set; }
public string Course_Code { get; set; }
}
}
Read and write serialized xml
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
namespace Serializer
{
class XMLManager
{
private const string configFileName = "Departments.xml";
public static Departments Read()
{
XmlSerializer reader = new XmlSerializer(typeof(Departments));
using (FileStream file = File.OpenRead(Path.Combine(Global.AppRoot, configFileName)))
{
return reader.Deserialize(file) as Departments;
}
}
public static void Write(Departments settings)
{
XmlSerializer writer = new XmlSerializer(typeof(Departments));
using (FileStream file = File.Create(Path.Combine(Global.AppRoot, configFileName)))
{
writer.Serialize(file, settings);
}
}
}
}
Usage
Departments depart = new Departments();
FST_Department fst = new FST_Department();
fst.Course_Details = new List<Course>();
Course course = new Course();
course.Course_Code = "1";
course.Course_Name = "Test 1";
fst.Course_Details.Add(course);
course = new Course();
course.Course_Code = "2";
course.Course_Name = "Test2";
fst.Course_Details.Add(course);
depart.FST_Department = fst;
Medicine_Department med = new Medicine_Department();
med.Course_Details = new List<Course>();
course = new Course();
course.Course_Code = "3";
course.Course_Name = "Test 3";
med.Course_Details.Add(course);
depart.Medicine_Department = med;
//put it all in some kind of order in case things were added out of order
depart.FST_Department.Course_Details.OrderBy(c => c.Course_Code);
depart.Medicine_Department.Course_Details.OrderBy(c => c.Course_Code);
XMLManager.Write(depart);
XML File Output
<?xml version="1.0"?>
<Departments xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FST_Department>
<Course_Details>
<Course>
<Course_Name>Test 1</Course_Name>
<Course_Code>1</Course_Code>
</Course>
<Course>
<Course_Name>Test2</Course_Name>
<Course_Code>2</Course_Code>
</Course>
</Course_Details>
</FST_Department>
<Medicine_Department>
<Course_Details>
<Course>
<Course_Name>Test 3</Course_Name>
<Course_Code>3</Course_Code>
</Course>
</Course_Details>
</Medicine_Department>
</Departments>
I've been using a file like the following to hold data:
field1 field2 field3 field4
myname myhashedpass myemail#email.com more stuff after
etc etc etc etc
Each line is converted into strings (Name, Pass, Email)
I'd like to get my text file (see above) converted into an XML file, like this:
<person1>
<name>myname</name>
<pass>myhashedpass</pass>
<email>etc</email>
</person1>
<person2>
etc etc etc etc
basically, I'm stuck on how to do this migration and also manipulate the XML data in the same way that I do with the text data
The litteral answer to your question is this:
using System;
using System.Linq;
using System.Xml.Linq;
namespace XmlSerialization
{
class Program
{
static void Main(string[] args)
{
var person1 = new Person();
person1.Name = "Joe";
person1.Password = "Cla$$ified";
person1.Email = "none#your.bussiness";
var person2 = new Person();
person2.Name = "Doe";
person2.Name = "$ecret";
person2.Email = "dont#spam.me";
var persons = new[] {person1, person2};
XElement xml = new XElement("persons",
from person in persons
select new XElement("person",
new XElement("name", person.Name),
new XElement("password", person.Password),
new XElement("email", person.Email))
);
xml.Save("persons.xml");
XElement restored_xml = XElement.Load("persons.xml");
Person[] restored_persons = (from person in restored_xml.Elements("person")
select new Person
{
Name = (string)person.Element("name"),
Password = (string)person.Element("password"),
Email = (string)person.Element("email")
})
.ToArray();
foreach (var person in restored_persons)
{
Console.WriteLine(person.ToString());
}
Console.ReadLine();
}
}
public class Person
{
public string Name { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public override string ToString()
{
return string.Format("The person with name {0} has password {1} and email {2}",
this.Name, this.Password, this.Email);
}
}
}
However, it is much better to let the built-in serializattion classes do the translation to and from XML for you. The code below needs an explicit reference to the System.Runtime.Serialization.dll. The using statement in itself is not enough:
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Runtime.Serialization;
namespace XmlSerialization
{
class Program
{
static void Main(string[] args)
{
var person1 = new Person();
person1.Name = "Joe";
person1.Password = "Cla$$ified";
person1.Email = "none#your.bussiness";
var person2 = new Person();
person2.Name = "Doe";
person2.Name = "$ecret";
person2.Email = "dont#spam.me";
var persons = new[] {person1, person2};
DataContractSerializer serializer=new DataContractSerializer(typeof(Person[]));
using (var stream = new FileStream("persons.xml", FileMode.Create, FileAccess.Write))
{
serializer.WriteObject(stream,persons);
}
Person[] restored_persons;
using (var another_stream=new FileStream("persons.xml",FileMode.Open,FileAccess.Read))
{
restored_persons = serializer.ReadObject(another_stream) as Person[];
}
foreach (var person in restored_persons)
{
Console.WriteLine(person.ToString());
}
Console.ReadLine();
}
}
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public string Email { get; set; }
public override string ToString()
{
return string.Format("The person with name {0} has password {1} and email {2}",
this.Name, this.Password, this.Email);
}
}
}
so to read out your original file, you have something like:
var people = File.ReadAllLines("filename"))
.Select(line => {
var parts = line.Split();
return new Person {
Name = parts[0],
Password = parts[1],
Email = parts[2]
});
then you can write out to xml by:
var serializer = new XmlSerializer(typeof(Person));
var xmlfile = File.OpenWrite("somefile");
foreach(var person in people)
serializer.Serialize(person, xmlfile);
You may want to take a look at this XML Serialization tutorial. Serialization can save you a lot of work loading and saving the XML file.
Linq provides a nice way to construct XML using the XNodes:
from p in person
select new XElement("person",
from s in p.Keys
select new XElement(s, p[s]));
Easy as cake.
It's not exactly clear from your question, but it sounds like you are serializing a Person class to a text file. This is probably the perfect use case for the XmlSerializer.
Example code:
class Person
{
// XmlSerializer requires parameterless constructor
public Person()
{
}
public string Name { get; set; }
public string Pass { get; set; }
public string Email { get; set; }
public string Host { get; set; }
}
// ...
XmlSerializer serializer = new XmlSerializer(typeof(Person));
// Write a person to an XML file
Person person = new Person() { Name = "N", Pass = "P", Email = "E", Host = "H" };
using (XmlWriter writer = XmlWriter.Create("person.xml"))
{
serializer.Serialize(writer);
}
// Read a person from an XML file
using (XmlReader reader = XmlReader.Create("person.xml"))
{
person = (Person)serializer.Deserialize(reader);
}