How to parse XML in a string in .NET? - c#

Hi Fellow StackOverflowers,
I am receiving a string in one of my .NET function. The string when viewed from the XML Visualizer looks like this:
- <root>
- <Table>
<ID>ABC-123</ID>
<CAT>Housekeeping</CAT>
<DATE>21-JUN-2009</DATE>
<REP_BY>John</REP_BY>
<LOCATION>Head Office</LOCATION>
</Table>
- <Table>
<ID>ABC-124</ID>
<CAT>Environment</CAT>
<DATE>23-JUN-2009</DATE>
<REP_BY>Michelle</REP_BY>
<LOCATION>Block C</LOCATION>
</Table>
- <Table>
<ID>ABC-125</ID>
<CAT>Staging</CAT>
<DATE>21-JUN-2009</DATE>
<REP_BY>George</REP_BY>
<LOCATION>Head Office</LOCATION>
</Table>
- <Table>
<ID>ABC-123</ID>
<CAT>Housekeeping</CAT>
<DATE>21-JUN-2009</DATE>
<REP_BY>John</REP_BY>
<LOCATION space="preserve" xmlns="http://www.w3.org/XML/1998/namespace" />
</Table>
</root>
I need to parse this string so that I could write the data into a datatable whose columns are the xml tags for each data.
In the above text, I would then have a datatable that wil have 5 columns, named ID, CAT, DATE, REP_BY and LOCATION which will then contain 4 rows of data.
In the fourth tag, notice that the does not have any data, but rather it is marked space="preserve". This would mean that the data I am placing in my datatable would be blank for the LOCATION column of the fourth row.
How can I achieve this? Sample codes would be highly appreciated. Thanks.

Using the XmlReader class. This class is fast and does not use a lot of memory but reading the xml can be difficult.
using (StringReader strReader = new StringReader(yourXMLString))
{
using (XmlReader reader = XmlReader.Create(strReader))
{
while (reader.Read())
{
if(reader.Name == "Table" && reader.NodeType == reader.NodeType == XmlNodeType.Element)
{
using(XmlReader tableReader = reader.ReadSubtree())
{
ReadTableNode(tableReader);
}
}
}
}
}
private void ReadTableNode(XmlReader reader)
{
while (reader.Read())
{
if(reader.Name == "ID" && reader.NodeType == reader.NodeType == XmlNodeType.Element)
//do something
else if(reader.Name == "CAT" && reader.NodeType == reader.NodeType == XmlNodeType.Element)
//do something
//and continue....
}
}
To get an attribute of the current node you use:
string value = reader.GetAttribute(name_of_attribute);
To get the inner text of an element:
string innerText = reader.ReadString();
Using the XmlDocument class. This class is slow but manipulating and reading the xml is very easy because the entire xml is loaded.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(yourXMLString);
//do something
Using the XDocument class. The advantage of using XDocument is elements can be accessed directly and simultaneously. This class also use the power of LINQ to query the xml document.
using(StringReader tr = new StringReader(yourXMLString))
{
XDocument doc = XDocument.Load(tr);
//do something
}

This is probably the simplest solution to get the XML into table form. Throwing the attributes out using regular expressions is not that smart (and safe), but I don't like the System.Xml API and LINQ to XML is no option in .NET 2.0.
using System;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
namespace GeneralTestApplication
{
class Program
{
private static void Main()
{
String input = #"<root><Table> [...] </root>";
input = Regex.Replace(input, #" [a-zA-Z]+=""[^""]*""", String.Empty);
DataSet dataSet = new DataSet();
dataSet.ReadXml(new StringReader(input));
foreach (DataRow row in dataSet.Tables[0].Rows)
{
foreach (DataColumn column in dataSet.Tables[0].Columns)
{
Console.Write(row[column] + " | ");
}
Console.WriteLine();
}
Console.ReadLine();
}
}
}
UPDATE
Or get rid of the attribute using System.Xml.
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(input));
foreach (XmlNode node in doc.SelectNodes("descendant-or-self::*"))
{
node.Attributes.RemoveAll();
}
input = doc.OuterXml;
But this doesn't work because the XML namespace on the last LOCATION element remains and the DataSet.LoadXml() complains that there connot be two columns named LOCATION.

