Show xml file info into Listview C# - c#

I'm working on a C# Desktop App and in a module I display the info of a xml file into a listview, I coded my solution with Linq to XML like this
string path = "prueba.xml";
listView1.Items.Clear();
listView1.Columns.Add(path, 400);
XElement doc = XElement.Load(path);
var result = from persona in doc.Elements("persona")
select new{
nombre = Convert.ToString(persona.Element("nombre").Value).Trim(),
ocupacion = Convert.ToString(persona.Element("ocupacion").Value).Trim()
};
foreach (var persona in result)
{
/*ListViewItem item = new ListViewItem(persona.nombre);
item.SubItems.Add(persona.ocupacion);*/
ListViewItem nombre = new ListViewItem("<nombre> " + persona.nombre + " </nombre>");
ListViewItem ocupacion = new ListViewItem("<ocupacion> " + persona.ocupacion + " </ocupacion>");
listView1.Items.Add("<persona>");
listView1.Items.Add(nombre);
listView1.Items.Add(ocupacion);
listView1.Items.Add("</persona>");
listView1.Items.Add("");
}
}
}
and it works very fine, as you can see there are items in the listview that represents the nodes of the xml file, but those items are specific for this xml file
<?xml version="1.0" encoding="utf-8" ?>
<personas>
<persona>
<nombre>Pablo el primero</nombre>
<ocupacion>Programador Cliente-Servidor</ocupacion>
</persona>
<persona>
<nombre>Pablo el segundo</nombre>
<ocupacion>Programador Web</ocupacion>
</persona>
</personas>
as you can see in the C# code, it fits for the xml file above but if I retrieve another xml file with different nodes name like for example
<juego>
<juegos>
<name id="ac"> God of War III </name>
...
</juegos>
</juego>
my code wont show me the nodes <juegos>...</juegos> because it will still display the <person>...</person> nodes because it was created to display only the node <person>...</person> so my question: is there a way to show the information of a xml file into a listview using Linq to XML and at the same time display the info as it is coded in the xml file?
I want to know if I can display this format in teh listview:
<?xml version="1.0" encoding="utf-8" ?>
<personas>
<persona>
<nombre>Pablo el primero</nombre>
<ocupacion>Programador Cliente-Servidor</ocupacion>
</persona>
<persona>
<nombre>Pablo el segundo</nombre>
<ocupacion>Programador Web</ocupacion>
</persona>
</personas>

You don't have to use linq to do it, you can simply query the elements of your document.
listView1.View = System.Windows.Forms.View.Details;
listView1.AutoArrange = false;
listView1.Alignment = ListViewAlignment.Left;
listView1.Items.Clear();
listView1.Columns.Add("XML",400);
string xml =
#"<?xml version=""1.0"" encoding=""utf-8"" ?>
<personas>
<persona>
<nombre>Pablo el primero</nombre>
<ocupacion>Programador Cliente-Servidor</ocupacion>
</persona>
<persona>
<nombre>Pablo el segundo</nombre>
<ocupacion>Programador Web</ocupacion>
</persona>
</personas>";
XDocument doc = XDocument.Parse(xml);
List<ListViewItem> ItemList = new List<ListViewItem>();
foreach (XElement elem in doc.Elements())
{
AddNewItemToList(ItemList, elem);
}
listView1.Items.AddRange(ItemList.ToArray());
...
private void AddNewItemToList(List<ListViewItem> ItemList, XElement elem)
{
string attributes = "";
if (elem.HasAttributes)
{
foreach (XAttribute attr in elem.Attributes())
{
attributes += " " + attr.Name + "=\"" + attr.Value + "\"";
}
}
if (elem.HasElements)
{
ItemList.Add(new ListViewItem("<" + elem.Name + attributes + ">"));
foreach (XElement childElem in elem.Elements())
{
AddNewItemToList(ItemList, childElem);
}
ItemList.Add(new ListViewItem("</" + elem.Name + ">"));
}
else
{
ItemList.Add(new ListViewItem("<" + elem.Name + attributes + ">" + elem.Value + "</" + elem.Name + ">"));
}
}

Related

Query XML Linq in C#

