Read particular depth XML ELEMENTS using XmlReader in C# - c#

I have an XML file with some nodes at different depths. I need a code to read only specific depth nodes but not all, and only by using XmlReader in C#.
Can someone help me in this?
Below is my XML structure. I want to read only "Depth2" nodes.
<Depth0>
<Depth1>
<Depth2/>
<Depth2/>
<Depth2/>
</Depth1>
<Depth1>
<Depth2/>
<Depth2/>
<Depth2/>
</Depth1>
<Depth1>
<Depth2/>
<Depth2/>
<Depth2/>
</Depth1>
</Depth0>
Code:
using (var reader = XmlReader.Create("D:\\xyz.xml"))
{
while (reader.Read())
{
if (reader.Depth == 4 && reader.NodeType == XmlNodeType.Element)
{
XmlReader chnode = reader.ReadSubtree();
AddItems(chnode);
}
else
reader.MoveToElement();
}
}

You can use the Descendants function:
var result = XDocument.Load("data.xml").Root
.Descendants("Depth2");
It will find for you all the Depth2 elements anywhere under the xml's Root
For an XmlReader way you can:
List<XmlNode> nodes = new List<XmlNode>();
using (var reader = XmlReader.Create("data.xml"))
{
XmlDocument document = new XmlDocument();
while (reader.Read())
{
if (reader.Depth == 2 && reader.NodeType == XmlNodeType.Element)
{
XmlNode node = document.CreateNode(XmlNodeType.Element, reader.Name, "");
//Here I just added all the inner xml but you can do whatever you need
node.InnerXml = reader.ReadInnerXml();
nodes.Add(node);
}
reader.MoveToElement();
}
}

Related

Console is able to display all imported XML data but cannot send all information to text file

I have the following code that gathers all elements and attributes from an XML file and sends to the Console. This works without issue.
I want to send the data to a text file, but only the first line or last line show up. Does anyone have any suggestions for having the data sent to a txt file?
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);
XmlNode rootNode = xmlDoc.DocumentElement;
DisplayNodes(rootNode);
Console.ReadLine();
void DisplayNodes(XmlNode node)
{
//Print the node type, node name and node value of the node
if (node.NodeType == XmlNodeType.Text)
{
Console.WriteLine(node.Value.TrimStart());
}
else
{
Console.WriteLine(node.Name.TrimStart());
}
//Print attributes of the node
if (node.Attributes != null)
{
XmlAttributeCollection attrs = node.Attributes;
foreach (XmlAttribute attr in attrs)
{
Console.WriteLine(attr.Name + " " + attr.Value + "\n");
}
}
XmlNodeList children = node.ChildNodes;
foreach (XmlNode child in children)
{
DisplayNodes(child);
}
}
You can use the static methods in the File class to write to a text file very easily, since it wraps the stream creation for you.
First, we could re-write your method above to return a List<string>, which then could be written to the console or a file, or anything else:
public static List<string> GetNodeInfo(XmlNode node)
{
if (node == null) return new List<string>();
var nodes = new List<string>
{
node.NodeType == XmlNodeType.Text
? node.Value.TrimStart()
: node.Name.TrimStart()
};
if (node.Attributes != null)
{
nodes.AddRange(node.Attributes.Cast<XmlAttribute>()
.Select(attribute => $"{attribute.Name} {attribute.Value}\n"));
}
nodes.AddRange(node.ChildNodes.Cast<XmlNode>().SelectMany(GetNodeInfo));
return nodes;
}
Now, we can use this method to get the node information and then write it to whatever we want:
List<string> nodeInfo = GetNodeInfo(myNode);
// Write it to the console:
Console.WriteLine(string.Join(Environment.NewLine, nodeInfo));
// Write it to a file:
File.WriteAllLines(myFilePath, nodeInfo);
I just found the answer to my question. I used the following:
using (FileStream f = new FileStream(fileName, FileMode.Append, FileAccess.Write))
using (StreamWriter s = new StreamWriter(f))
For each Console.Writline change to
s.WriteLine

How to retrieve all Elements from XML file using c#

