how can I turn a set of csv lines into xml? - c#

Is there a way to take a spreadsheet and turn it into xml file below?
<?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>

I put this in LinqPad and it did what you needed. If you've never used LinqPad... well now's a great time to start.
var csvs = new List<string>();
csvs.Add( "Company Name 1,123 Main St.");
csvs.Add("Company Name 2,1 Elm St.,2 Elm St.");
var xml =
(from c in csvs
let split = c.Split(',')
select // split
new XElement("ArrayOfBusiness",
new XElement("Business",
new XElement("Name", split[0] ),
new XElement("AddressList",
new XElement("Address"
,
(from s in split.Skip(1) // skip the first split
select
new XElement("AddressLine", s))
)
)))); // <-- is it LISP?
xml.Dump();
Results:
<ArrayOfBusiness>
<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>
<AddressLine>2 Elm St.</AddressLine>
</Address>
</AddressList>
</Business>
</ArrayOfBusiness>
It isn't exactly what you wanted, but looks functionally equivalent to me. Might need a bit of tweaking in the LINQ.
Write to file with: File.WriteAllText(#"c:\temp\addresses.xml", xml.ToString());

Parsing the .csv file into 'Business' objects should be straightforward.
Its then a simple case of using the XmlSerializer class to generate the xml.

I would say yes, but with out seeing the CSV file it is hard to say.
If your CSV was somthing like this:
Name, Address1, Address2
Company Name 1,123 Main St.,
Company Name 2,1 Elm St.,1 Elm St.
you could easily parse this into a class.
class Business
{
public string Name { get; set; }
public List<Address> AddressList { get; set; }
}
class Address
{
public string AddressLine { get; set; }
}
(untested)

Related

Extract XML from CData

I have the following problem. I need to write an application in C# that will read a given XML and prepare data for me to load into the database. In XML, the structure of which I have no influence, the main data is placed in CDATA. I have verified that the structure of this data is ordered in the correct XML structure.
I've searched hundreds of posts and can't find any solution from them. Below is the XML file from which I need to extract the data from the CDATA section. Maybe one of you can help me?
<Docs>
<Doc>
<Content>
<![CDATA[
<Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header DocNumber="1" Description="Desc1"></Header>
<Poss>
<Pos Id="1" Name="Pos1"></Pos>
<Pos Id="2" Name="Pos2"></Pos>
</Poss>
</Doc>
]]>
</Content>
</Doc>
<Doc>
<Content>
<![CDATA[
<Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header DocNumber="2" Description="Desc2"></Header>
<Poss>
<Pos Id="3" Name="Pos3"></Pos>
<Pos Id="4" Name="Pos4"></Pos>
</Poss>
</Doc>
]]>
</Content>
</Doc>
</Docs>
For me, the most important are the fields contained in the Content section and I have to load them as data into the database.
To extract the data from the CData part,
Construct the classes.
public class Doc
{
public Header Header { get; set; }
[XmlArrayItem(typeof(Pos), ElementName = "Pos")]
public List<Pos> Poss { get; set; }
}
public class Header
{
[XmlAttribute]
public int DocNumber { get; set; }
[XmlAttribute]
public string Description { get; set; }
}
public class Pos
{
[XmlAttribute]
public int Id { get; set; }
[XmlAttribute]
public string Name { get; set; }
}
Implement the extraction logic.
2.1. Read the XML string as XDocument via XDocument.Parse().
2.2. Select the DescendantNodes for the XPath of "/Docs/Doc/Content".
2.3. Convert the nodes to XCData type.
2.4. With XmlSerializer to deserialize the value of XCData to Doc type.
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml.Serialization;
using System.IO;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Doc));
XDocument xDoc = XDocument.Parse(xml);
var cdataSections = xDoc.XPathSelectElements("/Docs/Doc/Content")
.DescendantNodes()
.OfType<XCData>()
.Select(x => (Doc)xmlSerializer.Deserialize(new StringReader(x.Value)))
.ToList();
Demo # .NET Fiddle
Here is implementation based on a stored procedure with the XML parameter like in my comments.
I had to remove the <Poss> XML element to make CData section a well-formed XML.
SQL
DECLARE #xml XML =
N'<Docs>
<Doc>
<Content><![CDATA[
<Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header DocNumber="1" Description="Desc1"></Header>
<Pos Id="1" Name="Pos1"></Pos>
<Pos Id="2" Name="Pos2"></Pos>
</Doc>
]]>
</Content>
</Doc>
<Doc>
<Content><![CDATA[
<Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header DocNumber="2" Description="Desc2"></Header>
<Pos Id="3" Name="Pos3"></Pos>
<Pos Id="4" Name="Pos4"></Pos>
</Doc>
]]>
</Content>
</Doc>
</Docs>';
--INSERT INTO <targetTable>
SELECT h.value('(Header/#DocNumber)[1]', 'INT') AS DocNumber
, h.value('(Header/#Description)[1]', 'VARCHAR(256)') AS DocDescription
, d.value('#Id', 'INT') AS posID
, d.value('#Name', 'VARCHAR(256)') AS posName
FROM #xml.nodes('/Docs/Doc/Content/text()') AS t(c)
CROSS APPLY (SELECT TRY_CAST(c.query('.').value('.', 'NVARCHAR(MAX)') AS XML)) AS t1(x)
CROSS APPLY x.nodes('/Doc') AS t2(h)
CROSS APPLY h.nodes('Pos') AS t3(d);
Output
DocNumber
DocDescription
posID
posName
2
Desc2
3
Pos3
2
Desc2
4
Pos4
1
Desc1
1
Pos1
1
Desc1
2
Pos2