I want to retrieve data from XML(which have also an xsd file) using C#. What can it be wrong with my code:
My Xml file look likes this.
<Model_1 xmlns="http://www.3ds.com/xsd/3DXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.3ds.com/xsd/3DXML ./3DXML.xsd">
<Header>
<item></item>
<item1></item1>
<item2></item2>
</Header>
<Product>
<otheritem></otheritem>
<otheritem1></otheritem1>
<otheritem2></otheritem2>
</Product>
<Books>
<otheritem></otheritem>
<otheritem1></otheritem1>
<otheritem2></otheritem2>
</Books>
</Model_1>
...c#
XDocument xdoc = Document.Load("document.xml") var items = from item in xdoc.Descendants("Header")
select new
{
_Item= item.Element("Item").Value,
_Item1= item.Element("Item1").Value,
_Item2= item.Element("Item2").Value,
};
foreach (var item in items)
{
Item= item._Item;
Item1 = item._Item1;
Item2 = item.Item2;
}
Console.WriteLine("show me :" + Item+ " + " + Item1 + " + " + Item2);
How can I extract just items from Header and not Product or Books?
You need to use namespace:
var ns = xdoc.Root.GetDefaultNamespace();
var header = xdoc.Root.Element(ns + "Header");
Also keep in mind - you have lower case item in your xml, not Item:
Item = (string)header?.Element(ns + "item");
Item1 = (string)header?.Element(ns + "item1");
Item2 = (string)header?.Element(ns + "item2");

Creating a dynamic xml document

Hi you is it possible to create a dynamica xml with xdocument I've been trying but it appears that it returns an exception about having a wrong structure
My code is the following
public string ReadTest(Stream csvFile)
{
XDocument responseXml = new XDocument( new XDeclaration("1.0", "utf-8", "yes"));
try
{
if ( csvFile != null || csvFile.Length!=0)
{
responseXml.Add(new XElement("root"));
//using(CsvFileReader reader=new CsvFileReader(File.OpenRead(#"C:\Users\toshibapc\Documents\Visual Studio 2013\Projects\WCFLecturaCSV\WCFLecturaCSV\App_Data\archivo.csv"))){
using (CsvFileReader reader = new CsvFileReader(csvFile))
{
CsvRow row = new CsvRow();
List<String> headers = new List<string>();
while (reader.ReadRow(row))
{
int cont = 0;
XElement dato = new XElement("AccountInfos", new XElement("Info"));
XElement datos=null;
foreach (String s in row)
{
if(s.Equals("AccountIDToMove", StringComparison.OrdinalIgnoreCase)|| s.Contains("AccountNameToMove") || s.Contains("NewParentAccountID") || s.Contains("NewParentAccountName")){
headers.Add(s);
}
else{
if (s != String.Empty)
{
datos = new XElement(headers[cont], s); //.Append("<" + headers[cont] + ">" + s + "<" + headers[cont] + "/>");
dato.Add(datos);
}
}
cont++;
}
if (headers.Count == 4 && datos != null)
responseXml.Add(dato);
} // fin de while
}
} // Check if no file i sent or not info on file
}
catch (Exception ex) {
//oError = ex.Message;
}
return responseXml.ToString();
}
What i would like to acomplish by using this code is to get an xml like this
<xml version="1.0">
<root>
<AccountInfos>
<Info>
<AccountIDToMove>312456</AccountIDToMove>
<AccountNameToMove>Burger Count</AccountNameToMove>
<NewParentAccountID>453124</NewParentAccountID>
<NewParentAccountName> Testcom sales 1</NewParentAccountName>
</Info>
<Info>
<AccountIDToMove>874145</AccountIDToMove>
<AccountNameToMove>Mac Count</AccountNameToMove>
<NewParentAccountID>984145</NewParentAccountID>
<NewParentAccountName> Testcom sales 1</NewParentAccountName>
</Info>
</AccountInfos>
</root>
For any answer or help thank you so much
You are adding multiple roots to your document. You initially add one here:
responseXml.Add(new XElement("root"));
And later add more root elements in a loop here:
responseXml.Add(dato);
However, each XML document must have exactly one single root element. Thus you probably want to do:
responseXml.Root.Add(dato);

How to get attribute xml without loop c#