Don't use string parsing. Try using some xml library (Linq has some objects that might help you). You will probably do that much more easily.

I believe that you can simply use the ADO.NET DataSet class's ReadXml method to read an XML document in that format, and it will create the DataTable, DataColumn, and DataRow objects for you. You'll need to write a little conversion method if you want to subsequently turn the DATE column's data type to DateTime. But other than that, you shouldn't have to screw around with XML at all.
Edit
I see from Daniel Bruckner's post that the LOCATION elements in the odd namespace pose a problem. Well, that's easy enough to fix:
XmlDocument d = new XmlDocument();
d.LoadXml(xml);
XmlNamespaceManager ns = new XmlNamespaceManager(d.NameTable);
ns.AddNamespace("n", "http://www.w3.org/XML/1998/namespace");
foreach (XmlNode n in d.SelectNodes("/root/Table/n:LOCATION", ns))
{
XmlElement loc = d.CreateElement("LOCATION");
n.ParentNode.AppendChild(loc);
n.ParentNode.RemoveChild(n);
}
DataSet ds = new DataSet();
using (StringReader sr = new StringReader(d.OuterXml))
{
ds.ReadXml(sr);
}

I'm not a huge fan of xml myself, I need to use it as the datasource of a grid to visualize it.
I get some output from our FileNet imaging server in xml format and I need to get pieces of it out to populate a database.
Here's what I'm doing, HTH:
Dim dsXML As DataSet
Dim drXML As DataRow
Dim rdr As System.IO.StringReader
Dim docs() As String
Dim SQL As String
Dim xml As String
Dim fnID As String
docs = _fnP8Dev.getDocumentsXML(_credToken, _docObjectStoreName, _docClass, "ReferenceNumber=" & fnID, "")
xml = docs(0)
If (InStr(xml, "<z:row") > 0) Then
RaiseEvent msg("Inserting images for reference number " & fnID)
rdr = New System.IO.StringReader(xml)
dsXML = New DataSet
dsXML.ReadXml(rdr)
For Each drXML In dsXML.Tables(dsXML.Tables.Count - 1).Rows
SQL = "Insert into fnImageP8 values ("
SQL = SQL & "'" & drXML("Id") & "', "
Try
SQL = SQL & "'" & drXML("DocumentTitle") & "', "
Catch ex As Exception
SQL = SQL & "null, "
End Try

Related

Retrieve complete group of nested tags [duplicate]

How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.

How to Read Xaml Content in WPF application and fetch all the UI Control attributes [duplicate]

How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.

How to get specific attributes with values from an xml document using c# console? [duplicate]

How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.

Read xml file containing multiple tags with same attribute name and replace the value based on user's input