how to call for values inside the last object in xml, using c#

This is my xml and I want to get the value of the
of the last friend(than means only want the <fname>5</fname>'s <streetname></streetname>). how can I do that. I used XElement with Last(), but it didn't work for me.
<start>
<option>
<name></name>
<gender></gender>
<hometown>
<street1></street1>
<street2></street2>
</hometown>
<friend>
<fname>1</fname>
<lname></lname>
<address>
<number></number>
<streetname></streetname>
</address>
</friend>
<friend>
<fname>2</fname>
<lname></lname>
<address>
<number></number>
<streetname></streetname>
</address>
</friend>
<friend>
<fname>3</fname>
<lname></lname>
<address>
<number></number>
<streetname></streetname>
</address>
</friend>
<friend>
<fname>4</fname>
<lname></lname>
<address>
<number></number>
<streetname></streetname>
</address>
</friend>
<friend>
<fname>5</fname>
<lname></lname>
<address>
<number></number>
<streetname></streetname>
</address>
</friend>
</option>
</start>
this is my code.
XElement rootele = XElement.Load(Server.MapPath("~/XmlFiles/CruiseData/cruiseprodutstwo.xml"));
var getneededData = rootele.Elements("CruiseProduct")
.Where(l => l.Element("Location").Value == destination && l.Element("Types").Element("Type").Value == cruisetype);
foreach (var itm in getneededData)
{
d.Add(new Details
{
numberofDays = itm.Element("Itinerary").Element("ItineraryItem").Element("EndDay")//I want it in here
});
}
Use Elements() instead of singular Element(). The latter always return the first matched element without any additional method call, but you want the last here :
numberofDays = itm.Elements("Itinerary").Elements("ItineraryItem").Elements("EndDay").Last();
You can use XPath to extract this value:
using System.Xml.Linq;
using System.Xml.XPath;
XDocument xDocument = XDocument.Parse(xmlString);
string lastStreetname = xDocument
.XPathSelectElement("start/option/friend[last()]/address/streetname")
.Value;
Note that your XML is invalid. It should be a closing </option> tag in the end of your XML instead of <option>.

Reaching a specific Xmlnode from root using XPath with nested indexes

I have this xml string that I have to get a specific node
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.XPath;
//Xml string that has xml content
string xmlStr = "<Candidate>
<Content>
<DOB>14-Jan-1976</DOB>
<Employers>
<Employer>
<Name>Diane Trucking</Name>
<Addresses>
<Address>
<AddressLine1>1st Street</AddressLine1>
<AddressLine2/>
<City>First City</City>
<State>FL</State>
<Zip>12345</Zip>
</Address>
<Address>
<AddressLine1>1st Street</AddressLine1>
<AddressLine2/>
<City>Second City</City>
<State>FL</State>
<Zip>12346</Zip>
</Address>
<Address>
<AddressLine1>3rd Street</AddressLine1>
<AddressLine2/>
<City>Third City</City>
<State>FL</State>
<Zip>12347</Zip>
</Address>
</Addresses>
</Employer>
<Employer>
<Name>Tom Trucking</Name>
<Addresses>
<Address>
<AddressLine1>4th Street</AddressLine1>
<AddressLine2/>
<City>Fourth City</City>
<State>FL</State>
<Zip>12348</Zip>
</Address>
<Address>
<AddressLine1>5th Street</AddressLine1>
<AddressLine2/>
<City>Fifth City</City>
<State>FL</State>
<Zip>12349</Zip>
</Address>
<Address>
<AddressLine1>6th Street</AddressLine1>
<AddressLine2/>
<City>Sixth City</City>
<State>FL</State>
<Zip>12340</Zip>
</Address>
</Addresses>
</Employer>
</Employers>
</Content>
</Candidate>";
// Create xml Document
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlStr);
Navigator for alternative testing
XPathNavigator xPathNav = xmlDoc.CreateNavigator();
XPathExpression expr = XPathExpression.Compile("/Candidate/Content/Employers['1']/Employer['1']/Addresses['1']/Address");
Expression to read/Target xml specific xml node
XPathNodeIterator xPathIt = xPathNav.Select(expr);
if(xPathIt == null)
{
... xPathIt.Count is also 6
}
var xmlNodes1 = xmlDoc.SelectNodes("/Candidate/Content/Employers['1']/Employer['1']/Addresses['1']/Address");
for (int i = 0; i < xmlNodes1.Count; i++ )
{
...xmlNodes1.Count = 6. Returns all 6 address nodes , was expecting 3 nodes of "address" for the specific employers/employer/addresses/address
}
Both xPathIt as well as xmlNodes1 return 6 "Address" elements
I expected it to return 3 elements as there are 3 addresses for an employer
I wanted to target any element in the xml from root
Also, If I can do this I will be able to update the specific element.
Appreciate the help
Thank you
Try removing the single quotes from your XPath:
var xmlNodes1 = xmlDoc.SelectNodes("/Candidate/Content/Employers['1']/Employer['1']/Addresses['1']/Address");
should be
var xmlNodes1 = xmlDoc.SelectNodes("/Candidate/Content/Employers[1]/Employer[1]/Addresses[1]/Address");
Note the single quotes around the number 1 are removed.
The predicate for selecting the first item is [1]. Using the predicate ['1'] is ignored by SelectNodes so you are getting all nodes and not just the first.