I am trying to retrieve all elements from an XML file, but I just can reach one, is there any way I can retrieve all?
HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
using (XmlReader reader = XmlReader.Create(new StreamReader(objResponse.GetResponseStream())))
{
while (reader.Read())
{
#region Get Credit Score
//if (reader.ReadToDescendant("results"))
if (reader.ReadToDescendant("ssnMatchIndicator"))
{
string ssnMatchIndicator = reader.Value;
}
if (reader.ReadToDescendant("fileHitIndicator"))
{
reader.Read();//this moves reader to next node which is text
result = reader.Value; //this might give value than
Res.Response = true;
Res.SocialSecurityScore = result.ToString();
//break;
}
else
{
Res.Response = false;
Res.SocialSecurityScore = "Your credit score might not be available. Please contact support";
}
#endregion
#region Get fileHitIndicator
if (reader.ReadToDescendant("fileHitIndicator"))
{
reader.Read();
Res.fileHitIndicator = reader.Value;
//break;
}
#endregion
}
}
Can somebody help me out with this issue?
I am also using objResponse.GetResponseStream() because the XML comes from a response from server.
Thanks a lot in advance.
Try this :
XmlDataDocument xmldoc = new XmlDataDocument();
XmlNodeList xmlnode ;
int i = 0;
string str = null;
FileStream fs = new FileStream("product.xml", FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
xmlnode = xmldoc.GetElementsByTagName("Product");
for (i = 0; i <= xmlnode.Count - 1; i++)
{
xmlnode[i].ChildNodes.Item(0).InnerText.Trim();
str = xmlnode[i].ChildNodes.Item(0).InnerText.Trim() + " " + xmlnode[i].ChildNodes.Item(1).InnerText.Trim() + " " + xmlnode[i].ChildNodes.Item(2).InnerText.Trim();
MessageBox.Show (str);
}
I don't know why what you're doing is not working, but I wouldn't use that method. I've found the following to work well. Whether you're getting the xml from a stream, just put it into a string and bang...
StreamReader reader = new StreamReader(sourcepath);
string xml = reader.ReadToEnd();
reader.Close();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList list = doc.GetElementsByTagName("*");
foreach (XmlNode nd in list)
{
switch (nd.Name)
{
case "ContactID":
var ContactIdent = nd.InnerText;
break;
case "ContactName":
var ContactName = nd.InnerText;
break;
}
}
To capture what is between the Xml tags, if there are no child Xml tags, use the InnerText property, e.g. XmlNode.InnerText. To capture what is between the quotes in the nodes' attributes, use XmlAttribute.Value.
As for iterating through the attributes, if one of your nodes has attributes, such as the elements "Name", "SpectralType" and "Orbit" in the Xml here:
<System>
<Star Name="Epsilon Eridani" SpectralType="K2v">
<Planets>
<Planet Orbit="1">Bill</Planet>
<Planet Orbit="2">Moira</Planet>
</Planets>
</Star>
</System>
Detect them using the Attributes property, and iterate through them as shown:
if (nd.Attributes.Count > 0)
{
XmlAttributeCollection coll = nd.Attributes;
foreach (XmlAttribute cn in coll)
{
switch (cn.Name)
{
case "Name":
thisStar.Name = cn.Value;
break;
case "SpectralType":
thisStar.SpectralClass = cn.Value;
break;
}
}
}
You might find some more useful information HERE.

c# code to read xml file values

I have this xml file and I want to extract author name and access number and what I have is a very naive implementation in C# where I am using xml reader and reading line by line. But I am looking for an implementation where I can read the author name and access number in c# efficiently. I am new to C# and I have been told that LINQ should be used but looking at the document and this file I am not able to relate how to use Xdocument. Any help will be appreciated.
<xml>
<records>
<record>
<database name="CP_EndnoteLibrary_2012-2015-1.enl" path="C:\Users\Downloads\file.enl">file.enl</database>
<source-app name="EndNote" version="17.4">EndNote</source-app>
<rec-number>24</rec-number>
<contributors>
<authors>
<author>
<style face="normal" font="default" size="100%">ABCD, X.</style>
</author>
<author>
<style face="normal" font="default" size="100%">EFGH, I.</style>
</author>
</authors>
</contributors>
<accession-num>
<style face="normal" font="default" size="100%">12345678</style>
</accession-num>
</record>
<record>...</record>
</records>
Following a document, I was able to write this code to figure out author name.
{
class Program
{
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create("C:\\Users\\ile_xml.xml");
while(reader.Read())
{
if((reader.NodeType == XmlNodeType.Element) && (reader.Name == "author"))
{
reader.Read();
reader.Read();
if((reader.NodeType == XmlNodeType.Element) && (reader.Name == "style") && reader.HasAttributes)
{
var val = reader.ReadInnerXml();
Console.WriteLine("Display:" + reader.GetAttribute("author"));
}
}
}
}
}
}
The above code seems to be very inefficient and I am looking for ways to improve this or do it in a better way.
This will give you the correct result:-
XDocument xdoc = XDocument.Load(#"YourXMLfilePath");
var result = xdoc.Root.Elements("record")
.Select(x => new
{
Name = (string)x.Element("database").Attribute("name"),
Number = (string)x.Element("rec-number")
});
//Helpfull namespaces:
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml.Serialization;
static void Main(string[] args)
{
//Your snippet, which didn't work on my machine:
XmlReader reader = XmlReader.Create("C:\\Users\\Public\\ile_xml.xml");
while (reader.Read())
{
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "author"))
{
reader.Read();
reader.Read();
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "style") && reader.HasAttributes)
{
var val = reader.ReadInnerXml();
Console.WriteLine("Display:" + reader.GetAttribute("author"));
}
}
}
//Should produce the results you are looking for:
XmlNodeList xmlNodeList;
XmlDocument xDoc = new XmlDocument();
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.DtdProcessing = DtdProcessing.Parse;
//Get Authors from XML Source
using (XmlReader reader2 = XmlReader.Create("C:\\Users\\Public\\ile_xml.xml"))
{
xDoc.Load(reader2);
xmlNodeList = xDoc.SelectNodes("records/record/contributors/authors/author");
}
foreach (XmlNode node in xmlNodeList)
{
Console.WriteLine(node.InnerText);//.InnerXML to include style tags.
};
}
xpath will help find the information you need. Hopefully the above will get you closer with xdoc.
Another pattern I have recently adopted is to serialize the xml into c# class (or in this case a List) and then use LINQ to manipulate as desired.
this was helpful to me: Deserializing XML to Objects in C#

