Help with Linq to XML - c#

Iv got two DB tables. One containing types(Id, Name) and the other holds datapoints (RefId, Date, Value) that are referenced by the types. I need to create a XML file with the following strukture:
<?xml version='1.0' encoding='utf-8' ?>
<root>
<type>
<name></name>
<data>
<date></date>
<temp></temp>
</data>
<data>
<date></date>
<temp></temp>
</data>
<data>
<date></date>
<temp></temp>
</data>
</type>
</root>
And iv got the following code to do this
public XmlDocument HelloWorld()
{
string tmp = "";
try
{
sqlConn.ConnectionString = ConfigurationManager.ConnectionStrings["NorlanderDBConnection"].ConnectionString;
DataContext db = new DataContext(sqlConn.ConnectionString);
Table<DataType> dataTypes = db.GetTable<DataType>();
Table<DataPoints> dataPoints = db.GetTable<DataPoints>();
var dataT =
from t in dataTypes
select t;
var dataP =
from t in dataTypes
join p in dataPoints on t.Id equals p.RefId
select new
{
Id = t.Id,
Name = t.Name,
Date = p.PointDate,
Value = p.PointValue
};
string xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><root></root>";
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlString);
int count = 0;
foreach (var dt in dataT)
{
XmlElement type = xmldoc.CreateElement("type");
XmlElement name = xmldoc.CreateElement("name");
XmlNode nameText = xmldoc.CreateTextNode(dt.Name);
name.AppendChild(nameText);
type.AppendChild(name);
foreach(var dp in dataP.Where(dt.Id = dp.RefId))
{
XmlElement data = xmldoc.CreateElement("data");
XmlElement date = xmldoc.CreateElement("date");
XmlElement temp = xmldoc.CreateElement("temp");
XmlNode dateValue = xmldoc.CreateTextNode(dp.Date.ToString());
date.AppendChild(dateValue);
XmlNode tempValue = xmldoc.CreateTextNode(dp.Value.ToString());
temp.AppendChild(tempValue);
data.AppendChild(date);
data.AppendChild(temp);
type.AppendChild(data);
}
xmldoc.DocumentElement.AppendChild(type);
}
return xmldoc;
}
catch(Exception e)
{
tmp = e.ToString();
}
return null;
}
[Table(Name="DataTypes")]
public class DataType
{
[Column(IsPrimaryKey = true)]
public long Id;
[Column]
public string Name;
}
[Table(Name="DataPoints")]
public class DataPoints
{
[Column]
public long RefId;
[Column]
public DateTime PointDate;
[Column]
public double PointValue;
}
This is not a working code. Im having problems with LINQ and the inner joins. Could someone please help me to get the correct strukture. I hope its kinda clear what im trying to achive.
Best Regards
Marthin

var result =
new XDocument(new XElement("root",
from dt in dataTypes
join dp in dataPoints on dt.Id equals dp.RefId
select new XElement("type",
new XElement("name", dt.Name),
new XElement("data",
new XElement("date", dp.PointDate),
new XElement("temp", dp.PointValue)))));
var result =
new XDocument(new XElement("root",
from dt in dataTypes
select new XElement("type",
new XElement("name", dt.Name),
from dp in dataPoints
where dp.RefId == dt.Id
select new XElement("data",
new XElement("date", dp.PointDate),
new XElement("temp", dp.PointValue)))));

Related

merging 2 xml records with the same schema

