Read from XML > Add to Listview - c#

I have some problems getting the data that i read from XML split into seperate columns. Any help this new C# coder would get would be appreciated.
XDocument xmlDoc = XDocument.Load("emails.xml");
var t = from c in xmlDoc.Descendants("dt")
select (string)c.Element("name") + (string)c.Element("email");
foreach (string item in t)
{
listView.Items.Add(item);
}

XDocument xmlDoc = XDocument.Load("emails.xml");
var t = from c in xmlDoc.Descendants("dt")
select new
{
Name = e.Element("name").Value,
EMail = e.Element("email").Value,
};
foreach (var item in t)
{
var lvi = listView.Items.Add(item.Name);
lvi.SubItems.Add(item.EMail);
}

Related

Read XML File Using Linq is not reading element

I am not able to get the value from this xml response, I will appreciate any help.
<Response>
<Result>
<Item1>GREEN</Item1>
<Item2>05/19/2017 22:08:14</Item2>
</Result>
<Other>
<Id>xxxxxxxxxxxxc</Id>
</Other>
</Response>
What I tried so far but the results is empty
string responseXml = response.ToXML();
XElement doc = XElement.Load(new StringReader(responseXml));
var results = from p in
doc.Descendants("Result")
select new
{
item = p.Element("Item1").Value,
};
foreach (var elm in results)
{
Console.WriteLine(elm.item);
}
Use Parse instead of load. You may also be getting error due to extra characters in the string. In the string you postged there are single quotes. Not sure if the single quote is in the actual string you are using.
string responseXml = "<Response>" +
"<Result>" +
"<Item1>GREEN</Item1>" +
"<Item2>05/19/2017 22:08:14</Item2>" +
"</Result>" +
"<Other>" +
"<Id>xxxxxxxxxxxxc</Id>" +
"</Other>" +
"</Response>";
XElement doc = XElement.Parse(responseXml);
var results = from p in
doc.Descendants("Result")
select new
{
item = p.Element("Item1").Value,
};
foreach (var elm in results)
{
Console.WriteLine(elm.item);
}

Returning elements of an XML file as a string