i have xml file like this
> <?xml version='1.0' ?>
<config>
<app>
<app version="1.1.0" />
> </app>
</config>
and i want to read attribute version from node app
without any loop like this
while(reader.read()) or foreach etc.
Thanks
XmlDocument document = new XmlDocument();
document.Load("D:/source.xml");
XmlNode appVersion1 = document.SelectSingleNode("//app[#version]/#version");
XmlNode appVersion2 = document["config"]["app"]["app"].Attributes["version"];
Console.WriteLine("{0}, {1}",
appVersion1.Value,
appVersion2.Value);
You can do it this way.
XmlDocument doc = new XmlDocument();
string str = "<config><app><app version=" + "\"1.1.0\"" + "/></app></config>";
doc.LoadXml(str);
var nodes = doc.GetElementsByTagName("app");
foreach (XmlNode node in nodes)
{
if (node.Attributes["version"] != null)
{
string version = node.Attributes["version"].Value;
}
}
And you need to this for loop cause you got two nodes with same name App.
If you have a single node with name App,
XmlDocument doc = new XmlDocument();
string str = "<config><app version=" + "\"1.1.0\"" + "/></config>";
doc.LoadXml(str);
var node = doc.SelectSingleNode("//app");
if (node.Attributes["version"] != null)
{
string version = node.Attributes["version"].Value;
Console.WriteLine(version);
}
You can use linq to do
string stringXml= "yourXml Here";
XElement xdoc = XElement.Parse(stringXml);
var result= xdoc.Descendants("app").FirstOrDefault(x=> x.Attribute("version") != null).attribute("version").Value;
or:
var result = xdoc.Descendants("app").Where(x => x.Attribute("version") != null)
.Select(x => new { Version = x.Value });

Modify existing xml data using xml document in C#