How do we merge 2 XML records that have the same schema?
For example let's say we have two records such as :
<msg>
<name>alex</name>
<payload></payload>
</msg>
and the second:
<msg>
<name></name>
<payload>blabla</payload>
</msg>
The expected result:
<msg>
<name>alex</name>
<payload>blabla</payload>
</msg>
We simply took the non-empty value.
How do we merge two xml records with the same schema?
A simple implementation would just go though the elements pairing corresponding items by name and create a new element choosing the text of the non-blank element.
XElement ShallowMerge(XElement a, XElement b) =>
new XElement(a.Name,
from ae in a.Elements()
join be in b.Elements() on ae.Name equals be.Name
select new XElement(ae.Name,
!String.IsNullOrWhiteSpace((string)ae)
? (string)ae
: (string)be
)
);
//two lists for temp storing .xml data
List<Person> list1= new List<Person>();
List<Person> list2= new List<Person>();
List<Person> list3= new List<Person>();//for mixing
string path=#"c:\.....";
//properties of .xml notes like 'name' and 'payload'
public class Person
{
public string name{ get; set; }//1
public string payload{ get; set; }//2
}
//load both .xml files saperatly
void load_list1()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\list1.xml");
foreach (XmlNode xnode in xdoc.SelectNodes("Items/Item"))
{
Person p = new Person();
p.name= xnode.SelectSingleNode("a").InnerText;
p.payload= xnode.SelectSingleNode("b").InnerText;
list1.Items.Add(p);
}
}
void load_list2()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\list2.xml");
foreach (XmlNode xnode in xdoc.SelectNodes("Items/Item"))
{
Person p = new Person();
p.name= xnode.SelectSingleNode("a").InnerText;
p.payload= xnode.SelectSingleNode("b").InnerText;
list2.Items.Add(p);
}
}
//start mixing both lists
void mixdata()
{
for(int i=0;i<list1.Items.Count;i++)
{
Person p= new Person();
p.name=list1.Items[i].name;
p.payload=list2.Items[i].payload;
list3.Items.Add(p);
}
}
//saving final mixed list to .xml
void save()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\Mixed_data.xml");
XmlNode xnode = xdoc.SelectSingleNode("Items");
xnode.RemoveAll();
foreach (Person i in list3)
{
XmlNode xtop = xdoc.CreateElement("Item");
XmlNode x1 = xdoc.CreateElement("a");
XmlNode x2 = xdoc.CreateElement("b");
x1.InnerText = i.name;
x2.InnerText = i.payload;
xtop.AppendChild(x1);
xtop.AppendChild(x2);
xdoc.DocumentElement.AppendChild(xtop);
}
xdoc.Save(path + #"\data.xml");
}
//let me know any errors

how to create Nested XML in C#

I want to create nested xml so that the result would look like:
<?xml version=\"1.0\" encoding=\"UTF-8\"?><TASKLOADLOG>
<PERSON>
<EMAIL>data</EMAIL><LOADED>OK</LOADED><LOADERROR>ABC</LOADERROR>
</PERSON>
<PERSON>
<EMAIL>data</EMAIL><LOADED>OK</LOADED><LOADERROR>ABC</LOADERROR>
</PERSON>
<PERSON>
<EMAIL>data</EMAIL><LOADED>OK</LOADED><LOADERROR>ABC</LOADERROR>
</PERSON>
</TASKLOADLOG>"
I wrote following code and It crashed in a loop
XmlDocument XmlResponse = new XmlDocument();
XmlDeclaration xDeclare = XmlResponse.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement documentRoot = XmlResponse.DocumentElement;
XmlResponse.InsertBefore(xDeclare, documentRoot);
XmlElement el = (XmlElement)XmlResponse.AppendChild(XmlResponse.CreateElement("TASKLOADLOG"));
List<XmlElement> ls = new List<XmlElement>();
for (int i = 0; i < 3; i++)
{
ls[i].AppendChild(XmlResponse.CreateElement("EMAIL")).InnerText = "data";
ls[i].AppendChild(XmlResponse.CreateElement("LOADED")).InnerText = "OK";
ls[i].AppendChild(XmlResponse.CreateElement("LOADERROR")).InnerText = "ABC";
}
MessageBox.Show(XmlResponse.OuterXml);
I don't now how to define PERSON what I need to write to fix my code?
The problem is simple, you are not creating the PERSON node. Email, Loaded and LoadError should be child nodes to Person node.
Edit:
just to let you know, you could even use class Serialization for the XML you are trying to generate.
For Example:
[Serializable]
public class Person
{
[XmlAttribute]
public string Email { get; set; }
public string Loaded { get; set; }
public string LoadError{ get; set; }
}
Person p = new Person
{
Email = "abc",
Loaded = "abc";
LoadError = "abc"
};
new XmlSerializer(typeof(Person)).Serialize(Console.Out, Person);
thanks about the quick answer
I wrote following code and It got error in XmlResponse.Root.AppendChild :
XmlDocument XmlResponse = new XmlDocument();
XmlDeclaration xDeclare = XmlResponse.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement documentRoot = XmlResponse.DocumentElement;
XmlResponse.InsertBefore(xDeclare, documentRoot);
XmlElement el = (XmlElement)XmlResponse.AppendChild(XmlResponse.CreateElement("TASKLOADLOG"));
//List<XmlElement> ls = new List<XmlElement>();
for (int i = 0; i < 3; i++)
{
XmlResponse.Root.AppendChild(new XElement("PERSON",
new XElement("EMAIL", "data"),
new XElement("LOADED", "OK"),
new XElement("LOADERROR", "ABC")
)));
}
MessageBox.Show(XmlResponse.OuterXml);
Your code is crashing because you are referencing the first index of your list ls when the list is empty.
Create your document like this:
var doc = XDocument(new XElement("TASKLOADLOG"));
for (int i = 0; i < 3; i++)
doc.Root.AppendChild(new XElement("PERSON",
new XElement("EMAIL", "data"),
new XElement("LOADED", "OK"),
new XElement("LOADERROR", "ABC")
)));
}

