write this xml in c# - c#

What's the best way to produce this xml programmatically and persist to file? The data source is just going to be a csv file (you may suggest the csv file be formed another way if it makes programming the xml easier (flexible in this area)):
business name, address line
Comapny Name 1, 123 Main St.
Company Name 2, 1 Elm St.
Company Name 2, 2 Eml St.
<?xml version="1.0"?>
<ArrayOfBusiness xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Business>
<Name>Company Name 1</Name>
<AddressList>
<Address>
<AddressLine>123 Main St.</AddressLine>
</Address>
</AddressList>
</Business>
<Business>
<Name>Company Name 2</Name>
<AddressList>
<Address>
<AddressLine>1 Elm St.</AddressLine>
</Address>
<Address>
<AddressLine>2 Elm St.</AddressLine>
</Address>
</AddressList>
</Business>
</ArrayOfBusiness>

string path = #"C:\Path\To\Output.xml";
List<Business> list = // set data
using (var streamWriter = new StreamWriter(new FileStream(path, FileMode.Write)))
{
using (var xmlWriter writer = new XmlTextWriter(streamWriter))
{
var serialiser = new XmlSerializer(typeof(List<Business>));
serialiser.Serialize(xmlWriter, list);
}
}

I understand now that you are simply trying to convert the CSV file to the (inferred) XML schema above.
To follow on from the reply from Jason, this should accomplish most of it for you and act as starter code:
internal string Convert()
{
string[] lines = {
"Company Name 1, 123 Main St.",
"Company Name 2, 1 Elm St.",
"Company Name 2, 2 Elm St"
};
//var lines = File.ReadLines(path);
var builder = new StringBuilder();
foreach (var line in lines)
{
var fields = line.Split(',');
var settings = new XmlWriterSettings {OmitXmlDeclaration = true};
using (var writer = XmlWriter.Create(builder, settings))
{
//writer.WriteStartDocument();
writer.WriteStartElement("ArrayofBusiness");
writer.WriteStartElement("Business");
writer.WriteElementString("Name", fields[0]);
writer.WriteStartElement("AddressList");
writer.WriteStartElement("Address");
writer.WriteElementString("AddressLine", fields[1]);
writer.WriteEndElement();//Address
writer.WriteEndElement();//AddressList
writer.WriteEndElement();//Business
writer.WriteEndElement();//ArrayOfBusiness
//writer.WriteEndDocument();
}
}
return builder.ToString();
}

I can understand the difficulty in answering this question. There are many ways to recreate the xml but each technique has a pro and con depending on the system
for example:
you could iterate the list and use the c# xml commands
you could add xml attributes to your classes and properties and push them through a serialiser
you could even spit the xml out directly from sql
On top of that we have to assume that the elements shown are all the elements available as you have not provided a schema.

Based on your comment, it looks like your question is actually about how to read, say, a CSV file and obtain a collection of Business objects based on the file.
I'll assume a Business class defined as follows:
class Business {
public string CompanyName { get; set; }
public string AddressLine { get; set; }
public Business(string companyName, string addressLine) {
this.CompanyName = companyName;
this.AddressLine = addressLine;
}
}
Then:
var businesses = new List<Business>();
var lines = File.ReadLines(path);
foreach(var line in lines) {
string[] fields = line.Split(',');
string companyName = fields[0];
string addressLine = fields[1];
Business business = new Business(companyName, addressLine);
businesses.Add(business);
}
Note that I'm assuming that no field contains an embedded comma.

Related

Deserializing a class into a file and back into a list

