How to search the XML tag? - c#

I want to search the tags in XML.
My XML is:-
<school>
<student>
<firstname>Vijay</firstname>
<lastname>Prabhu</lastname>
<age>27</age>
<photo>/NewExample;component/Images/icon_man.png</photo>
</student>
<student>
<firstname>Arun</firstname>
<lastname>Prasath</lastname>
<age>5</age>
<photo>/NewExample;component/Images/icon_man.png</photo>
</student>
<student>
<firstname>Satheesh</firstname>
<lastname>Kumar</lastname>
<age>27</age>
</student>
</school>
Here I want to check <photo> tag is available or not.
I have try like this.
var school= from ack in xdoc.Descendants("school")
select ack;
for(int i =0;i<school.count();i++)
{
if(school.ElementAt(i).Element("photo").Name.LocalName.Equals("photo"));
Console.WriteLine("Tag is available in==>"+i);
else
Console.WriteLine("Tag is Not available in==>"+i);
}
It is working. But when I use this same in another example with diff elements it showing error.
Please let me know any other effective way to search the Tags in c#.
Thanks in advance.

Get all students. Then try to retrieve photo element from student element. If it is equal to null then photo no exist in current student:
var students = xdoc.Root.Elements("student");
int i = 1;
string format = "Tag is {0}available in {1}";
foreach(var student in students)
Console.WriteLine(format, student.Element("photo") == null ? "not " : "",i++);
Output:
Tag is available in 1
Tag is available in 2
Tag is not available in 3
You can write extension to make code more readable
public static bool HasElement(this XElement parent, XName name)
{
return parent.Element(name) != null;
}
E.g. selecting all students which have photo will look like
from student in xdoc.Root.Elements("student")
where student.HasElement("photo")
select student
You also can use XPath for same task
xdoc.XPathSelectElements("school/student[photo]")

Related

How to access element in XML files with attribute values?

This is my XML file
<colleges>
<college college_name="DYPSOE">
<departments>
<department department_name="Computer" id="10">
<![CDATA[I NEED TO CHANGE THIS COMMENT!]]>
</department>
<department department_name="Machanical" id="20">
<![CDATA[I NEED TO CHANGE THIS COMMENT!]]>
</department>
</departments>
</college>
<college college_name="DYPSOET">
<departments>
<department department_name="Computer" id="10">
<![CDATA[I NEED TO CHANGE THIS COMMENT!]]>
</department>
<department department_name="Machanical" id="20">
<![CDATA[I NEED TO CHANGE THIS COMMENT!]]>
</department>
</departments>
</college>
</colleges>
I have three attribute values as college_name, department_name and id available in the program. So I want to go to the particular "Department" node and change the value in the comments with these three attribute values.
I'am trying to reach the node with different queries, failed so far.
var node = from e in doc.Descendants("college")
where e.Attribute("college_name").ToString() == college_name
select (XElement)e.Elements("department");
foreach (XElement data in node)
{
Console.WriteLine(data); //Just to look what I got
data.Value = ""; //To change the comment section
}
This is not working at all. If you guys could suggest me the query it would help me a lot.
Presuming you want to select a single department element based on college and department names, you can find it using a query like this one:
var query = from college in doc.Descendants("college")
where (string) college.Attribute("college_name") == "DYPSOE"
from department in college.Descendants("department")
where (string) department.Attribute("department_name") == "Computer"
select department;
var element = query.Single();
You can then replace the comment like this:
element.ReplaceNodes(new XCData("new comment"));
I think you can use System.Xml.XmlReader to read the nodes' attribute and write it with System.Xml.XmlWriter
How to: Parse XML with XmlReader has the example of parsing and writing.

Reading special field from variable XML File c#