Below is my sample XML file stored in the server ;
<exam>
<name>Maths</name>
<percentage>100</percentage>
</exam>
<exam>
<name>Physics</name>
<percentage>70</percentage>
</exam>
<exam>
<name>Chemistry</name>
<percentage>70</percentage>
</exam>
I have another table as mentioned below
Name of Exam Percentage
Maths 50
Physics 60
Chemistry 70
What I need here is that I need to read this XML File and replace the percentage value in the XML file based on the table that I have. I have more than 75 tags for exam
I have used the below logic of hardcoding everything but I am not sure if my logic would be good
public static void Changepercentage()
{
try{
string xmlpercentage= Loaddefault.xmlpercentage;
string f = xml
List<string> lines = new List<string>();
// 2
// Use using StreamReader for disposing.
using (StreamReader r = new StreamReader(f, System.Text.Encoding.Default))
{
// 3
// Use while != null pattern for loop
string line;
while ((line = r.ReadLine()) != null)
{
if (System.Text.RegularExpressions.Regex.IsMatch(line, "<exam>Maths</exam>"))
{
lines.Add(#"" + line + "");
line = "<percentage>50</percentage>";
}
}
}
System.IO.File.WriteAllLines(xmlpercentage, lines.ToArray());
Logger.Instance.InfoLog("Successfully updated the percentage.xml file");
}
catch (Exception ex)
{
Logger.Instance.ErrorLog("Problem in updating the percentage.xml file :"+ ex.Message);
throw new Exception("Problem in updating the percentage.xml file");
}
}
You can use this documentation
//Make sure that the project references the System.Xml namespace.
//Use the Imports statement on the Xml namespace
using System.Xml;
//Create a new XmlDocument class, and use the Load method to load it.
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.Load ("test.xml");
//Iterate through the children of the document element, and find all the "percentage" nodes. and update it.
foreach(XmlNode node1 in node.ChildNodes)
foreach (XmlNode node2 in node1.ChildNodes)
if (node2.Name == "percentage")
{
Decimal percentage = 60;//your new percentage
node2.InnerText = percentage;
}
//Use the Save method of the XmlDocument class to save the altered XML to a new file that is named test1.xml.
myXmlDocument.Save("test1.xml");
Iterate over all <exam> nodes of your XML, read the child node <name>. With the InnerText of name query the data base and put the data base result into the <percentage> node.
Something like this should do:
var doc = XDocument.Parse(yourXml);
foreach(XElement exam in doc.Descendants("exam"))
{
var examName = exam.Descendants("name").First().Value;
var newPercentage = GetPercentage(examName);
exam.Descendants("percentage").First().Value = newPercentage;
}

How to load and merge a dataset of XML docs

I would like to consume a dataset of XML documents, and merge them into a single document containing only distinct elements.
To illustrate, I have a dataset as:
r, x
-- -------------------------------
1, <root><a>111</a></root>
2, <root><a>222</a><b>222</b></root>
3, <root><c>333</c></root>
would result in:
<a>111</a><b>222</b><c>333</c>
The <a> element from r=2 is not merged since we already have an element = <a> from r=1. I need only merge new elements, starting with r=1 going forward.
I am able to iterate over the list, but having difficulty comparing and merging. The code below fails to identify <a>222</a> as a duplicate. Is it possibly comparing the element values as well?
using (SqlDataReader dsReader = cmd.ExecuteReader())
{
XDocument baseDoc = new XDocument();
XDocument childDoc = new XDocument();
while (dsReader.Read())
{
// this is the base doc, merge forward from here
if (dsReader["r"].ToString() == "1")
{
baseDoc = XDocument.Parse(dsReader["x"].ToString());
SqlContext.Pipe.Send("start:" + baseDoc.ToString());
}
// this is a child doc, do merge operation
else
{
childDoc = XDocument.Parse(dsReader["x"].ToString());
// find elements only present in child
var childOnly = (childDoc.Descendants("root").Elements()).Except(baseDoc.Descendants("root").Elements());
foreach (var e in childOnly)
{
baseDoc.Root.Add(e);
}
}
}
}
I am bit confused about baseDoc and childDoc usage in your code. I hope I correctly understood your question. Here is my proposal:
using (SqlDataReader dsReader = cmd.ExecuteReader())
{
XElement result = new XElement("root");
while (dsReader.Read())
{
// Read source
XDocument srcDoc = XDocument.Parse(dsReader["x"].ToString());
// Construct result element
foreach (XElement baseElement in srcDoc.Descendants("root").Elements())
if (result.Element(baseElement.Name) == null) // skip already added nodes
result.Add(new XElement(baseElement.Name, baseElement.Value));
}
// Construct result string from sub-elements (to avoid "<root>..</root>" in output)
string str = "";
foreach (XElement element in result.Elements())
str += element.ToString();
// send the result
SqlContext.Pipe.Send("start:" + str);
}
Note that my code ignores r-numbering. I use order as it comes from sql data reader. If rows are not sorted by "r", then additional sort is required before my code.

Categories