XMLNode. HasChild considers InnerText as a child node - c#

I’m working on a windows form application I’m trying to see if a certain xml node has child nodes, in the first lines of my code I used OpenFileDialog to open an xml file; in this case the xml sample below.
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
</bookstore>
In my windows form application, I have an open button and a textbox1, the textbox1 is only used to display the address of the xml file and the open button sets everything in motion. Somewhere in the code I have the following lines of code:
using System;
using System.Data;
using System.Windows.Forms;
using System.Xml;
using System.IO;
//other lines of code
private void Open_XML_button_Click(object sender, EventArgs e)
{
//other lines of code
XmlDocument xmldoc = new XmlDocument();
string XML_Location;
XML_Location = textBox1.Text;
xmldoc.Load(XML_Location);
string category = "category = 'cooking'";
XmlNode test1 = xmldoc.SelectSingleNode(string.Format("/bookstore/book[#{0}]/author", category));
if (test1.HasChildNodes == true)
{
MessageBox.Show("It has Child nodes");
}
else
{
MessageBox.Show("it does not have Child nodes");
}
}
Here is what I don’t understand, I’m pointing to the author node which, as far as I can tell, does not have a child node but my code states that it does; if I were to erased Giada de Laurentiis then my code would say that the author node does not have
What Am I doing wrong?

You could check whether there are any child nodes that don't have a NodeType of XmlNodeType.Text:
string category = "category = 'cooking'";
XmlNode test1 = xmldoc.SelectSingleNode(string.Format("/bookstore/book[#{0}]/author", category));
if (test1.ChildNodes.OfType<XmlNode>().Any(x => x.NodeType != XmlNodeType.Text))
{
MessageBox.Show("It has Child nodes");
}
else
{
MessageBox.Show("it does not have Child nodes");
}

It has a child node which is an instance of https://msdn.microsoft.com/en-us/library/system.xml.xmltext(v=vs.110).aspx XmlText. In the DOM there are different kind of nodes and the property HasChildNodes checks for any kind of child nodes (element, comment, processing instruction, text, cdata).

Related

Edit and save element to XML file using Linq

I'm trying to make a small XML editor. It loads an XML file, displays all book titles (in my example file) in a listbox. Clicking on a title displays all information about the book in a textbox. If the information should be modified, the user can click on an Edit button, and the information can now be edited in a new textbox. Finally, the changes are saved and both textboxes cleared - and, if possible, the titles from the newly updated XML file should be reloaded into the listbox (screenshot).
The listbox and first textbox operations work fine, thanks to this post.
The problem arises when I try to send the XML values to the second textbox. Either changes aren't saved or, if they are, the rest of the XML file disappears.
I suppose that a solution might consist in adding the information (and its changes) to a new XML element and then deleting the old one, but so far, and I've been trying for a while now, I simply can't figure out how to do it. It's for the same reason, and I know it's bad style, my code stops short where the problem begins. I'd be glad if someone could help me out.
My example XML:
<?xml version='1.0'?>
<!-- This file represents a fragment of a book store inventory database -->
<books>
<book genre="autobiography">
<title>The Autobiography of Benjamin Franklin</title>
<author>Franklin, Benjamin</author>
<year>1981</year>
<price>8.99</price>
</book>
<book genre="novel">
<title>The Confidence Man</title>
<author>Melville, Herman</author>
<year>1967</year>
<price>11.99</price>
</book>
<book genre="philosophy">
<title>The Gorgias</title>
<author>Plato</author>
<year>1991</year>
<price>9.99</price>
</book>
</books>
And my .cs
private void btnLoadXML_Click(object sender, EventArgs e)
{
var xmlDoc = XDocument.Load("books03.xml");
var elements = from ele in xmlDoc.Elements("books").Elements("book")
where ele != null
select ele;
bookList = elements.ToList();
foreach (var book in bookList)
{
string title = book.Element("title").Value;
listBox1.Items.Add(title);
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var book = bookList[listBox1.SelectedIndex];
textBox1.Text =
"Title: " + book.Element("title").Value + Environment.NewLine +
"Author: " + book.Element("author").Value + Environment.NewLine +
"Year: " + book.Element("year").Value + Environment.NewLine +
"Price: " + book.Element("price").Value;
}
private void btnEdit_Click(object sender, EventArgs e)
{
textBox2.Visible = true;
btnSaveClose.Visible = true;
}
}
Try xml linq :
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);
string searchName = "The Autobiography of Benjamin Franklin";
XElement book = doc.Descendants("book").Where(x => (string)x.Element("title") == searchName).FirstOrDefault();
XElement price = book.Element("price");
price.SetValue("10.00");
}
}
}