I have got a file called xmlfile.xml:
<Personen>
<Person>
<Vorname>Manfred</Vorname>
<Telefon/>
<Zuname>Fischer</Zuname>
<Alter>45</Alter>
<Adresse Ort="Bonn" Strasse="Neuestr.34"></Adresse>
</Person>
</Personen>
There are two problems. First of all are the fields of '' variable. So maybe the xmlfile contains 3 persons or another value (of course it contains at least one). Now I need to print out the 'Vorname' of each Person, how can I do so? I tried this code (just a short view):
reader.ReadToFollowing("Person");
string isbn = reader.GetAttribute("Alter");
Console.WriteLine("age: " + isbn);
Console.ReadLine();
But it doesn't print out the age (Alter), how to get it working to print out the age of each person, in case there are more then one.
Just do a quick search and you'll find plenty of resource to read XML via fabulous Linq:
LINQ to read XML
For example to extract persons:
XDocument xdoc = XDocument.Load(yourFileName));
var persons = from lv1 in xdoc.Descendants("Person")
select lv1.Value;

How to modify XML file in c#?

<Customers>
<Customer1>
<Name>Bobby</Name>
<Age>21</Age>
<Address>Panjim</Address>
</Customer1>
<Customer2>
<Name>Peter</Name>
<Age>32</Age>
<Address>Panjim</Address>
</Customer2>
<Customer4>
<Name>Joel</Name>
<Age>32</Age>
<Address>Mapusa</Address>
</Customer4>
</Customers>
So the thing is I want to delete a particular element and when i delete the first element i.e customer1, I want to update the other elements. I mean I want to make customer3, customer2 and customer2, customer1.
Can anyone please help me achieve this?
What about:
class Program {
static void Main(string[ ] args) {
XDocument doc = XDocument.Load("D:\\file.xml"); //example file
doc.Root.SwitchAndRemove("Customer1");
doc.Save("D:\\file.xml");
}
}
public static class Utilities {
public static void SwitchAndRemove(this XElement customers, XName name) {
var x = customers.Descendants().Where(e => e.Name == name).Select((element, index) => new { element, index }).Single();
int count = 0;
XElement temp = x.element;
foreach (XElement el in customers.Nodes()) {
if (count == x.index + 1) {
temp.RemoveAll();
temp.Add(el.Descendants().ToArray());
temp = el;
}
else
count++;
}
temp.Remove();
}
}
By giving as input your xml the output is the following:
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer1>
<Name>Peter</Name>
<Age>32</Age>
<Address>Panjim</Address>
</Customer1>
<Customer2>
<Name>Joel</Name>
<Age>32</Age>
<Address>Mapusa</Address>
</Customer2>
</Customers>
I'd argue that your problem is not how you could rename your nodes with minimum effort but structure of your XML file.
You said order of customers is not important and apparently customer tag's number is not important, either, since you want to rename the tags upon deletion.
So maybe this structure just creates unnecessary complexity and extra work for you.
Only reason I see you could need the number in tag is to identify the node you are about to remove. Am I right or is there something more to it? If not then you could add random unique identifier (like Guid) to your customer data to remove the right one.
Could save you lot of trouble.
<customers>
<customer>
<guid>07fb-877c-...</guid>
<name>Notch</name>
<age>34</age>
<address>street</address>
</customer>
<customer>
<guid>1435-435a-...</guid>
<name>Sam</name>
<age>23</age>
<address>other</address>
</customer>
<customers>
Say the element you have to delete is Customer1, first of all you can read the complete xml file using one of the XML parsing classes available in c# like XDocument or XmlReader and write to another xml file say "Temp.xml" skipping the Customer1 element completely. This way we have achieved the deletion part.
Next to update, forget the file being XML file and read the entire file to a string, say "xmlstring". Now use the Replace function available with a string data type to replace "Customer2" with "Customer1" and then "Customer3" with "Customer2" and so on.
And now delete your original XML file and write the string "xmlstring" using a stream writer to a file name "YourFileName.xml"
Thats it. Hope this solution works for you. Try this and in case u are unable get this done, share the code which u tried and we shall suggest how to work it out.
taken from your comment that the order does not have to be preserved then you can do this
public static void RemoveCustomer(XElement customers, XElement removeThis){
var last = customeers.Elements().Last();
if(last != removeThis){
foreach(var element in removeThis.Elements()){
element.Value = last.Element(element.Name).Value;
}
}
last.Remove();
}
It effectively substitutes the one to be removed with the last (unless the last should be removed) and thereby eliminates the need for renaming any of the other elements