I'm attempting to display XML content tags from a word document that the user uploads, but I'm not sure how to explicitly pull out the data, and then display it as a string.
I think the below SHOULD find the correct descendent (or element, either should work right?) and then allow me to create a string out of it and display it, but I can't get the file to recognise xdoc). What I'm trying to return is located as "w.tag" in the bottom section of code.
Any ideas?
WordprocessingDocument _TempDoc = WordprocessingDocument.Open(Server.MapPath("~/") + filename, true);
//query to find particular descendants
var lv1s = from lv1 in xdoc.Descendants("table")
select new
{
Header = lv1.Attribute("name").Value,
Children = lv1.Descendants("tag")
};
//Loop through results
StringBuilder result = new StringBuilder();
foreach (var lv1 in lv1s)
{
result.AppendLine(lv1.Header);
foreach (var lv2 in lv1.Children)
result.AppendLine(" " + lv2.Attribute("name").Value);
}
//the label should contain the content controls of the document, using the class, XMLfromDocument
labelContentControls.Text = fileUpload_Displayx(XMLfromDocument.GetContentControls(_TempDoc));
public static XDocument GetXDocument(this OpenXmlPart part)
{
XDocument xdoc = part.Annotation<XDocument>();
if (xdoc != null)
return xdoc;
using (Stream str = part.GetStream())
using (StreamReader streamReader = new StreamReader(str))
using (XmlReader xr = XmlReader.Create(streamReader))
xdoc = XDocument.Load(xr);
part.AddAnnotation(xdoc);
return xdoc;
}
//following method gets the structure of the content controls / XML in the document
public static XElement GetContentControls( WordprocessingDocument document)
{
XElement contentControls = new XElement("ContentControls",
document
.MainDocumentPart
.GetXDocument()
.Root
.Element(W.body)
.Elements(W.sdt)
.Select(tableContentControl =>
new XElement("Table",
new XAttribute("Name", (string)tableContentControl
.Element(W.sdtPr).Element(W.tag).Attribute(
W.val)),
tableContentControl
.Descendants(W.sdt)
.Select(fieldContentControl =>
new XElement("Field",
new XAttribute("Name",
(string)fieldContentControl
.Element(W.sdtPr)
.Element(W.tag)
.Attribute(W.val)
)
)
)
)
)
);
// you cannot access the inner XML of the elemnt directly, you must concatenate to the child elements.
// string contentTitle = string.Concat(W.sdtPr);
//return W.tag;
return contentControls;

LINQ to read XML file and print results

I got the following XML file (Data.xml):
<root>
<sitecollection name="1A">
<site name="1B">
<maingroup name="1C">
<group name="1D"> </group>
</maingroup>
</site>
</sitecollection>
<sitecollection name="2A">
<site name="2B">
<maingroup name="2C">
<group name="2D"> </group>
</maingroup>
</site>
</sitecollection>
</root>
And I need to print all the all the child elements in this format:
1A
1B
1C
1D
2A
2B
2C
2D
I have the following code so far which needs some adjustment. I could also change it completely if there's an easier method. Thanks for your help
class xmlreader
{
public static void Main()
{
// Xdocument to read XML file
XDocument xdoc = XDocument.Load("Data.xml");
var result = new System.Text.StringBuilder();
var lv1s = from lv1 in xdoc.Descendants("sitecollection")
select new
{
sitecollection = lv1.Attribute("name").Value,
maingroup = lv1.Descendants("group")
};
var lv2s = from lv2 in xdoc.Descendants("site")
select new
{
site = lv2.Attribute("name").Value,
sitetittle = lv2.Descendants()
};
var lv3s = from lv3 in xdoc.Descendants("maingroup")
select new
{
maingroup = lv3.Attribute("name").Value,
};
var lv4s = from lv4 in xdoc.Descendants("group")
select new
{
grouppage = lv4.Attribute("name").Value,
};
// Loop to print results
foreach (var lv1 in lv1s)
{
result.AppendLine(lv1.sitecollection);
foreach (var lv2 in lv2s)
{
result.AppendLine(" " + lv2.Attribute("name").Value);
foreach (var lv3 in lv3s)
{
result.AppendLine(" " + lv3.Attribute("name").Value);
foreach (var lv4 in lv4s)
{
result.AppendLine(" " + lv4.Attribute("name").Value);
}
}
}
}
}
}
With such a uniform hierarchy, recursion can do the job with a lot less code:
void PrintNames(StringBuilder result, string indent, XElement el)
{
var attr = el.Attributes("name");
if (attr != null)
{
result.Append(indent);
result.Append(attr.Value);
result.Append(System.Environment.NewLine);
}
indent = indent + " ";
foreach(var child in el.Elements())
{
PrintNames(result, indent, child);
}
}
...
var sb = new StringBuilder();
PrintNames(sb, String.Empty, xdoc.Root);
How about the following, find all elements with a name attribute, then add spaces based on their depth.
var result = new System.Text.StringBuilder();
var namedElements = doc.Descendants().Where(el => el.Attributes("name")!=null);
foreach(var el in namedElements)
{
int depth = el.Ancestors().Count();
for (int i=0;i<depth;i++)
result.Append(" ");
result.Append(el.Attributes("name").Value);
result.Append(System.Environment.NewLine);
}
NOTE: The above is from memory, so please check the syntax!

Write xml file output values to a dataset

This code is programmed to display some data values from alot of xml files is their anyway to alter it so that it write the values to a dataset/table?
static void Main(string[] args)
{
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
XDocument doc = XDocument.Load(fileName);
var query = from x in doc.Descendants("XAxisCalib")
select new
{
//Max1 = x.Attribute("Max").Value,
//Min2 = x.Attribute("Min").Value
MaxChild = x.Descendants("Max"),
MinChild = x.Descendants("Min")
};
foreach (var x in query)
{
foreach (var nextLevel in x.MaxChild)
{
Console.WriteLine("XMax: " + nextLevel.Value);
}
foreach (var nextLevel in x.MinChild)
{
Console.WriteLine("XMin: " + nextLevel.Value);
}
//Console.WriteLine("XAxisCalib");
}
var query2 = from y in doc.Descendants("YAxisCalib")
select new
{
//Max3 = x.Attribute("Max").Value,
//Min4 = x.Attribute("Min").Value
MaxChild = y.Descendants("Max"),
MinChild = y.Descendants("Min")
};
foreach (var y in query2)
{
foreach (var nextLevel in y.MaxChild)
{
Console.WriteLine("YMax: " + nextLevel.Value);
}
foreach (var nextLevel in y.MinChild)
{
Console.WriteLine("YMin: " + nextLevel.Value);
}
//Console.WriteLine("YAxisCalib");
var query3 = from z in doc.Descendants("ZAxisCalib")
select new
{
//Max5 = x.Attribute("Max").Value,
//Min6 = x.Attribute("Min").Value
MaxChild = z.Descendants("Max"),
MinChild = z.Descendants("Min")
};
foreach (var z in query3)
{
foreach (var nextLevel in z.MaxChild)
{
Console.WriteLine("ZMax: " + nextLevel.Value);
}
foreach (var nextLevel in z.MinChild)
{
Console.WriteLine("ZMin: " + nextLevel.Value);
}
//Console.WriteLine("ZAxisCalib");
}
}
}
}
}
}
I don't know if I'm missing something, but what about the DataSet.ReadXml method?:
DataSet ds = new DataSet();
ds.ReadXml("myxmlfile.xml");
The ReadXml() method has an overload for passing in XmlReadMode, which provides various options handling the schema.
In your case, assuming that you want to read each XML file into it's own DataSet, you can do something like this:
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
DataSet ds = new DataSet();
ds.ReadXml(fileName, XmlReadMode.InferSchema);
}
To read the XML files into the same DataSet, you can do something like this:
DataSet masterSet = new DataSet();
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
//initialize a new dataset and read the xml into it
DataSet tempSet = new DataSet();
tempSet.ReadXml(fileName, XmlReadMode.InferSchema);
//merge the tables from the temporary datset into the master dataset
foreach (DataTable table in tempSet.Tables)
masterSet.Merge(table);
}
Here's another way of doing the same thing, using the enumerable LINQ methods:
DataSet masterSet = new DataSet();
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
//initialize a new dataset and read the xml into it
DataSet tempSet = new DataSet();
tempSet.ReadXml(fileName, XmlReadMode.InferSchema);
//merge the tables from the temporary datset into the master dataset
tempSet.Tables.Cast<DataTable>().ToList().ForEach(table => masterSet.Merge(table));
}
One of the XmlReadMode enumerations should definitely suit your needs.
Auto
DiffGram
Fragment
IgnoreSchema
InferSchema
InferTypedSchema
ReadSchema
Here is a link on MSDN that explains what the different XmlReadMode enumerations do:
http://msdn.microsoft.com/en-us/library/system.data.xmlreadmode.aspx

