Retrieving Xml Attribute Value in C# - c#

I'm new to C# & I'm trying to read XML attribute from XML file in my Asp.net web project, when i retrieve attribute content i get this result :
"System.XML.Attribute;"
here is XML file:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<!--creating XML file-->
<Document PagesInDocument="1" Filename="YahyaXML">
<Page Filename="YahyaXML" ZonesInPage="1" PageID="0">
<Zone TextLinesInZone="2" zoneLRY="558" zoneLRX="1202"
zoneULY="3" zoneULX="886" ZoneID="0">
<TextLine Content="aaaaaaaaaaa" TextLineID="0"/>
<TextLine Content="aaaaaaaaaaaaaaaaaa" TextLineID="1"/>
</Zone>
</Page>
</Document>
Here is my c# code:
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\Program Files (x86)\NovoDynamics\NovoVerus\api\examples\C#Samples\WebAppTest\Uploads\test-ht.xml");
StringBuilder Content_Value = new StringBuilder();
XmlNodeList aNodes = doc.SelectNodes("/Document/Page/Zone");
XmlNodeList bNodes = doc.SelectNodes("/Document/Page/Zone/TextLine");
foreach (XmlNode aNode in aNodes)
{
XmlAttribute ULX_xml = aNode.Attributes["zoneULX"];
XmlAttribute ULY_xml = aNode.Attributes["zoneULY"];
XmlAttribute LRX_xml = aNode.Attributes["zoneLRX"];
XmlAttribute LRY_xml = aNode.Attributes["zoneLRY"];
if (ULX_xml.Value == TextBox5.Text && ULY_xml.Value == TextBox6.Text && LRX_xml.Value == TextBox7.Text && LRY_xml.Value == TextBox8.Text )
{
foreach (XmlNode bNode in bNodes)
{
//XmlAttribute ContentAttribute = bNode.Attributes["Content"];
if (bNode.Attributes["Content"].Value != null)
{
Content_Value.Append(bNode.Attributes["Content"].Value.ToString());
}
}
Content_Value.Append("\n");
}
}
TextBox9.Text = Content_Value.ToString();

Your code works. Try change first string in your xml file to:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
More: https://msdn.microsoft.com/en-us/library/ms256048(v=vs.120).aspx

Using xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(FILENAME);
reader.ReadLine(); //skip identification
XDocument doc = XDocument.Load(reader);
var results = doc.Descendants("Page").Select(x => new
{
filename = (string)x.Attribute("Filename"),
page = (int)x.Attribute("ZonesInPage"),
id = (int)x.Attribute("PageID"),
zones = x.Elements("Zone").Select(y => new {
textLines = (int)y.Attribute("TextLinesInZone"),
ulx = (int)y.Attribute("zoneULX"),
uly = (int)y.Attribute("zoneULY"),
lrx = (int)y.Attribute("zoneLRX"),
lry = (int)y.Attribute("zoneLRY"),
textLine = y.Elements("TextLine").Select(z => new {
content = (string)z.Attribute("Content"),
id = (int)z.Attribute("TextLineID")
}).ToList()
}).ToList()
}).ToList();
}
}
}

Related

Filter Attributes in Xml in c# AND modify the Xml

I am trying to convert and Xml A into Xml B using C#.
XML A
<root>
<country>
<city name="Boston" value="100">
<city name="Boston" value="200">
</country>
</root>
XMl B(Expected)
<root>
<country>
<city name="Boston" value="300">
</country>
</root>
C# code:
var doc = XDocument.Load(path);
var myDocument = new XmlDocument();
myDocument.Load(path);
var nodes = myDocument.GetElementsByTagName("city");
var resultNodes = new List<XmlNode>();
foreach (XmlNode node in nodes)
{
if (node.Attributes != null && node.Attributes["name"] != null && node.Attributes["name"].Value == "Boston")
resultNodes.Add(node);
foreach(var elements in resultNodes)
{
elements.Attributes.RemoveNamedItem("Boston");
}
}
Basically what i wanted to do here is add the 2 values(100 &200)from 2 different Boston attributes from XML A and print into a new XML B file but lost a bit here as what goes into this block.
foreach (XmlNode i in resultNodes)
{
}
Problems like this is easy to create new XElements. See code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> countries = doc.Descendants("country").ToList();
foreach (XElement oldCountry in countries)
{
XElement newCountry = new XElement("country");
var cities = oldCountry.Elements("city").GroupBy(x => (string)x.Attribute("name"));
foreach (var city in cities)
{
newCountry.Add(new XElement("city", new object[] { new XAttribute("name", city.Key), new XAttribute("value", city.Sum(x => (int)x.Attribute("value"))) }));
}
oldCountry.ReplaceWith(newCountry);
}
}
}
}