Unable to extract value from XDocument using xpath

I have a simple xml of users. I have a StudentId, I just need to get the student name from the xml on the basis of studentid. Seems to be simple but I am unable to get it done using xpath.
Here's the xml:
<Students>
<Student>
<StudentId>1</StudentId>
<StudentName>Mad</StudentName>
</Student>
<Student>
<StudentId>2</StudentId>
<StudentName>Cad</StudentName>
</Student>
</Students>
Here's my code:
XDocument xmldoc = XDocument.Load(Server.MapPath("~/xmlsample.xml"));
string StudentId = "2"; // id to be selected
var username = xmldoc.XPathSelectElement("Students/Student/StudentName").Value;// Not sure how to use where condition here
You just need to filter by studentId. Should be:
var username = xmldoc.XPathSelectElement(String.Format("Students/Student[StudentId={0}]/StudentName", StudentId)).Value;

XML XPath Question

My XML File looks like what is below, I am trying in my C Sharp code to have it only populate the combobox with questions based off of the name the course name that is selected. So for example if they select XML Programming in the course combobox, it will only display the questions for XML Programming in the question combobox. What would my XPath need to look like in order to accomplish this? Any help would be appreciated.
if (comboBoxCourse.SelectedItem.ToString() == selectNode.InnerText )
{
try
{
XmlNodeList loadQuestions = loadDoc.SelectNodes("//Course/Questions");
foreach (XmlNode xml in loadQuestions)
{
if (comboBoxCourse.SelectedItem.ToString() == selectNode.InnerText)
comboBoxQuestions.Items.Add(xml.InnerText);
else
continue;
}
}
catch (XmlException ex)
{
MessageBox.Show(ex.ToString());
}
}
<?xml version="1.0" encoding="utf-8" ?>
<Courses>
<Course>
<Name>Direct X Programming</Name>
<Professor>Michael Feeney</Professor>
<Questions>Are you a Ninja</Questions>
<Questions>What version of Direct X do we use?</Questions>
</Course>
<Course>
<Name>XML Programming</Name>
<Professor>Michael Feeney</Professor>
<Questions>Are you an XML Ninja?</Questions>
<Questions>What does XML stand for?</Questions>
</Course>
<Course>
<Name>Windows GUI</Name>
<Professor>Leanne Wong</Professor>
<Questions>What is a treeview?</Questions>
<Questions>What is a database?</Questions>
</Course>
</Courses>
I would use LINQ to XML instead:
doc.Root.Elements()
.Where(c => c.Element("Name").Value == "Windows GUI")
.Elements("Questions")
But if you really want to use XPath, it would look something like this:
/Courses/Course[Name = 'Windows GUI']/Questions
Be careful when constructing the query though, because you have to do some escaping of the string from the user.
This will select and display in the output window all the questions associated with the selected course:
string xpath = string.Format("//Course[Name = '{0}']/Questions", comboBoxCourse.SelectedItem);
foreach (XmlNode node in loadDoc.SelectNodes(xpath))
Debug.WriteLine(node.InnerText);
To load another combobox from those results I'd replace your entire method with this:
string xpath = string.Format("//Course[Name = '{0}']/Questions", comboBoxCourse.SelectedItem);
foreach (XmlNode node in loadDoc.SelectNodes(xpath))
comboBoxQuestions.Items.Add(xml.InnerText);
Use this XPath expression:
/*/*[Name = 'XML Programming']/Questions
This selects any Questions element that is a child of any element that is a child of the top element and that has a child named Name whose string value is 'XML Programming'

Categories