I have a program to display the node name and value like this
public void findAllNodes(XmlNode node)
{
Console.Write("{0}:", node.Name);
Console.WriteLine(node.Value);
Console.WriteLine("{0}"," ");
foreach (XmlNode n in node.ChildNodes)
findAllNodes(n);
}
using this xml:
<application_data>
<applicant_data type="primary">
<first_name>VINNY</first_name>
<mi></mi>
<last_name>SSILVERLACE</last_name>
<ssn>666279999</ssn>
<dob>1973-06-27</dob>
<address type="current">
<po_box_no></po_box_no>
<roural_route></roural_route>
<street_no>7690</street_no>
<street_name>KETTLEDRUMS</street_name>
<apt_no></apt_no>
<city>MILILANI TOWN</city>
<state>HI</state>
<zip_code>96789</zip_code>
</address>
</applicant_data>
</application_data>
But for this code, while displaying the node values, it diplays like this
#text:("node value").
Can you suggest some way to delete "#text" from the node value?
It has nothing to do with your xml, but with your node.Name statement.
If you look here you will see that, node.Name will print #text for text nodes every time. I'm not familiar enough with XmlNode to tell you how to get the tag name as you appear to be wanting. You could try Linq-To-Xml as someone commented.
Example:
public void findAllNodes(XElement node)
{
Console.Write("{0}:", node.Name.ToString());
Console.WriteLine(node.Value);
Console.WriteLine("{0}"," ");
foreach (XElement n in node.Elements())
findAllNodes(n);
}
findAllNodes(XElement.Load(file));
private static void RecurseXmlDocument(XmlNode root)
{
if (root is XmlElement)
{
Console.Write("\n" + root.Name + ": ");
if (root.HasChildNodes) RecurseXmlDocument(root.FirstChild);
if (root.NextSibling != null) RecurseXmlDocument(root.NextSibling);
}
else if (root is XmlText)
{
Console.Write(((XmlText)root).Value);
}
else if (root is XmlComment)
{
Console.Write(root.Value);
if (root.HasChildNodes) RecurseXmlDocument(root.FirstChild);
if (root.NextSibling != null) RecurseXmlDocument(root.NextSibling);
}
}
I modified this according to your needs and it works just fine now. You're going to have to call it like this:
public static void Main()
{
XmlDocument document = new XmlDocument();
document.Load("File.xml");
RecurseXmlDocument((XmlNode)document.DocumentElement);
Console.ReadKey();
}
Related
I am trying to display the id attribute of the channel element called id, the inner text of the display-name tag and the inner text of the icon that sometimes is contained inside the channel element.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv generator-info-name="xmltv.co.uk" source-info-name="xmltv.co.uk">
<channel id="0052a71acac348ff93f5680aa9c125eb">
<display-name>2910</display-name>
</channel>
<channel id="00da025711e82cf319cb488d5988c099">
<display-name>Sony Movies</display-name>
</channel>
<channel id="00dfea977320f17bb419abaa1f079f39">
<display-name>Good Food</display-name>
<icon src="/images/channels/00dfea977320f17bb419abaa1f079f39.png"/>
</channel>
<channel id="018202232e044b504f9dc5263617d496">
<display-name>The Box</display-name>
<icon src="/images/channels/018202232e044b504f9dc5263617d496.png"/>
</channel>
I tried using this code C# code below But the second if give me a error about not referenced to an object.
XmlDocument doc = new XmlDocument();
doc.Load(xmlLocation);
//dispaly the nodes
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
//get the channel
if (node.Name.Equals("channel"))
{
Debug.WriteLine("Channel Name : " + node.ChildNodes[0].Name.ToString()); //or loop through its children as well
//Debug.WriteLine("Channel Name : " + node.AttributeCount.ToString()); //or loop through its children as well
//get the icon element
if(node.ChildNodes[1].Name != null)
Debug.WriteLine("Channel Name : " + node.ChildNodes[1].Name.ToString());
}
}
Although XDocument/XElement and LinQ to XML is the new trend,
to follow your implementation, and adding to it only one feature (using XPATH to query document contents);
Please find the code to fetch channel names and their respective icon source URL's (if exist)
By applying SelectNodes and SelectSingleNode, the API is iterating over the nodes for us.
// Select all the XML elements whose name is "channel"
foreach (XmlNode channelNode in doc.DocumentElement.SelectNodes("channel"))
{
// check if a child element with the name "display-name" exists
XmlNode displayNameNode = channelNode.SelectSingleNode("display-name");
if (displayNameNode != null)
{
// If yes, print the inner text
Debug.WriteLine("Channel Name : " + displayNameNode.InnerText);
}
// then check if the icon node exists
XmlNode iconNode = channelNode.SelectSingleNode("icon");
if (iconNode != null)
{
// and check if it has an attribute with the name "src"
if (iconNode.Attributes["src"] != null)
{
// and if yes, print out its value
Debug.WriteLine(" Icon Src : " + iconNode.Attributes["src"].Value);
}
}
}
First, you need to convert string to XML and load them up in XmlDocument and then use the XPath as shown below. The simple program you can run that in dotnetfiddle.net to check this out.
using System;
using System.Xml;
public class Program
{
public static void Main()
{
string xmlString = "<tv generator-info-name='xmltv.co.uk' source-info-name='xmltv.co.uk'> <channel id='0052a71acac348ff93f5680aa9c125eb'> <display-name>2910</display-name> </channel> <channel id='00da025711e82cf319cb488d5988c099'> <display-name>Sony Movies</display-name> </channel> <channel id='00dfea977320f17bb419abaa1f079f39'> <display-name>Good Food</display-name> <icon src='/images/channels/00dfea977320f17bb419abaa1f079f39.png'/> </channel> <channel id='018202232e044b504f9dc5263617d496'> <display-name>The Box</display-name> <icon src='/images/channels/018202232e044b504f9dc5263617d496.png'/> </channel></tv>";
XmlDocument xmltest = new XmlDocument();
xmltest.LoadXml(xmlString);
XmlNodeList itemNodes = xmltest.SelectNodes("//tv/channel");
foreach(XmlNode itemNode in itemNodes)
{
if (itemNode!= null) {
Console.WriteLine(string.Format("Id:{0}", (itemNode as XmlElement).GetAttribute("id")));
}
}
}
}
How to parse all the XML files under a given directory as an input to the application and write its output to a text file.
Note: The XML is not always the same the nodes in the XML can vary and have any number of Child-nodes.
Any help or guidance would be really helpful on this regard :)
XML File Sample
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>
<CNT>USA</CNT>
<CODE>3456</CODE>
</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
</CATALOG>
C# Code
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;
using System.Xml.Linq;
namespace XMLTagParser
{
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)
{
string loc = locNode.Name;
// 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("Error :-(");
}
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
}
}
Preferred Output:
CATALOG/CD/TITLE
CATALOG/CD/ARTIST
CATALOG/CD/COUNTRY/CNT
CATALOG/CD/COUNTRY/CODE
CATALOG/CD/COMPANY
CATALOG/CD/PRICE
CATALOG/CD/YEAR
CATALOG/CD/TITLE
CATALOG/CD/ARTIST
CATALOG/CD/COUNTRY
CATALOG/CD/COMPANY
CATALOG/CD/PRICE
CATALOG/CD/YEAR
This is a recursive problem, and what you are looking for is called 'tree traversal'. What this means is that for each child node, you want to look into it's children, then into that node's children (if it has any) and so on, recording the 'path' as you go along, but only printing out the names of the 'leaf' nodes.
You will need a function like this to 'traverse' the tree:
static void traverse(XmlNodeList nodes, string parentPath)
{
foreach (XmlNode node in nodes)
{
string thisPath = parentPath;
if (node.NodeType != XmlNodeType.Text)
{
//Prevent adding "#text" at the end of every chain
thisPath += "/" + node.Name;
}
if (!node.HasChildNodes)
{
//Only print out this path if it is at the end of a chain
Console.WriteLine(thisPath);
}
//Look into the child nodes using this function recursively
traverse(node.ChildNodes, thisPath);
}
}
And then here is how I would add it into your program (within your foreach sitemap loop):
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// start traversing from the children of the root node
var rootNode = xDoc.FirstChild;
traverse(rootNode.ChildNodes, rootNode.Name);
}
catch
{
Console.WriteLine("Error :-(");
}
I made use of this other helpful answer: Traverse a XML using Recursive function
Hope this helps! :)
im unable to delete an xml node from a xml file. Im unable to figure out what is the issue in my code. I have attached my code
class Program
{
static void Main(string[] args)
{
XmlDocument xDoc=new XmlDocument();
xDoc.Load(#"C:\Users\MyUser\Desktop\Family.xml");
//try 1
XmlNode firstNode=xDoc.SelectSingleNode("Apartments/Family[Father='Father1']");
xDoc.LastChild.RemoveChild(firstNode);
xDoc.RemoveAll();
//Try2
XmlNodeList nodeColl = xDoc.GetElementsByTagName("Apartments/Family");
foreach (XmlNode xNode in nodeColl)
{
if (xNode["Father"].InnerText == "Father1")
{
xNode.ParentNode.RemoveChild(xNode);
}
}
// firstNode.ParentNode.RemoveChild(firstNode);
}
}
the Xml document format is
<?xml version="1.0"?>
<Apartments>
<Family>
<Father>Father1</Father>
<Mother>Mother1</Mother>
<Daughter>Daughter1</Daughter>
<Son>Son1</Son>
</Family>
<Family>
<Father>Father2</Father>
<Mother>Mother2</Mother>
<Daughter>Daughter2</Daughter>
<Son>Son2</Son>
</Family>
<Family>
<Father>Father3</Father>
<Mother>Mother3</Mother>
<Daughter>Daughter3</Daughter>
<Son>Son3</Son>
</Family>
<Family>
<Father>Father4</Father>
<Mother>Mother4</Mother>
<Daughter>Daughter4</Daughter>
<Son>Son4</Son>
</Family>
</Apartments>
Please let me know where im wrong.
After the modifications you need to save the changes to file.
XmlDocument xDoc=new XmlDocument();
xDoc.Load(#"C:\Users\MyUser\Desktop\Family.xml");
XmlNodeList nodeColl = xDoc.GetElementsByTagName("Apartments/Family");
foreach (XmlNode xNode in nodeColl)
{
if (xNode["Father"].InnerText == "Father1")
{
xNode.ParentNode.RemoveChild(xNode);
}
}
// save the changes back to file
xDoc.Save(#"C:\Users\MyUser\Desktop\Family.xml");
I am trying to delete an element with specific node name. Using the following code but receive an error like "Name cannot begin with the '2' character, hexadecimal value 0x32." As I understand this method is not correct for the relevant xml format.
How can I delete Table with specific User_Name info. should delete specific table When I try to delete Administrator User
RemoveElement("Accounts.xml", "User", "Test1");
private static void RemoveElement(string xmlFile, string elementName, string elementAttribute)
{
XDocument xDocument = XDocument.Load(xmlFile);
foreach (var profileElement in xDocument.Descendants("Table").ToList())
{
if (profileElement.Attribute(elementAttribute).Value == elementName)
{
profileElement.Remove();
}
}
xDocument.Save(xmlFile);
}
Here is the Xml file;
`<?xml version="1.0" encoding="utf-8"?>
<Accounts>
<Table>
<User>Administrator</User>
<Domain>Localhost</Domain>
<Password>Test</Password>
<Account_Type>Windows</Account_Type>
</Table>
<Table>
<User>Test1</User>
<Domain>demo</Domain>
<Password>empty</Password>
<Account_Type>Domain</Account_Type>
</Table>
</Accounts>`
Original code snippet doesn't work because name of user is not an attribute of user but a value. Also, you can replace .Descendants("Table") with .Descendants(elementName) to avoid unnecessary if statement.
I think, the most elegant way to achieve needed functionality is to use Linq to Xml:
XDocument xDocument = XDocument.Load(xmlFile);
xDocument.Descendants(elementName)
.Where(e => e.Value == elementAttribute)
.ToList()
.ForEach(e => e.Remove());
xDocument.Save(xmlFile);
As for your second question: I believe that you remove first element in this line
listViewMevcutKullaniciListesi.Items.RemoveAt(listViewMevcutKullaniciListesi.SelectedIndices[0]);
When you call listViewMevcutKullaniciListesi.SelectedIndices[0] for the second time you obviously get an Exception.
Also, listViewMevcutKullaniciListesi.SelectedIndices[0].ToString() don't give you selected item but just it's number.
Yeah Found it how you can delete when you get info from texBox
xDoc.Load("Accounts.xml");
foreach (XmlNode node in xDoc.SelectNodes("Accounts/Table"))
{
if (node.SelectSingleNode("User").InnerText == textBox1.Text)
{
node.ParentNode.RemoveChild(node);
}
}
xDoc.Save("Accounts.xml");
But I Want to get info from listview. I receive an error When I try to use following code.
Error : InvalidArgument=Value of '0' is not valid for 'index'.\r\nParameter name: index
listViewMevcutKullaniciListesi.Items.RemoveAt(listViewMevcutKullaniciListesi.SelectedIndices[0]);
xDoc.Load("Accounts.xml");
foreach (XmlNode node in xDoc.SelectNodes("Accounts/Table"))
{
if (node.SelectSingleNode("User").InnerText == listViewMevcutKullaniciListesi.SelectedIndices[0].ToString())
{
node.ParentNode.RemoveChild(node);
}
}
xDoc.Save("Accounts.xml");
Here is the answer with XmlDocument class;
You are calling the method like
`RemoveElementWithXmlDocument("Accounts.xml", "Accounts/Table", "User", listViewMevcutKullaniciListesi.SelectedItems[0].Text);`
method;
private static void RemoveElementWithXmlDocument(string xmlFile, string nodeName, string elementName, string elementAttribute)
{
xDoc.Load(xmlFile);
try
{
foreach (XmlNode node in xDoc.SelectNodes(nodeName))
{
if (node.SelectSingleNode(elementName).InnerText == elementAttribute)
{
node.ParentNode.RemoveChild(node);
}
}
xDoc.Save(xmlFile);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
And also I wanna use XDocument class for same structure But I receive an exception like "Object reference not set to an instance of an object" in foreach loop when the ran profileElement.Remove(); line. If I comment out to this line never get the exception but I need this line for removing relevant node from xml. So, As I understand I missing something in XDocument. need your help
RemoveElementWithXDocument("Accounts.xml", "Table", "User", listViewMevcutKullaniciListesi.SelectedItems[0].Text);
method for XDocument
private static void RemoveElementWithXDocument(string xmlFile, string nodeName, string elementName, string elementAttribute)
{
XDocument xDocument = XDocument.Load(xmlFile);
try
{
foreach (XElement profileElement in xDocument.Descendants(nodeName))
{
if (profileElement.Element(elementName).Value == elementAttribute)
{
profileElement.Remove();
}
}
xDocument.Save(xmlFile);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I have already an XML file whose structure is like this:
<?xml version="1.0" encoding="utf-16"?>
<configuration>
<FilePath>C:\Recordings</FilePath>
<Timer>2</Timer>
</configuration>
I want to to add one more child in <configuration> and want the new structure like shown below. Moreover, before adding I also want to make sure that the new child added is present or not.
<?xml version="1.0" encoding="utf-16"?>
<configuration>
<FilePath>C:\Recordings</FilePath>
<Timer>2</Timer>
<LastSyncTime>Some Value</LastSyncTime>
</configuration>
If <LastSyncTime> is not there, then and only it should be added otherwise not.
I have tried so far as given below:
try
{
XmlDocument doc = new XmlDocument();
doc.Load(newpath);
XmlNodeList nodes = doc.SelectNodes("LastSyncDateTime");
if(nodes.Count == 0) //Means LastSyncDateTime node does not exist
{
XmlNode mynode = doc.CreateNode(XmlNodeType.Text, "LastSyncDateTime",null);
mynode.Value = DateTime.Now.ToString() + "";
doc.AppendChild(mynode);
}
foreach (XmlNode node in nodes)
{
if (node.LastChild != null)
{
LastSyncDateTime = (node.LastChild.InnerText);
Console.WriteLine("Last Date Time is : " + LastSyncDateTime);
}
}
}
catch (Exception ex)
{
//throw ex;
string str = (String.Format("{0} {1}", ex.Message, ex.StackTrace));
Console.WriteLine(str);
}
But I am getting exception. Please suggest me best working solution for this.
Thanks
EDIT : I am getting the following exception:
[System.InvalidOperationException] = {"The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong type."}
You should've used XmlNodeType.Element instead of XmlNodeType.Text. And it needs some other fixes as shown below :
.....
XmlNodeList nodes = doc.SelectNodes("//LastSyncDateTime");
if (nodes.Count == 0) //Means LastSyncDateTime node does not exist
{
XmlNode mynode = doc.CreateNode(XmlNodeType.Element, "LastSyncDateTime", null);
//set InnerText instead of Value
mynode.InnerText = DateTime.Now.ToString();
//append to root node (DocumentElement)
doc.DocumentElement.AppendChild(mynode);
}
.....