Xml Tags get wrong encoded

I'm trying to write a list of objects to valid xml. My code looks basicly like this:
public class Person
{
public string First { get; set; }
public string Last { get; set; }
}
List<Person> people = new List<Person>();
XElement elements = new XElement("People",
from p in people
select new XElement("Person",
new XElement("First", p.First),
new XElement("Last", p.Last)));
string output = elements.ToString();
Unfortunately output when written to a file looks like this:
<People>
<Person>
<First>Tom</First>
<Last>Hanks</Last>
</Person>
</People>
XDeclaration declaration = new XDeclaration("1.0", "utf-8", "yes");
XProcessingInstruction procInstruction = new XProcessingInstruction("xml-stylesheet", "type='text/xsl'");
XElement root = new XElement("Store");
XDocument settingsFile = new XDocument(declaration, procInstruction, root);
foreach (string key in persistentSettings.Keys)
{
string value = persistentSettings[key];
if (!string.IsNullOrEmpty(value))
{
XElement setting = new XElement("Setting", new XAttribute("Name", key));
setting.Value = value;
root.Add(setting);
}
}
settingsFile.Save(SettingsFileName);
What is that I'm doing wrong here?
I had to use the parse function in the Constructor of xElement
XElement setting
= new XElement("Setting", new XAttribute("Name", key), XElement.Parse(value));
instead of
XElement setting = new XElement("Setting", new XAttribute("Name", key));
setting.Value = value;

Using Linq to get XML data from database

I'm struggling to get the values of a single xml node using Linq.
Here is my XML.
<?xml version="1.0" encoding="utf-8"?>
<record>
<AddressLine1>abcd street</AddressLine1>
<AddressLine2>xyz AVE</AddressLine2>
<AddressCity>Illinois</AddressCity>
<AddressState>Chicago</AddressState>
<AddressZip>23434</AddressZip>
</record>
And here is my c# code
XElement xmlDoc = XElement.Parse(varQ.Content);
//When I debug I find that xmlDoc contains the XML. So that is alright.
var q = (from lpi in xmlDoc.Descendants("record")
select new { AddressLine1 = lpi.Element("AddressLine1").Value,
AddressLine2 = lpi.Element("AddressLine2").Value,
AddressCity = lpi.Element("AddressCity").Value,
AddressCountry = lpi.Element("AddressCountry").Value,
AddressState = lpi.Element("AddressState").Value,
AddressZip = lpi.Element("AddressZip").Value,
}).FirstOrDefault();
var q shows null. Can u please help me find out what is wrong here?
Replace Descendants on DescendantsAndSelf:
string xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<record>
<AddressLine1>abcd street</AddressLine1>
<AddressLine2>xyz AVE</AddressLine2>
<AddressCity>Illinois</AddressCity>
<AddressState>Chicago</AddressState>
<AddressZip>23434</AddressZip>
</record>";
XElement xmlDoc = XElement.Parse(xml);
var q = (from lpi in xmlDoc.DescendantsAndSelf("record")
select new
{
AddressLine1 = (string)lpi.Element("AddressLine1"),
AddressLine2 = (string)lpi.Element("AddressLine2"),
AddressCity = (string)lpi.Element("AddressCity"),
AddressCountry = (string)lpi.Element("AddressCountry"),
AddressState = (string)lpi.Element("AddressState"),
AddressZip = (string)lpi.Element("AddressZip"),
}).FirstOrDefault();
Console.WriteLine(q);
Print:
{ AddressLine1 = abcd street, AddressLine2 = xyz AVE, AddressCity = Illinois, AddressCountry = , AddressState = Chicago, AddressZip = 23434 }
Link: https://dotnetfiddle.net/fXQivX