I am trying to deserialize a csv file into a list.
If there is a better way of sending my class' data into a file and then putting it back together into a list, please do let me know.
The class:
[Serializable]
public class Student
{
int studentID;
string studentName;
string studentAge;
}
The list:
List<Student> students = new List<Student>();
students.studentID = txt_sID.Text;
students.studentName = txt_sName.Text;
students.studentAge = txt_sAge.Text;
Serializer:
XmlSerializer SerializerObj = new XmlSerializer(typeof(Student));
TextWriter WriteFileStream = new StreamWriter(#"students.csv", true);
SerializerObj.Serialize(WriteFileStream, students);
WriteFileStream.Close();
Deserializer:
XmlSerializer serializer = new XmlSerializer(typeof(Student));
using (Stream reader = new FileStream(#"students.csv", FileMode.Open))
{
Student students2 = (Student)serializer.Deserialize(reader);
students.Add(students2);
}
Error:
XmlException: Unexpected XML declaration. The XML declaration must be the first node in the document, and no whitespace characters are allowed to appear before it.
The CSV file contents:
<?xml version="1.0" encoding="utf-8"?>
<Student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<studentID>1</studentID>
<studentName>Jonathan Joestar</studentName>
<studentAge>21</studentAge>
</Student><?xml version="1.0" encoding="utf-8"?>
What I have tried:
use XmlWriter.Create as a serializer to get rid of the Xml tags. The csv file must accept multiple entries and be put back into a list, which XmlWriter.Create can only do with one entry at one time (?).
Kind regards and thank you for your time.
I would suggest ignoring CSV and focusing on XML. CSV files essentially represents a table, and this cannot represent arbitrary object hierarchies. So in that aspect xml is more flexible.
To serialize a list of objects you should specify a list type when serializing. I.e. List<Student> or Student[]. For a complete example:
[Serializable]
public class Student
{
public int Id;
public string Name;
public float Age;
public Student() { }
public Student(int id, string name, float age)
{
Id = id;
Name = name;
Age = age;
}
}
public void SerializeDeserialize()
{
var xmlSerializer = new XmlSerializer(typeof(Student[]));
var ms = new MemoryStream();
var students = new Student[]
{
new Student(1, "Bob", 42),
new Student(2, "Alice", 22.4f)
};
xmlSerializer.Serialize(ms, students);
ms.Position = 0; // Reset stream to allow it to be deserialized
var deserialized = (Student[])xmlSerializer.Deserialize(ms);
}
Replace the memory stream with a file stream you want to save to a file.
Note that while xml is perfectly fine, most of the industry are moving to json. As far as I know json does not have any real technical advantage, so its more a issue of being less verbose and having serialization libraries that are a bit better.

How to get node values in XML file using c#

I have an XML file, in this XML you can see the RESPONSE_DATA tag. This tag have some more inner tags. I need to get all the values inside PERSON_DATA tags. Also i need to get all the other value in below xml file.
<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n
<HUMAN_VERIFICATION xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RESPONSE_DATA>
<RESPONSE_STATUS>
<ERROR>100</ERROR>
<MESSAGE>successful</MESSAGE>
</RESPONSE_STATUS>
<CONTACT_NUMBER>3120202456011</CONTACT_NUMBER>
<PERSON_DATA>
<NAME>Alex</NAME>
<DATE_OF_BIRTH>10-9-1982</DATE_OF_BIRTH>
<BIRTH_PLACE>Washington</BIRTH_PLACE>
<EXPIRY>2020-12-15</EXPIRY>
</PERSON_DATA>
<CARD_TYPE>idcard</CARD_TYPE>
</RESPONSE_DATA>
</HUMAN_VERIFICATION>
I prefer using Linq to Xml.
var results = doc.Descendants("PERSON_DATA") // Flatten the hierarchy and look for PERSON_DATA
.Select(x=> new
{
NAME = (string)x.Element("NAME"),
DATE_OF_BIRTH = (string)x.Element("DATE_OF_BIRTH"),
BIRTH_PLACE = (string)x.Element("BIRTH_PLACE"),
EXPIRY = (string)x.Element("EXPIRY"),
});
Check the Demo
You can try this code it may be helpful for you.
XmlDocument newdoc = new XmlDocument();
newdoc.InnerXml = " <?xml version=\"1.0\" encoding=\"utf-16\"?><HUMAN_VERIFICATION><RESPONSE_DATA><RESPONSE_STATUS><ERR>100</ERROR><MESSAGE>successful</MESSAGE></RESPONSE_STATUS><CONTACT_NUMBER>3120202456011</ CONTACT _NUMBER><PERSON_DATA><NAME>Alex</NAME><DATE_OF_BIRTH>10-9-1982</DATE_OF_BIRTH><BIRTH_PLACE>Washington</BIRTH_PLACE><EXPIRY>2020-12-15</EXPIRY></PERSON_DATA><CARD_TYPE>idcard</CARD_TYPE></RESPONSE_DATA></HUMAN_VERIFICATION>";
var selectnode = "HUMAN_VERIFICATION/RESPONSE_DATA/PERSON_DATA";
var nodes = newdoc.SelectNodes(selectnode);
foreach (XmlNode nod in nodes)
{
string name = nod["NAME" ].InnerText;
string dob = nod["DATE_OF_BIRTH"].InnerText;
string place = nod["BIRTH_PLACE" ].InnerText;
string expiry = nod["EXPIRY" ].InnerText;
Console.WriteLine("Person: {0} {1} {2} {3}", name, dob, place, expiry);
}
It's really easy and intuitive with System.Xml.Linq.
var xml = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<HUMAN_VERIFICATION xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <RESPONSE_DATA>\r\n <RESPONSE_STATUS>\r\n <ERROR>100</ERROR>\r\n <MESSAGE>successful</MESSAGE>\r\n </RESPONSE_STATUS>\r\n <CONTACT_NUMBER>3120202456011</CONTACT_NUMBER>\r\n <PERSON_DATA>\r\n <NAME>Alex</NAME>\r\n <DATE_OF_BIRTH>10-9-1982</DATE_OF_BIRTH>\r\n <BIRTH_PLACE>Washington</BIRTH_PLACE>\r\n <EXPIRY>2020-12-15</EXPIRY>\r\n </PERSON_DATA>\r\n <CARD_TYPE>idcard</CARD_TYPE>\r\n </RESPONSE_DATA>\r\n</HUMAN_VERIFICATION>";
var document = XDocument.Parse(xml);
var name = document.Element("HUMAN_VERIFICATION").Element("RESPONSE_DATA").Element("PERSON_DATA").Element("NAME").Value;
OR
var personData = document.Element("HUMAN_VERIFICATION").Element("RESPONSE_DATA").Element("PERSON_DATA").Elements().ToDictionary(e => e.Name.ToString(), e => e.Value);

XML - where node has same name but different values

I am trying to read an xml file (and later import the data in to a sql data base) which contains employees names address' etc.
The issue I am having is that in the xml the information for the address for the employee the node names are all the same.
<Employee>
<EmployeeDetails>
<Name>
<Ttl>Mr</Ttl>
<Fore>Baxter</Fore>
<Fore>Loki</Fore>
<Sur>Kelly</Sur>
</Name>
<Address>
<Line>Woof Road</Line>
<Line>Woof Lane</Line>
<Line>Woofington</Line>
<Line>London</Line>
</Address>
<BirthDate>1985-09-08</BirthDate>
<Gender>M</Gender>
<PassportNumber>123756rt</PassportNumber>
</EmployeeDetails>
</Employee>
I all other items are fine to extract and I have tried to use Linq to iterate through each "Line" node but it always just gives be the first Line and not the others.
var xAddreesLines = xEmployeeDetails.Descendants("Address").Select(x => new
{
address = (string)x.Element("Line").Value
});
foreach (var item in xAddreesLines)
{
Console.WriteLine(item.address);
}
I need to able to when I'm importing to my sql db that address line is separate variable
eg
var addressline1 = first <line> node
var addressline2 = second <line> node etc etc.
Any advice would be most welcome.
This should give you the expected output:-
var xAddreesLines = xdoc.Descendants("Address")
.Elements("Line")
.Select(x => new { address = (string)x });
You need to simply fetch the Line elements present inside Address node and you can project them. Also note there is no need to call the Value property on node when you use explicit conversion.
You can do it like this:
using System.Xml;
.
.
.
XmlDocument doc = new XmlDocument();
doc.Load("source.xml");
// if you have the xml in a string use doc.LoadXml(stringvar)
XmlNamespaceManager nsmngr = new XmlNamespaceManager(doc.NameTable);
XmlNodeList results = doc.DocumentElement.SelectNodes("child::Employee", nsmngr);
foreach (XmlNode result in results)
{
XmlNode namenode = result.SelectSingleNode("Address");
XmlNodeList types = result.SelectNodes("line");
foreach (XmlNode type in types)
{
Console.WriteLine(type.InnerText);
}
XmlNode fmtaddress = result.SelectSingleNode("formatted_address");
}
Refer to this question for the original source.

Parsing XML using C# [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Amazon Marketplace XML parsing
I am new to parsing XML in C# and I have some data from Amazon MWS library that is displayed below. I need to parse out various ItemAttributes such as ItemDimensions. I am use to JSON responses so I am not sure how to apply this to XML. Would it be possible from someone to point me in the right direction? I have Googled XML Parsing with C# but not valuable results were found to help me complete my tasks.
<GetMatchingProductResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
<GetMatchingProductResult ASIN="1430225491" status="Success">
<Product>
<Identifiers>
<MarketplaceASIN>
<MarketplaceId>ATVPDKIKX0DER</MarketplaceId>
<ASIN>1430225491</ASIN>
</MarketplaceASIN>
</Identifiers>
<AttributeSets>
<ns2:ItemAttributes xml:lang="en-US">
<ns2:Author>Troelsen, Andrew</ns2:Author>
<ns2:Binding>Paperback</ns2:Binding>
<ns2:Brand>Apress</ns2:Brand>
<ns2:Edition>5</ns2:Edition>
<ns2:ItemDimensions>
<ns2:Height Units="inches">9.21</ns2:Height>
<ns2:Length Units="inches">7.48</ns2:Length>
<ns2:Width Units="inches">2.52</ns2:Width>
<ns2:Weight Units="pounds">5.80</ns2:Weight>
</ns2:ItemDimensions>
<ns2:IsAutographed>false</ns2:IsAutographed>
<ns2:IsEligibleForTradeIn>true</ns2:IsEligibleForTradeIn>
<ns2:IsMemorabilia>false</ns2:IsMemorabilia>
<ns2:Label>Apress</ns2:Label>
<ns2:Languages>
<ns2:Language>
<ns2:Name>english</ns2:Name>
<ns2:Type>Unknown</ns2:Type>
</ns2:Language>
<ns2:Language>
<ns2:Name>english</ns2:Name>
<ns2:Type>Original Language</ns2:Type>
</ns2:Language>
<ns2:Language>
<ns2:Name>english</ns2:Name>
<ns2:Type>Published</ns2:Type>
</ns2:Language>
</ns2:Languages>
<ns2:ListPrice>
<ns2:Amount>59.99</ns2:Amount>
<ns2:CurrencyCode>USD</ns2:CurrencyCode>
</ns2:ListPrice>
<ns2:Manufacturer>Apress</ns2:Manufacturer>
<ns2:NumberOfItems>1</ns2:NumberOfItems>
<ns2:NumberOfPages>1752</ns2:NumberOfPages>
<ns2:PackageDimensions>
<ns2:Height Units="inches">2.60</ns2:Height>
<ns2:Length Units="inches">9.20</ns2:Length>
<ns2:Width Units="inches">7.50</ns2:Width>
<ns2:Weight Units="pounds">5.80</ns2:Weight>
</ns2:PackageDimensions>
<ns2:PartNumber>9781430225492</ns2:PartNumber>
<ns2:ProductGroup>Book</ns2:ProductGroup>
<ns2:ProductTypeName>ABIS_BOOK</ns2:ProductTypeName>
<ns2:PublicationDate>2010-05-14</ns2:PublicationDate>
<ns2:Publisher>Apress</ns2:Publisher>
<ns2:SmallImage>
<ns2:URL>http://ecx.images-amazon.com/images/I/51h9Sju5NKL._SL75_.jpg</ns2:URL>
<ns2:Height Units="pixels">75</ns2:Height>
<ns2:Width Units="pixels">61</ns2:Width>
</ns2:SmallImage>
<ns2:Studio>Apress</ns2:Studio>
<ns2:Title>Pro C# 2010 and the .NET 4 Platform</ns2:Title>
</ns2:ItemAttributes>
</AttributeSets>
<Relationships/>
<SalesRankings>
<SalesRank>
<ProductCategoryId>book_display_on_website</ProductCategoryId>
<Rank>43011</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>697342</ProductCategoryId>
<Rank>36</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>3967</ProductCategoryId>
<Rank>53</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>4013</ProductCategoryId>
<Rank>83</Rank>
</SalesRank>
</SalesRankings>
</Product>
</GetMatchingProductResult>
<ResponseMetadata>
<RequestId>440cdde0-fa76-4c48-bdd1-d51a3b467823</RequestId>
</ResponseMetadata>
</GetMatchingProductResponse>
I find "Linq To Xml" easier to use
var xDoc = XDocument.Parse(xml); //or XDocument.Load(filename);
XNamespace ns = "http://mws.amazonservices.com/schema/Products/2011-10-01";
var items = xDoc.Descendants(ns + "ItemAttributes")
.Select(x => new
{
Author = x.Element(ns + "Author").Value,
Brand = x.Element(ns + "Brand").Value,
Dimesions = x.Element(ns+"ItemDimensions").Descendants()
.Select(dim=>new{
Type = dim.Name.LocalName,
Unit = dim.Attribute("Units").Value,
Value = dim.Value
})
.ToList()
})
.ToList();
You could reinvent the wheel, or you could use Amazon's wheel (see #George Duckett's answer for the direct link):
Amazon Marketplace API
One option to address your question: if you want a tool that will enable you to work with your xml file, I would look at xsd.exe. MSDN for xsd.exe
This tool is able to generate classes from xml.
Otherwise, you can create a parser from the XDocument class that will allow you to use linq to build a parser such as #L.B noted in his post.
You have not made clear exactly what you need from the XML, so I cannot give you an objective answer. I'll begin by stating that there are many different ways to parse XML using .Net (and C# in your case, albeit they are similar with VB and C#).
The first one that I would look into is actually modeling your XML Data into .Net objects, more specifically, POCOs. To that class model you could add attributes that would bind or relate them to the XML and then all you'd need to do is pass the data and the class to a XML deserializer.
Now, if you don't need to retrieve the whole object, you can either use XDocument or XmlDocument. The fun part of XDocument is that its syntax in LINQ friendly, so you can parse you XML very simply.
XmlDocument is more old-style sequential method invocation, but achieves the same thing.
Let me illustrate. Consider a simpler XML, for simplicity sake's:
<body>
<h1>This is a text.</h1>
<p class="SomeClass">This is a paragraph</p>
</body>
(see what I did there? That HTML is a valid XML!)
I. Using A Deserializer:
First you model the classes:
[XmlRoot]
public class body
{
[XmlElement]
public h1 h1 { get; set; }
[XmlElement]
public p p { get; set; }
}
public class h1
{
[XmlText]
public string innerXML { get; set; }
}
public class p
{
[XmlAttribute]
public string id { get; set; }
[XmlText]
public string innerXML { get; set; }
}
Once you have your class model, you call the serializer.
void Main()
{
string xml =
#"<body>
<h1>This is a text.</h1>
<p id=""SomeId"">This is a paragraph</p>
</body>";
// Creates a stream that reads from the string
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
// Check the classes below before proceding.
XmlSerializer serializer = new XmlSerializer(typeof(body));
var obj = (body)serializer.Deserialize(stream);
// Check obj here with the debugger. All fields are filled.
}
II. Using XDocument
The example above makes for a very neat code, since you access everything typed. However, it demands a lot of setup work since you must model the classes. Maybe some simpler will suffice in your case. Let's say you want to get the attribute of the p element:
void Main()
{
string xml =
#"<body>
<h1>This is a text.</h1>
<p id=""SomeId"">This is a paragraph</p>
</body>";
// Creates a stream that reads from the string
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
// Using XDocument
var pAttrib = XDocument.Load(stream).Element("body").Element("p").Attribute("id").Value;
Console.Writeline(pAttrib);
}
Simple, huh? You can do more complex stuff throwing LINQ there... Let's try to find the element with id named "SomeId":
void Main()
{
string xml =
#"<body>
<h1>This is a text.</h1>
<p id=""SomeId"">This is a paragraph</p>
</body>";
// Creates a stream that reads from the string
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
// Using XDocument
var doc = XDocument.Load(stream);
var found = from body in doc.Elements("body")
from elem in body.Elements()
from attrib in elem.Attributes()
where attrib.Name == "id" && attrib.Value == "SomeId"
select elem;
foreach (var e in found) Console.WriteLine(e);
}
Hope it helps.

Parsing XML document using .Descendents(value)

I am trying to parse an xml document that I have created. However xml.Descendants(value) doesn't work if value has certain characters (including space, which is my problem).
My xml is structured like this:
<stockists>
<stockistCountry country="Great Britain">
<stockist>
<name></name>
<address></address>
</stockist>
</stockistCountry>
<stockistCountry country="Germany">
<stockist>
<name></name>
<address></address>
</stockist>
</stockistCountry>
...
</stockists>
And my C# code for parsing looks like this:
string path = String.Format("~/Content/{0}/Content/Stockists.xml", Helper.Helper.ResolveBrand());
XElement xml = XElement.Load(Server.MapPath(path));
var stockistCountries = from s in xml.Descendants("stockistCountry")
select s;
StockistCountryListViewModel stockistCountryListViewModel = new StockistCountryListViewModel
{
BrandStockists = new List<StockistListViewModel>()
};
foreach (var stockistCountry in stockistCountries)
{
StockistListViewModel stockistListViewModel = new StockistListViewModel()
{
Country = stockistCountry.FirstAttribute.Value,
Stockists = new List<StockistDetailViewModel>()
};
var stockist = from s in xml.Descendants(stockistCountry.FirstAttribute.Value) // point of failure for 'Great Britain'
select s;
foreach (var stockistDetail in stockist)
{
StockistDetailViewModel stockistDetailViewModel = new StockistDetailViewModel
{
StoreName = stockistDetail.FirstNode.ToString(),
Address = stockistDetail.LastNode.ToString()
};
stockistListViewModel.Stockists.Add(stockistDetailViewModel);
}
stockistCountryListViewModel.BrandStockists.Add(stockistListViewModel);
}
return View(stockistCountryListViewModel);
I am wondering if I am approaching the Xml parsing correctly, whether I shouldn't have spaces in my attributes etc? How to fix it so that Great Britain will parse
However xml.Descendants(value) doesn't work if value has certain characters
XElement.Descendants() expects an XName for the tag, not for the value.
And XML tags are indeed not allowed to contain spaces.
Your sample XML however only contains a value for an attribute, and the space there is fine.
Update:
I think you need
//var stockist = from s in xml.Descendants(stockistCountry.FirstAttribute.Value)
// select s;
var stockists = stockistCountry.Descendants("stockist");

Categories

Resources