Delete node from treeView when Attribute are similar

Am working on my first C# Winform application :(
I browse an XML file to a treeView , then I select node and I wante do delete it.My problem is :
Each node contains an Id attribute , then this node is used two or tree time in the same file , ans i want to delete all the duplicate .
This is an exp :
<list>
<object number="3" background_colour="7" id="2996" name="MyFirst" type="2">
<child id="3794" x="0" y="0"/>
<child id="13794" x="0" y="44"/>
<child **id="13794**" x="239" y="44"/>
</object>
<object height="4" id="13793" line="24487" direction="1"/>
<object height="194" **id="13794"** line_attributes="24487" line ="0"/>
</list`>
So, Now I can delete node ( node is an object) , but I want if i delete the object with id =13794 , I automaticlly delete also the Child with id =13794
I really think about this from one week :( if someone have an idea . Thanks.
My function Code :
private void DeleteHandler(TreeNode tNode)
{
tNode.BackColor = Color.Red;
var messageResult = MessageBox.Show("Are u sur to delete node and childs?", "Alerte de suppression", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (messageResult == System.Windows.Forms.DialogResult.Yes)
RemoveChildNodes(tNode);
else
tNode.BackColor = Color.Transparent;
}
private void RemoveChildNodes(TreeNode aNode)
{
if (aNode.Nodes.Count > 0)
{
for (int i = aNode.Nodes.Count - 1; i >= 0; i--)
{
aNode.Nodes[i].Remove();
}
}
var messageResult = MessageBox.Show("Delete from XML too ?", "Alerte de suppression", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (messageResult == System.Windows.Forms.DialogResult.Yes)
aNode.Remove();
}
private void deleteNode_Click(object sender, EventArgs e)
{
TreeNode sourceNode = sourceTreeView.SelectedNode;
DeleteHandler(sourceNode);
}
Using LINQ you could delete all nodes in the XML with a certain ID like this.
private XDocument DeleteID(string XmlFile, string NodeID)
{
XDocument list = XDocument.Load(XmlFile);
list.Descendants().Where(elm => (string)elm.Attribute("id") == NodeID).Remove();
return list;
}
You could then edit RemoveChildNodes to be something like:
private void RemoveChildNodes(TreeNode aNode)
{
//get the id from the node (I don't know where id is for our purpose I'll say it is in tag
XDocument list = DeleteID(#"c:\temp\test.xml", (string)aNode.Tag);
//reload the tree here
var messageResult = MessageBox.Show("Delete from XML too ?", "Alerte de suppression", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (messageResult == System.Windows.Forms.DialogResult.Yes)
{
list.Save(#"c:\temp\test.xml");
}
}
If I understand what you want to do is remove all the nodes from you Tree that have the same ID. LINQ can be used to build a collection of all Nodes that have a particular ID and then you can just remove all the nodes in the list.
Sorry I haven't time at the moment to produce any code at the moment but I hope this helps.
Ok I have added some code.
Here is a quick piece of code I knocked up. Use it for an idea, I have not tested it. This will only check the top level of nodes but it wouldn't be hard to correct this.
IEnumerable<TreeNode> Result = TreeView.Nodes.WHERE((N) => N.ID == "13794");
foreach(TreeNode Node in Result){TreeView.Nodes.Remove(Node);}
Hope this helps
Danny

Is MoveToParent()/MoveToFirstChild() pair necessary with XPathNavigator?

This is an example of using XPathNavigator from Microsoft.
using System;
using System.Xml;
using System.Xml.XPath;
// http://support.microsoft.com/kb/308343
namespace q308343 {
class Class1 {
static void Main(string[] args) {
XPathNavigator nav;
XPathDocument docNav;
docNav = new XPathDocument(#"Books.Xml");
nav = docNav.CreateNavigator();
nav.MoveToRoot();
//Move to the first child node (comment field).
nav.MoveToFirstChild();
do {
//Find the first element.
if (nav.NodeType == XPathNodeType.Element) {
//Determine whether children exist.
if (nav.HasChildren == true) {
//Move to the first child.
nav.MoveToFirstChild();
//Loop through all of the children.
do {
//Display the data.
Console.Write("The XML string for this child ");
Console.WriteLine("is '{0}'", nav.Value);
//Check for attributes.
if (nav.HasAttributes == true) {
Console.WriteLine("This node has attributes");
}
} while (nav.MoveToNext());
}
}
} while (nav.MoveToNext());
//Pause.
Console.ReadLine();
}
}
}
I think this code has a bug that it doesn't execute MoveToParent() to go up to one level when there is no elements to show.
nav.MoveToFirstChild();
//Loop through all of the children.
do {
....
} while (nav.MoveToNext());
nav.MoveToParent(); <-- This seems to be missing.
However, when I compile/execute this example, it works fine with and without nav.MoveToParent().
Is MoveToParent()/MoveToFirstChild() pair necessary with XPathNavigator? Is it OK not to use MoveToParent() because the second execution of MoveToNext() works as MoveToParent() when the first execution of MoveToNext() returns false?
In this code, after we go through all of the children of the root node, there is no more work to be done, there can't be more than one root node. So there is no need to MoveToParent(), we can just exit. Which is exactly what the code does.

How to insert data into an existing xml file in asp.net?

I'm using Visual Web Developer 2008 Express Edition and I need your assistance since I'm new to it. I'm trying to insert or write a data to my xml file so that I can display it into my xml control. Now, what I'm trying to do here is everytime the user enter a message into the textbox he has an option to save it so if he clicks the command button I want to save the text message from the textbox into any elements of my xml file. Let say, I want to insert it in the element of my xml file. How do I do it using C# or VB.Net codes? I have my xml file below and my C# code but the c# code doesn't work for me. I need the code for that either in c# or vb.net, either way will work for me.
Thank you very much and I greatly appreciate any help that could be shared.
myxmlfile.xml
<?xml version="1.0" encoding="utf-8" ?>
<comments>
<comment>
Your Comments Here: Please post your comments now. Thank you.
</comment>
<comment2>
Note: Please do not post any profane languages.
</comment2>
<comment3>
I don't like their service. It's too lousy.
</comment3>
<comment4>
Always be alert on your duty. Don't be tardy enough to waste your time.
</comment4>
</comments>
code
protected void Button1_Click(object sender, EventArgs e)
{
System.Xml.Linq.XDocument mydoc =
new System.Xml.Linq.XDocument(
new System.Xml.Linq.XDeclaration("1.0", "UTF-8", "yes"),
new System.Xml.Linq.XElement("comment",
new System.Xml.Linq.XComment(TextBox1.Text)));
mydoc.Save("myxmlfile.xml",System.Xml.Linq.SaveOptions .None);
}
#Joseph LeBrech and #AVD --Thank you very much for your reply. That code would add a new root element in myxmlfile so the problem is that the new root element is not showing on my xml control when the page is reloaded because the new root element is not included on my xslt file to show the myxmlfile on the xml control. I don't want to add a new root element on myxmlfile. I just want to insert the messages entered from the textbox into the existing element of myxmlfile which is the element so that it can be shown on the xml control where i intend to display the myxmlfile. I hope you can modify the code for me again. Thank you very for your help. I greatly appreciated it.
You have to specify the absolute file path using MapPath() to save the XML document and don't increment tag name like comment1,comment2.. etc.
Take a look at code-snippet:
protected void Button1_Click(object sender, EventArgs e)
{
string file = MapPath("~/comments.xml");
XDocument doc;
//Verify whether a file is exists or not
if (!System.IO.File.Exists(file))
{
doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new System.Xml.Linq.XElement("comments"));
}
else
{
doc = XDocument.Load(file);
}
XElement ele = new XElement("comment",TextBox1.Text);
doc.Root.Add(ele);
doc.Save(file);
}
EDIT: If you want to insert <comment> tag into existing xml document then no need to create XDocument. Just load the existing document and add a new element at the root.
protected void Button1_Click(object sender, EventArgs e)
{
string file = MapPath("~/myxmlfile.xml");
XDocument doc = XDocument.Load(file);
XElement ele = new XElement("comment",TextBox1.Text);
doc.Root.Add(ele);
doc.Save(file);
}
To add another <comment> tag inside <comment>:
XElement ele = new XElement("comment",TextBox1.Text);
doc.Root.Element("comment").Add(ele);
doc.Save(file);
To replace the text value of <comment> tag:
doc.Root.Element("comment").Value = TextBox1.Text;
//doc.Root.Element("comment").Value += TextBox1.Text; //append text
doc.Save(file);
XML document :
<?xml version="1.0" encoding="utf-8" ?>
<comments> <!-- Root Node -->
<comment>First Child</comment>
<comment> <!-- Second Child -->
<comment>Nested</comment>
</comment>
</comments>
myDoc.Element("comments").Add(new xElement("comment5") { Value = "put the value in here"});
Design the page like this.In button click event write the following
code
protected void btnInsert_Click(object sender, EventArgs e)
{
System.Xml.XmlDocument myXml = new System.Xml.XmlDocument();
myXml.Load(Server.MapPath("InsertData.xml"));
System.Xml.XmlNode xmlNode = myXml.DocumentElement.FirstChild;
System.Xml.XmlElement xmlElement = myXml.CreateElement("entry");
xmlElement.SetAttribute("Name", Server.HtmlEncode(txtname.Text));
xmlElement.SetAttribute("Location", Server.HtmlEncode(txtlocation.Text));
xmlElement.SetAttribute("Email", Server.HtmlEncode(txtemail.Text));
xmlElement.SetAttribute("Gender", Server.HtmlEncode(ddlgender.SelectedItem.Text));
myXml.DocumentElement.InsertBefore(xmlElement,xmlNode);
myXml.Save(Server.MapPath("InsertData.xml"));
BindData();
lbldisplay.Text = "Record inserted into XML file successfully";
txtname.Text = "";
txtlocation.Text = "";
txtemail.Text = "";
}
private void BindData()
{
XmlTextReader xmlReader = new XmlTextReader(Server.MapPath("InsertData.xml"));
xmlReader.Close();
}
and also put events tag in xml file.
Now run the application and check the output

textbox value to be stored into a new node in xml file

i have a textbox for users to enter their new email address. they will click the "Update" button and this text that they entered will then create a new entry in an existing XML file. this xml file is used to populate 2 dropdownlist and needs to constantly update the dropdownlist with new updated entries that user entered.
i tried the following code snipper but i am weak at methods.. so please guide me
xml file: (eg i want a new builder entry)
<?xml version="1.0" encoding="utf-8"?>
<email>
<builderemail>
<builder>
<id>1</id>
<value>builder#xyz.com</value>
</builder>
<builder>
<id>2</id>
<value>Others</value>
</builder>
</builderemail>
<manageremail>
<manager>
<id>1</id>
<value>manager#xyz.com</value>
</manager>
<manager>
<id>2</id>
<value>Others</value>
</manager>
</manageremail>
</email>
so upon this button click i call the method AddNodeToXMLFile
protected void Button1_Click(object sender, EventArgs e)
{
AddNodeToXMLFile("~/App_Data/builderemail.xml", email);
}
public void AddNodeToXMLFile(string XmlFilePath, string NodeNameToAddTo)
{
//create new instance of XmlDocument
XmlDocument doc = new XmlDocument();
//load from file
doc.Load(XmlFilePath);
//create main node
XmlNode node = doc.CreateNode(XmlNodeType.Element, "builder", null);
//create the nodes first child
XmlNode ButtonName = doc.CreateElement("id");
//set the value
ButtonName.InnerText = "1";
//create the nodes second child
XmlNode url = doc.CreateElement("value");
//set the value
url.InnerText = "" + TextBox1.Text;
// add childes to father
node.AppendChild(id);
node.AppendChild(value);
// find the node we want to add the new node to
XmlNodeList l = doc.GetElementsByTagName(NodeNameToAddTo);
// append the new node
l[0].AppendChild(node);
// save the file
doc.Save(XmlFilePath);
}
i think there is something wrong with my code..many thanks for your help
You should write:
// add children to father
node.AppendChild(ButtonName);
node.AppendChild(url);
and you should check if your xmlnodelist contains any nodes to prevent exceptions:
if (l.Count > 0)
{
// append the new node
l[0].AppendChild(node);
}
For the rest it looks alright to me. Good luck!

Categories

Resources