I want to modify XML data given below:
<?xml version="1.0" encoding="utf-8"?>
<allitems>
<item ID="17997" quantity="three">
<available>Y</available>
<last_modified_price>300</last_modified_price>
<edition>2008<edition>
<item>
<item ID="18039" quantity="two">
<available>Y</available>
<last_modified_price>250</last_modified_price>
<edition>2010<edition>
<item>
</allitems>
all elements value should be modified as per set in runtime....
For this I used following code but data is not modified..please help me in getting solution.
XmlDocument modifydoc = new XmlDocument();
modifydoc.Load(#"E:\XMLapp\XMLstorageWEB\patrick\XMLFile1.xml");
var root = modifydoc.GetElementsByTagName("allitems")[0];
var oldelem = root.SelectSingleNode("item[#ID =" + txt_id.Text + "]");
var newelem = modifydoc.CreateElement("item");
root.ReplaceChild(newelem, oldelem);
while (oldelem.ChildNodes.Count != 0)
{
XmlElement available= modifydoc.CreateElement("available");
available.InnerText = ddl_available.SelectedItem.Text;
XmlElement last_modified_price= modifydoc.CreateElement("last_modified_price");
last_modified_price.InnerText = ddl_last_modified_price.SelectedItem.Text;
XmlElement edition= modifydoc.CreateElement("edition");
edition.InnerText = ddl_edition.SelectedItem.Text;
newelem.AppendChild(available);
newelem.AppendChild(last_modified_price);
newelem.AppendChild(edition);
modifydoc.DocumentElement.AppendChild(newelem);
}
while (oldelem.Attributes.Count != 0)
{
newelem.Attributes.Append(oldelem.Attributes[0]);
}
modifydoc.Save(#"E:\XMLapp\XMLstorageWEB\patrick\XMLFile1.xml");
please give me solution..
Not the cleanest way, to add and remove a XmlNode, but just fixing your code I think this is what you want
var txt_id = "17997";
XmlDocument modifydoc = new XmlDocument();
modifydoc.Load(#"c:\temp\so\1.xml");
var root = modifydoc.GetElementsByTagName("allitems")[0];
var oldelem = root.SelectSingleNode("item[#ID =" + txt_id + "]");
var newelem = modifydoc.CreateElement("item");
root.ReplaceChild(newelem, oldelem);
XmlElement available= modifydoc.CreateElement("available");
available.InnerText = "CambiameInnerText";
XmlElement last_modified_price= modifydoc.CreateElement("last_modified_price");
last_modified_price.InnerText = "LastModifed";
XmlElement edition= modifydoc.CreateElement("edition");
edition.InnerText = "SelectedItem";
newelem.AppendChild(available);
newelem.AppendChild(last_modified_price);
newelem.AppendChild(edition);
modifydoc.DocumentElement.AppendChild(newelem);
foreach (XmlAttribute attribute in oldelem.Attributes)
{
newelem.SetAttribute(attribute.Name, attribute.Value);
}
and your xml is not correct, at least the example
<?xml version="1.0" encoding="utf-8"?>
<allitems>
<item ID="17997" quantity="three">
<available>Y</available>
<last_modified_price>300</last_modified_price>
<edition>2008</edition>
</item>
<item ID="18039" quantity="two">
<available>Y</available>
<last_modified_price>250</last_modified_price>
<edition>2010</edition>
</item>
</allitems>
Here is the small and easy example , i use for change the connectionString value in my [web.config]. I hope it's can help you. So easy to adapt for your code ;-)
System.Xml.XmlDocument myXmlDocument = new System.Xml.XmlDocument();
myXmlDocument.Load("myFullPathWebConfig.xml");
foreach (System.Xml.XmlNode node in myXmlDocument["configuration"]["connectionStrings"])
{
if (node.Name == "add")
{
if (node.Attributes.GetNamedItem("name").Value == "SCI2ConnectionString")
{
node.Attributes.GetNamedItem("connectionString").Value = connectionString;
}
}
}

how to read attribute data inside node in xml

i m creating an web application in that i m matching the user answer with my xml answer i have done all code and my code work fine then after i have changed my xml format so now i m unable to read the attribute of my xml file node.
and below is my xml file.
<?xml version="1.0" encoding="utf-8" ?>
<Exam>
<Question number="1" Text="What is IL Code">
<Answer Text="Half compiled, Partially compiled code"> </Answer>
</Question>
<Question number="2" Text="What is JIT">
<Answer Text="IL code to machine language"> </Answer>
</Question>
<Question number="3" Text="What is CLR">
<Answer Text="Heart of the engine , GC , compilation , CAS(Code access security) , CV ( Code verification)"> </Answer>
</Question>
</Exam>
and below is my snipped code.
XmlDocument docQuestionList = new XmlDocument();// Set up the XmlDocument //
docQuestionList.Load(#"E:\ferozProject\WindowsFormsApplication1\WindowsFormsApplication1\QuestionFile.xml"); //Load the data from the file into the XmlDocument //
XmlNodeList QuestionList = docQuestionList.SelectNodes("Exam/Question");
foreach (XmlNode nodexm in QuestionList)
{
if (**nodexm.InnerText.Trim()** == label2.Text)
{
string[] arrUserAnswer = textBox1.Text.Trim().ToLower().Split(' ');
string[] arrXMLAnswer = nodexm.NextSibling.InnerText.Trim().ToLower().Split(' ');
List<string> lststr1 = new List<string>();
foreach (string nextStr in arrXMLAnswer)
{
if (Array.IndexOf(arrUserAnswer, nextStr) != -1)
{
lststr1.Add(nextStr);
}
}
if (lststr1.Count > 0)
{
label4.Visible = true;
label4.Text = "Your Answer is "+ ((100 * lststr1.Count) / arrXMLAnswer.Length).ToString() + "%" + "Correct";
}
else
{
label4.Text = "Your Answer is Wrong";
}
}
}
XmlNodeList QuestionList = docQuestionList.SelectNodes("Exam/Question");
the above line you can see that i have read the question node but inside the question node there is attribute like Text in that my question present you can see in my xml file.
if (nodexm.InnerText.Trim() == label2.Text)
in the above line i m matching the screen display question with my xml file question but i can't do that.label2 is used for displaying the question
help me please.
Try this (using System.Linq;
using System.Xml;
using System.Xml.Linq;)
XDocument map = XDocument.Parse("<Exam> " +
"<Question number= \"1\" Text=\"What is IL Code\">" +
" <Answer Text=\"Half compiled, Partially compiled code\"> </Answer>" +
"</Question>" +
"<Question number=\"2\" Text=\"What is JIT\">" +
" <Answer Text=\"IL code to machine language\"> </Answer>" +
"</Question>" +
"<Question number=\"3\" Text=\"What is CLR\">" +
" <Answer Text=\"Heart of the engine , GC , compilation , CAS(Code access security) , CV ( Code verification)\"> </Answer>" +
"</Question>" +
"</Exam>");
var atts = map.Descendants("Question").Attributes().Where(a => a.Name == "Text").ToList();
var QuestionList = map.Descendants("Question").ToList();
foreach (XElement nodexm in QuestionList)
{
if((string)nodexm.Attributes("Text").FirstOrDefault()== label2.Text)
{
string[] arrUserAnswer = textBox1.Text.Trim().ToLower().Split(' ');
string[] arrXMLAnswer = nodexm.Elements("Answer").SelectMany(o => ((string)o.Attribute("Text")).Split(',')).ToArray();
List<string> lststr1 = new List<string>();
foreach (string nextStr in arrXMLAnswer)
{
if (Array.IndexOf(arrUserAnswer, nextStr) != -1)
{
lststr1.Add(nextStr);
}
}
if (lststr1.Count > 0)
{
label4.Visible = true;
label4.Text = "Your Answer is "+ ((100 * lststr1.Count) / arrXMLAnswer.Length).ToString() + "%" + "Correct";
}
else
{
label4.Text = "Your Answer is Wrong";
}
}
}

Categories