Replace the value by relying on the existing value in XML file

This is a sample XML file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Automation Test</string>
<string name="current_data_state_incoming_call">Incoming Call</string>
<string name="current_data_state_outgoing_call">Outgoing Call</string>
<string name="current_data_state_missed_call">Missed Call</string>
<string name="current_data_state_photo">Photo</string>
<string name="current_data_state_video">Video</string>
<string name="current_data_state_mp3">MP3</string>
<string name="current_data_state_voice_memo">Voice Memo</string>
<string name="current_data_state_phone_book">Phone Book</string>
<string name="current_data_state_phone_booksim">Phone Book(SIM)</string>
<string name="current_data_state_etc">Etc</string>
<string name="current_data_state_schedule">S Planner</string>
</resources>
I have a large file XML file and I want to replace the values in elements depending on their original value.
For example, I want to replace "Outgoing Call" with another word.
I tried this code:
XmlDocument xdoc = new XmlDocument();
xdoc.Load("strings.xml");
XmlElement root = xdoc.DocumentElement;
XmlNodeList elemList = root.GetElementsByTagName("string");
for (int i = 0; i < elemList.Count; i++)
{
xdoc.Save("strings.xml");
if (elemList[i].InnerText == "Incoming Call")
{
// xdoc.LoadXml(File.ReadAllText("strings.xml").Replace(elemList[i].InnerText, "صندوق"));
// MessageBox.Show(elemList[i].InnerText);
elemList[i].SelectSingleNode("resources/string").InnerText="مكالمات قادمة";
xdoc.Save("strings.xml");
}
}
and this code
XmlDocument xdoc = new XmlDocument();
xdoc.Load("strings.xml");
XmlNodeList aNodes = xdoc.SelectNodes("resources/string");
foreach (XmlNode node in aNodes)
{
XmlNode child1 = node.SelectSingleNode("string");
if(child1.InnerText == "Incoming Call")
{
child1.InnerText = "اتصالات قادمة";
}
}
xdoc.Save("strings.xml");
I can not replace the value.
===================================
thanx i solve my prob
var root2 = new XmlDocument();
root2.Load("strings.xml");
var root = new XmlDocument();
root.Load("strings2.xml");
foreach (XmlNode e1 in root2.GetElementsByTagName("string"))
{
string a = e1.Attributes["name"].Value;
foreach (XmlNode ee in root.GetElementsByTagName("string"))
{
string b = ee.Attributes["name"].Value;
if (a == b)
{
e1.FirstChild.Value = ee.FirstChild.Value;
}
}
}
root.Save("strings.xml");
I would use LINQ to XML for this. It makes all kinds of things much simpler than XmlDocument. Here's a complete example to perform a replacement (loading input.xml and writing output.xml):
using System;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
XDocument doc = XDocument.Load("input.xml");
ReplaceValue(doc, "Outgoing Call", "Other value");
doc.Save("output.xml");
}
static void ReplaceValue(XDocument doc, string original, string replacement)
{
foreach (var element in doc.Descendants("string").Where(x => x.Value == original))
{
element.Value = replacement;
}
}
}
You could easily change the method to throw an exception if it didn't find the value you were trying to replace, or if it found more than one element.
An alternative to replacing by value would be to replace by the name attribute, which would be a trivial change:
static void ReplaceNamedValue(XDocument doc, string name, string replacement)
{
foreach (var element in doc.Descendants("string")
.Where(x => (string) x.Attribute("name") == name))
{
element.Value = replacement;
}
}
You'd then call it like this:
ReplaceNamedValue(doc, "current_data_state_outgoing_call", "Other value");
You may want to create file on xml on the fly instead of replace. I prefer using the newer Net library xml linq (XDocument) rather than the older version XmlDocument. Here is an example of the code I would use :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string ident = "<?xml version=\"1.0\" encoding=\"utf-8\"?><resources></resources>";
XDocument doc = XDocument.Parse(ident);
XElement resources = doc.Root;
resources.Add(new XElement("string", new object[] {
new XAttribute("name","app_name"),
"Automation Test"
}));
resources.Add(new XElement("string", new object[] {
new XAttribute("name","current_data_state_incoming_call"),
"مكالمات قادمة"
}));
}
}
}
Here is code for replacement
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement resource = doc.Root;
Dictionary<string, XElement> dict = resource.Elements()
.GroupBy(x => (string)x.Attribute("name"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
if(dict.ContainsKey("app_name"))
{
dict["app_name"].SetValue("Automation Test");
}
if (dict.ContainsKey("current_data_state_incoming_call"))
{
dict["current_data_state_incoming_call"].SetValue("مكالمات قادمة");
}
}
}
}