LINQ to read XML

I am using this XML file:
<root>
<level1 name="A">
<level2 name="A1" />
<level2 name="A2" />
</level1>
<level1 name="B">
<level2 name="B1" />
<level2 name="B2" />
</level1>
<level1 name="C" />
</root>
Could someone give me a C# code using LINQ, the simplest way to print this result:
(Note the extra space if it is a level2 node)
A
A1
A2
B
B1
B2
C
Currently I have written this code:
XDocument xdoc = XDocument.Load("data.xml"));
var lv1s = from lv1 in xdoc.Descendants("level1")
select lv1.Attribute("name").Value;
foreach (var lv1 in lv1s)
{
result.AppendLine(lv1);
var lv2s = from lv2 in xdoc...???
}
Try this.
using System.Xml.Linq;
void Main()
{
StringBuilder result = new StringBuilder();
//Load xml
XDocument xdoc = XDocument.Load("data.xml");
//Run query
var lv1s = from lv1 in xdoc.Descendants("level1")
select new {
Header = lv1.Attribute("name").Value,
Children = lv1.Descendants("level2")
};
//Loop through results
foreach (var lv1 in lv1s){
result.AppendLine(lv1.Header);
foreach(var lv2 in lv1.Children)
result.AppendLine(" " + lv2.Attribute("name").Value);
}
Console.WriteLine(result);
}
Or, if you want a more general approach - i.e. for nesting up to "levelN":
void Main()
{
XElement rootElement = XElement.Load(#"c:\events\test.xml");
Console.WriteLine(GetOutline(0, rootElement));
}
private string GetOutline(int indentLevel, XElement element)
{
StringBuilder result = new StringBuilder();
if (element.Attribute("name") != null)
{
result = result.AppendLine(new string(' ', indentLevel * 2) + element.Attribute("name").Value);
}
foreach (XElement childElement in element.Elements())
{
result.Append(GetOutline(indentLevel + 1, childElement));
}
return result.ToString();
}
A couple of plain old foreach loops provides a clean solution:
foreach (XElement level1Element in XElement.Load("data.xml").Elements("level1"))
{
result.AppendLine(level1Element.Attribute("name").Value);
foreach (XElement level2Element in level1Element.Elements("level2"))
{
result.AppendLine(" " + level2Element.Attribute("name").Value);
}
}
Here are a couple of complete working examples that build on the #bendewey & #dommer examples. I needed to tweak each one a bit to get it to work, but in case another LINQ noob is looking for working examples, here you go:
//bendewey's example using data.xml from OP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
class loadXMLToLINQ1
{
static void Main( )
{
//Load xml
XDocument xdoc = XDocument.Load(#"c:\\data.xml"); //you'll have to edit your path
//Run query
var lv1s = from lv1 in xdoc.Descendants("level1")
select new
{
Header = lv1.Attribute("name").Value,
Children = lv1.Descendants("level2")
};
StringBuilder result = new StringBuilder(); //had to add this to make the result work
//Loop through results
foreach (var lv1 in lv1s)
{
result.AppendLine(" " + lv1.Header);
foreach(var lv2 in lv1.Children)
result.AppendLine(" " + lv2.Attribute("name").Value);
}
Console.WriteLine(result.ToString()); //added this so you could see the output on the console
}
}
And next:
//Dommer's example, using data.xml from OP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
class loadXMLToLINQ
{
static void Main( )
{
XElement rootElement = XElement.Load(#"c:\\data.xml"); //you'll have to edit your path
Console.WriteLine(GetOutline(0, rootElement));
}
static private string GetOutline(int indentLevel, XElement element)
{
StringBuilder result = new StringBuilder();
if (element.Attribute("name") != null)
{
result = result.AppendLine(new string(' ', indentLevel * 2) + element.Attribute("name").Value);
}
foreach (XElement childElement in element.Elements())
{
result.Append(GetOutline(indentLevel + 1, childElement));
}
return result.ToString();
}
}
These both compile & work in VS2010 using csc.exe version 4.0.30319.1 and give the exact same output. Hopefully these help someone else who's looking for working examples of code.
EDIT: added #eglasius' example as well since it became useful to me:
//#eglasius example, still using data.xml from OP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
class loadXMLToLINQ2
{
static void Main( )
{
StringBuilder result = new StringBuilder(); //needed for result below
XDocument xdoc = XDocument.Load(#"c:\\deg\\data.xml"); //you'll have to edit your path
var lv1s = xdoc.Root.Descendants("level1");
var lvs = lv1s.SelectMany(l=>
new string[]{ l.Attribute("name").Value }
.Union(
l.Descendants("level2")
.Select(l2=>" " + l2.Attribute("name").Value)
)
);
foreach (var lv in lvs)
{
result.AppendLine(lv);
}
Console.WriteLine(result);//added this so you could see the result
}
}
XDocument xdoc = XDocument.Load("data.xml");
var lv1s = xdoc.Root.Descendants("level1");
var lvs = lv1s.SelectMany(l=>
new string[]{ l.Attribute("name").Value }
.Union(
l.Descendants("level2")
.Select(l2=>" " + l2.Attribute("name").Value)
)
);
foreach (var lv in lvs)
{
result.AppendLine(lv);
}
Ps. You have to use .Root on any of these versions.
Asynchronous loading of the XML file can improve performance, especially if the file is large or if it takes a long time to load. In this example, we use the XDocument.LoadAsync method to load and parse the XML file asynchronously, which can help to prevent the application from becoming unresponsive while the file is being loaded.
Demo: https://dotnetfiddle.net/PGFE7c (using XML string parsing)
Implementation:
XDocument doc;
// Open the XML file using File.OpenRead and pass the stream to
// XDocument.LoadAsync to load and parse the XML asynchronously
using (var stream = File.OpenRead("data.xml"))
{
doc = await XDocument.LoadAsync(stream, LoadOptions.None, CancellationToken.None);
}
// Select the level1 elements from the document and create an anonymous object for each element
// with a Name property containing the value of the "name" attribute and a Children property
// containing a collection of the names of the level2 elements
var results = doc.Descendants("level1")
.Select(level1 => new
{
Name = level1.Attribute("name").Value,
Children = level1.Descendants("level2")
.Select(level2 => level2.Attribute("name").Value)
});
foreach (var result in results)
{
Console.WriteLine(result.Name);
foreach (var child in result.Children)
Console.WriteLine(" " + child);
}
Result:
A
  A1
  A2
B
  B1
  B2
C

Categories