Read the data from XML file into flat files(txt) and with formated data

I have an XML file with nodes and data...I need to write that into a text file as normal data. The nodes being the headers of the data
that follow.
EG XML:
<Bank>
<accountholder>Georgina Wax</accountholder>
<accountnumber>408999703657</accountnumber>
<accounttype>cheque</accounttype>
<bankname>National Bank</bankname>
<branch>Africa</branch>
<amount>2750.00</amount>
<date>12/01/2012</date>
</Bank>
To txt file and formatted as :
accountholder accountnumber accounttype bankname
Georgina Wax 408999703657 cheque National Bank
I can't seem to have it to have spaces between the data and hearders.
Below is what I tried :
StreamWriter writer = File.CreateText(#"C:\\Test.txt");
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\\bank.xml");
writer.WriteLine(string.Join("|",doc.SelectSingleNode("/debitorders/deduction").ChildNodes.C ast<XmlElement>().Select(e => doc.SelectSingleNode("/debitorders/deduction/bankname").ToString())));
foreach (XmlElement book in doc.SelectNodes("/debitorders/deduction"))
{
writer.WriteLine(book.ChildNodes.Cast<XmlElement>().Select(e => e.InnerText).ToArray());
}
Please help.
This will produce output like you want.
private static void LoadAndWriteXML()
{
string headerFiles = "";
string values = "";
using (XmlReader reader = XmlReader.Create(#"C:\\bank.xml"))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && !reader.Name.Equals("Bank")) // we have to skip root node means bank node.
{
headerFiles += reader.Name + " ";
values += reader.ReadString() + " ";
}
}
}
StreamWriter writer = new StreamWriter(#"C:\\Test.txt");
writer.WriteLine(headerFiles.Trim());
writer.WriteLine(values.Trim());
writer.Close();
}
XDocument xdoc = new XDocument();
xdoc = XDocument.Load(fname);
xdoc.Save(fname1);
will save the file with the tags alignment formating

Enumerating Linq.Xelement

How to adjust this code to work when RESPONSE is no more string but Linq.Xelement?
String response = "anyxml data";
XmlDocument xmlDocument = LoadXMLDocument(response);
XmlNodeList nodeList = xmlDocument.GetElementsByTagName("fql_query_response");
if (nodeList != null && nodeList.Count > 0)
{
if (nodeList[0].HasChildNodes)
{
XmlNodeList results = xmlDocument.GetElementsByTagName("event_member");
Dictionary<string, EventUser> eventUserDict = new Dictionary<string, EventUser>();
foreach (XmlNode node in results)
{
myuids.Add(Int64.Parse(node.FirstChild.InnerText));
}
}
Do you mean you want to create an XmlDocument from an XElement?
The simplest way to do that may well be this:
XmlDocument doc = new XmlDocument();
using (XmlReader reader = element.CreateReader())
{
doc.Load(reader);
}
However, I have to say the code would probably be simpler if you just converted it all to LINQ to XML, which is generally a nicer API to start with. Is there any reason why you want to stay with XmlDocument?
You can use XElement.ToString() to create an XML string from the XElement which you can load into your XmlDocument:
XmlDocument xmlDocument = LoadXMLDocument(yourXElement.ToString());

Categories