how do you retrieve xml data from nested nodes

<CustomerOrders>
<Customers>
<CustomerID>ALFKI</CustomerID>
<Orders>
<OrderID>10643</OrderID>
<CustomerID>ALFKI</CustomerID>
<OrderDate>1997-08-25</OrderDate>
</Orders>
<Orders>
<OrderID>10692</OrderID>
<CustomerID>ALFKI</CustomerID>
<OrderDate>1997-10-03</OrderDate>
</Orders>
<CompanyName>Alfreds Futterkiste</CompanyName>
</Customers>
<Customers>
<CustomerID>ANATR</CustomerID>
<Orders>
<OrderID>10308</OrderID>
<CustomerID>ANATR</CustomerID>
<OrderDate>1996-09-18</OrderDate>
</Orders>
<CompanyName>Ana Trujillo Emparedados y helados</CompanyName>
</Customers>
</CustomerOrders>
How do you retrieve OrderID,CustomerID and OrderDate? i have been trying it for hours already. Can someone help me? Thanks!
XmlNodeList xmlnode = doc.GetElementsByTagName("Customers");
HtmlGenericControl div = new HtmlGenericControl("div");
for(int i = 0; i < xmlnode.Count; i++)
{
Label lbl2 = new Label();
lbl2.Text = xmlnode[i].ChildNodes[1].Name;
div.Controls.Add(lbl2);
RadioButtonList rb1 = new RadioButtonList();
rb1.Items.Add(xmlnode[i].ChildNodes[1].InnerText+"<br>");
div.Controls.Add(rb1);
}
div1.Controls.Add(div);
You can use the XDocument class and its decendants. You can use XPath expressions to delve deeper into the code:
e.g.
using System.Xml.Linq
using System.Xml.XPath
....
XDocument doc= XDocument.Load("sample.xml");
XElement root= doc.Element("CustomerOrders");
var result= root.XPathSelectElements("Customers/CustomerId");
foreach(var customerid in result)
{
.....
}
Depending on what you want to achieve this should put you at the right track. While I was typing the answer, another answer proposes to use XmlDocument class. That should work as well, but when using XDocument you can use Linq, which adds a lot of flexibilty.
XmlDocument doc = new XmlDocument();
doc.LoadXml("yourxmldata");
XmlNodeList customers = doc.DocumentElement.SelectNodes("Customers");
foreach (XmlNode customer in customers)
{
XmlNodeList customerOrders = customer.SelectNodes("Orders");
string customername = customer["CustomerID"].InnerText;
foreach (XmlNode customerOrder in customerOrders)
{
string orderid = customerOrder["OrderID"].InnerText;
string orderdate = customerOrder["OrderDate"].InnerText;
}
}
Here is everything using Xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication47
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("Customers").Select(x => new
{
customerID = (string)x.Element("CustomerID"),
companyName = (string)x.Element("CompanyName"),
orders = x.Elements("Orders").Select(y => new {
orderID = (int)y.Element("OrderID"),
customerID = (string)y.Element("CustomerID"),
date = (DateTime)y.Element("OrderDate")
}).ToList()
}).ToList();
}
}
}

How to get all attribute names from selected XML node in C#

This is my XML file. I need to select one test element and get all attributes name from its result child nodes.
<?xml version="1.0" encoding="UTF-8"?>
<summary>
<test>
<id>test 1</id>
<result value="-45">330</result>
<result value="0">300</result>
<result value="45">340</result>
</test>
<test>
<id>test 3</id>
<result value="-45">330</result>
<result value="0">300</result>
<result value="45">340</result>
</test>
</summary>
I wrote below code. but repeat same values and I want to stop it.
XmlDocument xd = new XmlDocument();
xd.Load(_xmlFilePath);
XmlNodeList nodelist = xd.GetElementsByTagName("result");
foreach (XmlNode node in nodelist)
{
string attrVal = node.Attributes["value"].Value;
Console.WriteLine(attrVal);
}
Any suggestion is appreciated.
Thanks.
You can use LINQ to Xml with XDocument class
var doc = XDocument.Load(_xmlFilePath);
var distinctResults = doc.Descendants("result")
.Select(element => element.Attribute("value").Value)
.Distinct();
foreach(var result in distinctResults)
{
Console.WriteLine(result);
}
Or with using of HashSet<string>
var results = doc.Descendants("result")
.Select(element => element.Attribute("value").Value);
var distinctResults = new HashSet<string>(results);
foreach(var result in distinctResults)
{
Console.WriteLine(result);
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication34
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string id = "test 1";
var results = doc.Descendants("test").Where(x => (string)x.Element("id") == id).FirstOrDefault().Elements("result").Select(x => new
{
angle = (int)x.Attribute("value"),
length = (int)x
}).ToList();
}
}
}