Convert xml string to a list of my Object

<root>
<row>
<linksclicked>http://www.examiner.com/</linksclicked>
<clickedcount>34</clickedcount>
</row>
<row>
<linksclicked>http://www.sample123.com</linksclicked>
<clickedcount>16</clickedcount>
</row>
<row>
<linksclicked>http://www.testing123.com</linksclicked>
<clickedcount>14</clickedcount>
</row>
</root>
I have xml like above in a string and i have class like below
public class Row
{
public string linksclicked { get; set; }
public int clickedcount { get; set; }
}
How can i convert the xml string to a list of Row Object
You can use LINQ to XML:
var doc = XDocument.Parse(xmlString);
var items = (from r in doc.Root.Elements("row")
select new Row()
{
linksclicked = (string) r.Element("linksclicked"),
clickedcount = (int) r.Element("clickedcount")
}).ToList();
This approach can be a safer one to avoid exceptions in case if xml result becomes empty from the server call.
string xmlString = "<School><Student><Id>2</Id><Name>dummy</Name><Section>12</Section></Student><Student><Id>3</Id><Name>dummy</Name><Section>11</Section></Student></School>";
XDocument doc = new XDocument();
//Check for empty string.
if (!string.IsNullOrEmpty(xmlString))
{
doc = XDocument.Parse(xmlString);
}
List<Student> students = new List<Student>();
//Check if xml has any elements
if(!string.IsNullOrEmpty(xmlString) && doc.Root.Elements().Any())
{
students = doc.Descendants("Student").Select(d =>
new Student
{
id=d.Element("Id").Value,
name=d.Element("Name").Value,
section=d.Element("Section").Value
}).ToList();
}
public class Student{public string id; public string name; public string section;}
Check the demo fiddle Demo
You can use an XMLSerializer to deserialize the a property of type List and assign the tag name to the property as root.
However, you'll need the XML tag at the starting of the file.
U can write your own XML parser using XElement.
You can the list of row nodes, parse each of them n load them in a list.
XElement rootNode = XElement.Load(filepath);
List<XElement> nodes = rootNode.Descendants().Where(t=> t.Name.ToString().Equals("row"));
for each tag you can create an object Row and fill its properties based on child tags.
Hope it helps
You can try this piece of code
string xml = "<Ids><id>1</id><id>2</id></Ids>";
ArrayList list = new ArrayList();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList idNodes = doc.SelectNodes("Ids/id");
foreach (XmlNode node in idNodes)
list.Add(node.InnerText);
Try this one:
var xml = #"
<root>
<row>
<linksclicked>http://www.examiner.com/</linksclicked>
<clickedcount>34</clickedcount>
</row>
<row>
<linksclicked>http://www.sample123.com</linksclicked>
<clickedcount>16</clickedcount>
</row>
<row>
<linksclicked>http://www.testing123.com</linksclicked>
<clickedcount>14</clickedcount>
</row>
</root>";
var xElems = XDocument.Parse(xmlString);
var xRow = doc.Root.Elements("row");
List<Row> rowList = (from rowTags in xRow
let clickCount = 0
let isClickCountOk = Int32.TryParse((rowTags.Element("clickedcount").Value, clickCount);
where !string.IsNullOrEmpty(rowTags.Element("linksclicked").Value) &&
!string.IsNullOrEmpty(rowTags.Element("clickedcount").Value)
select new Row()
{
linksclicked = rowTags.Element("linksclicked").Value,
clickedcount = clickCount
}).ToList();

Categories

Resources