XML to Dataset : How does one access a complex type within a node?

The XML file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfCompany xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Company>
<CompanyID>Company A</CompanyID>
<CompanyName>Company A</CompanyName>
<CompanyRecID>1491</CompanyRecID>
<Contacts>
<Contact>
<City>Birmingham</City>
<Country>United States</Country>
<FirstName>Steven</FirstName>
</Contact>
<Contact>
<City>Birmingham</City>
<Country>United States</Country>
<FirstName>Natalie</FirstName>
</Contact>
</Contacts>
</Company>
<Company>
<CompanyID>Company B</CompanyID>
<CompanyName>Company B</CompanyName>
<CompanyRecID>1492</CompanyRecID>
<Contacts>
<Contact>
<City>Birmingham</City>
<Country/>
<FirstName>Greg</FirstName>
</Contact>
<Contact>
<City>Birmingham</City>
<Country/>
<FirstName>Robert</FirstName>
</Contact>
</Contacts>
</Company>
</ArrayOfCompany>
With two lines of code, I can take that XML file and pump it into a dataset:
var dsCustomer = new System.Data.DataSet("CustomerDataSet");
dsCustomer.ReadXml(System.IO.Path.Combine(currentAssemblyDirectoryName, "company.xml"));
.NET understands the schema. This is what it looks like when I use ds.WriteXmlSchema command:
Given a company name, how can use a LINQ query to return the contacts?
You can parse xml with LINQ to XML:
var name = "Company B";
var xdoc = XDocument.Load("company.xml");
var contacts = from company in xdoc.Descendants("Company")
where (string)company.Element("CompanyName") == name
from contact in company.Element("Contacts").Elements()
select new {
City = (string)contact.Element("City"),
Country = (string)contact.Element("Country"),
FirstName = (string)contact.Element("FirstName")
};
This will return collection of anonymous objects representing contacts of selected company. Each object will have properties for city, country and first name.

Finding and Filtering XML Data

I have an XML document here:
<?xml version="1.0" encoding="utf-8" ?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
<CD>
<TITLE>Test Title 1</TITLE>
<ARTIST>Test Name 1</ARTIST>
<COUNTRY>Test Country 1</COUNTRY>
<COMPANY>Test Company 1</COMPANY>
<PRICE>100.00</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Test Title 3</TITLE>
<ARTIST>Test Name 3</ARTIST>
<COUNTRY>Test Country 3</COUNTRY>
<COMPANY>Test Company 3</COMPANY>
<PRICE>1.99</PRICE>
<YEAR>1984</YEAR>
</CD>
<CD>
<TITLE>Test Title 2</TITLE>
<ARTIST>Test Name 2</ARTIST>
<COUNTRY>Test Country 2</COUNTRY>
<COMPANY>Test Company 2</COMPANY>
<PRICE>19.99</PRICE>
<YEAR>1985</YEAR>
</CD>
</CATALOG>
What I am trying to do is find all the CDs that have a year of 1985. I'm very new to LINQ to XML and I have no idea what I'm doing. Because most internet resources are very specific example, I'm having trouble applying it to my example.
Here's the C# that I've coded so far:
namespace ReadingXML
{
class Program
{
static void Main(string[] args)
{
XElement xelement = XElement.Load("..\\..\\music.xml");
IEnumerable<XElement> music = xelement.Elements();
/*// Read the entire XML
foreach (var item in catalogues)
{
Console.WriteLine(item);
}
Console.ReadLine();*/
var query = from item in music.Descendants("CD")
select new { year = item.Element("YEAR").Equals(1985) };
foreach (var item in query)
Console.WriteLine(item.ToString());
Console.ReadLine();
}
}
}
Can someone please tell me how I can achieve what I'm trying to do and/or why my code isn't functioning?
XDocument X = XDocument.Load(#"XMLFileLocation");
var CDsIn1985 = X.Element("CATALOG").Elements("CD").Where(E => E.Element("YEAR").Value == "1985");
foreach (var item in CDsIn1985)
{
Console.WriteLine(String.Format("Title : {0}, Artist : {1}", item.Element("TITLE").Value, item.Element("ARTIST").Value));
}
Another away is to use String Interpolation
foreach (var item in CDsIn1985)
{
Console.WriteLine(String.Format($"Title : {item.Element("TITLE").Value}, Artist : { item.Element("ARTIST").Value}"));
}

Categories