I want to recursively list the nodes in xml

I recursively want to display xml nodes. But unfortunately it doesn't work. The output is only the first element of the xml file. Why?
public string GetOutline(int indentLevel, XmlNode xnod)
{
StringBuilder result = new StringBuilder();
XmlNode xnodWorking;
result = result.AppendLine(new string('-', indentLevel * 2) + xnod.Name);
if (xnod.NodeType == XmlNodeType.Element)
{
if (xnod.HasChildNodes)
{
xnodWorking = xnod.FirstChild;
while (xnodWorking != null)
{
GetOutline(indentLevel + 1, xnodWorking);
xnodWorking = xnodWorking.NextSibling;
}
}
}
return result.ToString();
}
Here the code calling the function. The XML file begins with <Videos> then <Video>... etc...
private void button2_Click(object sender, EventArgs e)
{
SaveFileDialog fDialog = new SaveFileDialog();
fDialog.Title = "Save XML File";
fDialog.FileName = "drzewo.xml";
fDialog.CheckFileExists = false;
fDialog.InitialDirectory = #"C:\Users\Piotrek\Desktop";
if (fDialog.ShowDialog() == DialogResult.OK)
{
using (var newXmlFile = File.Create(fDialog.FileName));
{
string xmlTree = fDialog.FileName.ToString();
XmlDocument xdoc = new XmlDocument();
xdoc.Load(XML);
XmlNode xnodDE = xdoc.DocumentElement;
textBox2.Text = GetOutline(0, xnodDE);
//StringBuilder result = new StringBuilder();
/*
foreach (var childelement in xdoc.DescendantNodes().OfType<XElement>()
.Select(x => x.Name).Distinct())
{
result.Append(childelement + Environment.NewLine );
}
textBox2.Text = result.ToString();
*/
using (StreamWriter sw = File.AppendText(xmlTree))
{
sw.Write(textBox2.Text);
}
}
}
XML content :
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Actors>
<Actor>Eddie Murphy</Actor>
<Actor>Lane Smith</Actor>
<Actor>Sheryl Lee Ralph</Actor>
<Actor>Joe Don Baker</Actor>
</Actors>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>
You need to read all document line by line whith a for each or a while instruction
XmlReader reader = XmlReader.Create(your xml file);
reader.MoveToContent();
while (reader.Read())
{
// your code
}
reader.Close();
not the best way, try to have a look also on linq to xml
try that
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace testStackOverflow
{
class Program
{
static void Main(string[] args)
{
//Load xml
XDocument xdoc = XDocument.Load("test.xml");
//Run query
var lv1s = from lv1 in xdoc.Descendants("Video")
select new
{
title = lv1.Element("Title").Value
};
//Loop through results
foreach (var lv1 in lv1s)
{
Console.WriteLine(lv1.title);
}
Console.ReadLine();
}
}
}
You're not doing anything to add the results of the recursive calls to the string you're building. You need to do this:
result.Append(GetOutline(indentLevel + 1, xnodWorking));
And this modification should avoid the text nodes and nodes with the same name:
public string GetOutline(int indentLevel, XmlNode xnod)
{
StringBuilder result = new StringBuilder();
XmlNode xnodWorking;
result = result.AppendLine(new string('-', indentLevel * 2) + xnod.Name);
if (xnod.HasChildNodes)
{
List<string> foundElements = new List<string>();
xnodWorking = xnod.FirstChild;
while (xnodWorking != null)
{
if(xnodworking.NodeType == XmlNodeType.Element && !foundElements.Contains(xnodworking.Name))
{
result.Append(GetOutline(indentLevel + 1, xnodWorking));
foundElements.Add(xnodworking.Name);
}
xnodWorking = xnodWorking.NextSibling;
}
}
return result.ToString();
}

Categories

Resources