read only particular instance using xmlreader - c#

I have a xml file that looks like
<Name>AAA</Name>
<Age>23</Age>
<I1>
<Element1>A</Element1>
<Element2>B</Element2>
<Element3>C</Element3>
<\I1>
<I2>
<Element1>AA</Element1>
<Element2>BB</Element2>
<Element3>CC</Element3>
</I2>
I am reading all the values of elements using xmlreader in C# 3.0. But now i have to change by reading only the values within particular start and end tage. For the xml file mentioned above, i need to read <Name>, <Age> by default and then i have a function that returns the value "I1" or "I2" which is basically the element names. If it returns "I1" then i should read only the elements between <I1> and </I1> and should not read <I2> and vice versa. So the code structure would be (just the logic please ignore the syntax errors) like
/******function that returns element name I1 or I2*********/
string elementName = func(a,b);
xmlreader reader = reader.create("test.xml");
while(reader.read())
{
switch(reader.nodetype)
{
case xmlnodetype.element:
string nodeName = reader.name
break;
case xmlnodetype.text
switch(nodeName)
{
/*************Read default name and age values*******/
case "Name":
string personName = reader.value
break;
case "Age":
string personAge = reader.value;
break;
/*******End of reading default values**************/
/*** read only elements between the value returned by function name above
If function returns I1 then i need to read only values between <I1> </I1> else read </I2> and </I2>**/
}
}
}
Thanks!

So assuming, since we dont have any other tags to go off, that your file would look something such as this from beginning to end
<?xml version="1.0" encoding="utf-8" ?>
<RootElement>
<UserInformation>
<Name>AAA</Name>
<Age>23</Age>
<I1>
<Element1>A</Element1>
<Element2>B</Element2>
<Element3>C</Element3>
<\I1>
<I2>
<Element1>AA</Element1>
<Element2>BB</Element2>
<Element3>CC</Element3>
</I2>
</UserInformation>
</RootElement>
and then to call it
System.IO.StreamReader sr = new System.IO.StreamReader("test.xml");
String xmlText = sr.ReadToEnd();
sr.Close();
List<UserInfo> finalList = readXMLDoc(xmlText);
if(finalList != null)
{
//do something
}
private List<UserInfo> readXMLDoc(String fileText)
{
//create a list of Strings to hold our user information
List<UserInfo> userList = new List<UserInfo>();
try
{
//create a XmlDocument Object
XmlDocument xDoc = new XmlDocument();
//load the text of the file into the XmlDocument Object
xDoc.LoadXml(fileText);
//Create a XmlNode object to hold the root node of the XmlDocument
XmlNode rootNode = null;
//get the root element in the xml document
for (int i = 0; i < xDoc.ChildNodes.Count; i++)
{
//check to see if we hit the root element
if (xDoc.ChildNodes[i].Name == "RootElement")
{
//assign the root node
rootNode = xDoc.ChildNodes[i];
break;
}
}
//Loop through each of the child nodes of the root node
for (int j = 0; j < rootNode.ChildNodes.Count; j++)
{
//check for the UserInformation tag
if (rootNode.ChildNodes[j].Name == "UserInformation")
{
//assign the item node
XmlNode userNode = rootNode.ChildNodes[j];
//create userInfo object to hold results
UserInfo userInfo = new UserInfo();
//loop through each if the user tag's elements
foreach (XmlNode subNode in userNode.ChildNodes)
{
//check for the name tag
if (subNode.Name == "Name")
{
userInfo._name = subNode.InnerText;
}
//check for the age tag
if (subNode.Name == "Age")
{
userInfo._age = subNode.InnerText;
}
String tagToLookFor = "CallTheMethodThatReturnsTheCorrectTag";
//check for the tag
if (subNode.Name == tagToLookFor)
{
foreach (XmlNode elementNode in subNode.ChildNodes)
{
//check for the element1 tag
if (elementNode.Name == "Element1")
{
userInfo._element1 = elementNode.InnerText;
}
//check for the element2 tag
if (elementNode.Name == "Element2")
{
userInfo._element2 = elementNode.InnerText;
}
//check for the element3 tag
if (elementNode.Name == "Element3")
{
userInfo._element3 = elementNode.InnerText;
}
}
}
}
//add the userInfo to the list
userList.Add(userInfo);
}
}
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
//return the list
return userList;
}
//struct to hold information
struct UserInfo
{
public String _name;
public String _age;
public String _element1;
public String _element2;
public String _element3;
}

Related

C# xml reader, same element name

I'm trying to read an element from my xml file.
I need to read an string in an "link" element inside the "metadata",
but there are 2 elements called "link", I only need the second one:
<metadata>
<name>visit-2015-02-18.gpx</name>
<desc>February 18, 2015. Corn</desc>
<author>
<name>text</name>
<link href="http://snow.traceup.com/me?id=397760"/>
</author>
<link href="http://snow.traceup.com/stats/u?uId=397760&vId=1196854"/>
<keywords>Trace, text</keywords>
I need to read this line:
<link href="http://snow.traceup.com/stats/u?uId=397760&vId=1196854"/>
This is the working code for the first "link" tag, it works fine,
public string GetID(string path)
{
string id = "";
XmlReader reader = XmlReader.Create(path);
while (reader.Read())
{
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "link"))
{
if (reader.HasAttributes)
{
id = reader.GetAttribute("href");
MessageBox.Show(id + "= first id");
return id;
//id = reader.ReadElementContentAsString();
}
}
}
return id;
}
Does anyone know how I can skip the first "link" element?
or check if reader.ReadElementContentAsString() contains "Vid" or something like that?
I hope you can help me.
xpath is the answer :)
XmlReader reader = XmlReader.Create(path);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nodes = doc.SelectNodes("metadata/link");
foreach(XmlNode node in nodes)
Console.WriteLine(node.Attributes["href"].Value);
Use the String.Contains method to check if the string contains the desired substring, in this case vId:
public string GetID(string path)
{
XmlReader reader = XmlReader.Create(path);
while (reader.Read())
{
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "link"))
{
if (reader.HasAttributes)
{
var id = reader.GetAttribute("href");
if (id.Contains(#"&vId"))
{
MessageBox.Show(id + "= correct id");
return id;
}
}
}
return String.Empty;
}
If acceptable you can also use LINQ2XML:
var reader = XDocument.Load(path); // or XDocument.Parse(path);
// take the outer link
Console.WriteLine(reader.Root.Element("link").Attribute("href").Value);
The output is always:
http://snow.traceup.com/stats/u?uId=397760&vId=1196854= first id
Another options is to use XPath like #user5507337 suggested.
XDocument example:
var xml = XDocument.Load(path); //assuming path points to file
var nodes = xml.Root.Elements("link");
foreach(var node in nodes)
{
var href = node.Attribute("href").Value;
}

How can I get the value from XML return boolean value?

I want to make a funtion to input value (funName) and check XML file attribute (FunName) then output XML file attribute (isEnable) boolean true or false
How can I modify this code?
My XML file
<itema>
<itemb FunName="ABC" isEnable="true"></itemb>
<itemb FunName="DEF" isEnable="false"></itemb>
</itema>
My Code
public bool FunEnable(string funName , string isEnable)
{
bool result = true;
XmlDocument xDL = new XmlDocument();
xDL.Load("C://XMLFile2.xml"); //Load XML file
XmlNode xSingleNode = xDL.SelectSingleNode("//itemb");
XmlAttributeCollection xAT = xSingleNode.Attributes; //read all Node attribute
for (int i = 0; i < xAT.Count; i++)
{
if (xAT.Item(i).Name == "isEnable")
{
Console.WriteLine(xAT.Item(i).Value); //read we want attribute content
}
}
return result;
}
Thanks a lot
Well you can try this :
public static bool FunEnable(string funNam)
{
bool result = true;
XmlDocument xDL = new XmlDocument();
xDL.Load(#"C:/XMLFile2.xml"); //Load XML file
XmlNodeList nodeList = xDL.SelectNodes("//itemb");
foreach (XmlNode node in nodeList)
{
if (node.Attributes["FunName"].Value.Equals(funNam))
{
result = Convert.ToBoolean(node.Attributes["isEnable"].Value);
break;
}
}
Console.WriteLine("with funName = "+ funNam +" isEnable equal to : " + result);
return result;
}
Output
with funName = ABC isEnable equal to : True
This is fairly trivial using LINQ to XML. You can load the document using XDocument.Load and then get your isEnable value like so:
var result = doc.Descendants("itemb")
.Where(e => (string)e.Attribute("FunName") == "ABC")
.Select(e => (bool)e.Attribute("isEnable"))
.Single();
You can see a working demo here: https://dotnetfiddle.net/MYTOl6
var xDoc = XDocument.Load(path);
bool result = (from itemb in xDoc.Descendants("itemb")
where itemb.Attribute("FunName").Value == funcName
select itemb.Attribute("isEnable").Value == "true")
.FirstOrDefault();
Well, I prefer Linq to XML..
Maybe that one works:
public bool FunEnable(string funName, string isEnable)
{
bool result = true;
XDocument xDL = XDocument.Load("C://XMLFile2.xml");
var xSingleNode = from node in xDL.Descendants("itemb")
where node.Attribute("FunName").Value == funName
select node;
if(xSingleNode.Count() > 0)
{
result = xSingleNode.ElementAt(0).Attribute("isEnable").Value == "true";
//If there is at least one node with the given name, result is set to the first nodes "isEnable"-value
}
return result;
}

how to parse XML using XmlReader along with their closing tags?

Consider the following XML which I have to parse.
<root>
<item>
<itemId>001</itemId>
<itemName>test 1</itemName>
<description/>
</item>
</root>
I have to parse each of its tag and store it into a table as follows:
TAG_NAME TAG_VALUE IsContainer
------------ -------------- -----------
root null true
item null true
itemId 001 false
itemName test 1 false
description null false
/item null true
/root null true
Now to get this done, I am using XmlReader as this allows us to parse each & every node.
I am doing it as follows:
I created the following class to contain each tag's data
public class XmlTag
{
public string XML_TAG { get; set; }
public string XML_VALUE { get; set; }
public bool IsContainer { get; set; }
}
I am trying to get the list of tags(including closing ones) as follows:
private static List<XmlTag> ParseXml(string path)
{
var tags = new List<XmlTag>();
using (var reader = XmlReader.Create(path))
{
while (reader.Read())
{
var tag = new XmlTag();
bool shouldAdd = false;
switch (reader.NodeType)
{
case XmlNodeType.Element:
shouldAdd = true;
tag.XML_TAG = reader.Name;
//How do I get the VALUE of current reader?
//How do I determine if the current node contains children nodes to set IsContainer property of XmlTag object?
break;
case XmlNodeType.EndElement:
shouldAdd = true;
tag.XML_TAG = string.Format("/{0}", reader.Name);
tag.XML_VALUE = null;
//How do I determine if the current closing node belongs to a node which had children.. like ROOT or ITEM in above example?
break;
}
if(shouldAdd)
tags.Add(tag);
}
}
return tags;
}
but I am having difficulty determining the following:
How to determine if current ELEMENT contains children XML nodes? To set IsContainer property.
How to get the value of current node value if it is of type XmlNodeType.Element
Edit:
I have tried to use LINQ to XML as follows:
var xdoc = XDocument.Load(#"SampleItem.xml");
var tags = (from t in xdoc.Descendants()
select new XmlTag
{
XML_TAG = t.Name.ToString(),
ML_VALUE = t.HasElements ? null : t.Value,
IsContainer = t.HasElements
}).ToList();
This gives me the XML tags and their values but this does not give me ALL the tags including the closing ones. That's why I decided to try XmlReader. But If I have missed anything in LINQ to XML example, please correct me.
First of all, as noted by Jon Skeet in the comments you should probably consider using other tools, like XmlDocument possibly with LINQ to XML (EDIT: an example with XmlDocument follows).
Having said that, here is the simplest solution for what you have currently (note that it's not the cleanest possible code, and it doesn't have much validation):
private static List<XmlTag> ParseElement(XmlReader reader, XmlTag element)
{
var result = new List<XmlTag>() { element };
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
element.IsContainer = true;
var newTag = new XmlTag() { XML_TAG = reader.Name };
if (reader.IsEmptyElement)
{
result.Add(newTag);
}
else
{
result.AddRange(ParseElement(reader, newTag));
}
break;
case XmlNodeType.Text:
element.XML_VALUE = reader.Value;
break;
case XmlNodeType.EndElement:
if (reader.Name == element.XML_TAG)
{
result.Add(new XmlTag()
{
XML_TAG = string.Format("/{0}", reader.Name),
IsContainer = element.IsContainer
});
}
return result;
}
}
return result;
}
private static List<XmlTag> ParseXml(string path)
{
var result = new List<XmlTag>();
using (var reader = XmlReader.Create(path))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
result.AddRange(ParseElement(
reader,
new XmlTag() { XML_TAG = reader.Name }));
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
result.Add(new XmlTag()
{
XML_TAG = string.Format("/{0}",current.Name)
});
}
}
}
return result;
}
An example using XmlDocument. This will give slightly different result for self-enclosing tags (<description/> in your case). You can change this behaviour easily, depending on what you want.
private static IEnumerable<XmlTag> ProcessElement(XElement current)
{
if (current.HasElements)
{
yield return new XmlTag()
{
XML_TAG = current.Name.ToString(),
IsContainer = true
};
foreach (var tag in current
.Elements()
.SelectMany(e => ProcessElement(e)))
{
yield return tag;
}
yield return new XmlTag()
{
XML_TAG = string.Format("/{0}", current.Name.ToString()),
IsContainer = true
};
}
else
{
yield return new XmlTag()
{
XML_TAG = current.Name.ToString(),
XML_VALUE = current.Value
};
yield return new XmlTag()
{
XML_TAG = string.Format("/{0}",current.Name.ToString())
};
}
}
And using it:
var xdoc = XDocument.Load(#"test.xml");
var tags = ProcessElement(xdoc.Root).ToList();

Finding inner text value from XML file

When I write this code, I get only the parent tag value. I want to get their childnodes value also, please tell me about this.
XmlDocument DOC = new XmlDocument();
DOC.RemoveAll();
DOC.Load("C:\\Users\\DIGITEL EYE SYSTEM\\Desktop\\response.xml");
foreach (XmlNode AllNodes in ParentNode)
{
Project.Name = AllNodes["Name"].InnerText;
if (AllNodes.ChildNodes == DOC.GetElementsByTagName("AppBuilderForms"))
{
// Project.Forms = DOC.GetElementsByTagName("");
// String sb = AllNodes["Forms"].InnerText;
}
else if (AllNodes.ChildNodes==DOC.GetElementsByTagName("CheckMarkObject"))
{
checkmark.Name = AllNodes["Name"].InnerText;
checkmark.Label = AllNodes["Label"].InnerText;
// checkmark.IsChecked = AllNodes["IsChecked"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("DateTimeObject"))
{
DateTime.Name = AllNodes["Name"].InnerText;
DateTime.Label = AllNodes["Label"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("LocationObject"))
{
Location.Name = AllNodes["Name"].InnerText;
Location.Label = AllNodes["Label"].InnerText;
Location.Longitude = AllNodes["Longitude"].InnerText;
Location.Latitude = AllNodes["Latitude"].InnerText;
}
else if (ParentNode==DOC.GetElementsByTagName("SwitchObject"))
{
Switch.Name = AllNodes["Name"].InnerText;
Switch.Label = AllNodes["Label"].InnerText;
// Switch.IsChecked =AllNodes["IsChecked"].InnerText;
}
else if(ParentNode==DOC.GetElementsByTagName("TextViewObject"))
{
TextView.Name = AllNodes["Name"].InnerText;
TextView.Value = AllNodes["Value"].InnerText;
}
else if (ParentNode ==DOC.GetElementsByTagName("TextFieldObject"))
{
TextField.Name = AllNodes["Name"].InnerText;
TextField.Value = AllNodes["Value"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("PhotoPickerObject"))
{
PhotoPicker.Name = AllNodes["Name"].InnerText;
PhotoPicker.Label = AllNodes["Label"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("SpinWheelPickerObject"))
{
SpinWheelPicker.Name = AllNodes["Name"].InnerText;
SpinWheelPicker.Label = AllNodes["Label"].InnerText;
// SpinWheelPicker.Columns = AllNodes["Columns"].InnerText;
}
}
var xdoc = XDocument.Load(#"C:\Users\DIGITEL EYE SYSTEM\Desktop\response.xml");
var allElements = xdoc.Root.Elements();
foreach (string element in allElements)
{
//TODO add logic
}
First we'll load up the xml into a XDocument (needs .Net 3.5),
nothing odd going on here.
Second we'll select the root node and ALL
the elements under the root into a IEnumrable. You can add a filter here in the Elements() method.
Third we'll start iterating over the elements in our IEnumerable and implicitly
cast them to a string, this is a operator in the LINQ to XML lib
that just returns the XElement.Value (so if you think that's more
readable or need the whole Element for some other reason write
that! I.E XElement element in allElements)
Don't know how to do it in XmlDocument, I've totally forgotten, hopefully this might help you in case you'll go down that path (pun intended).

Count child nodes of node matching listbox item

Im having a problem here with selected index change. My xml file contains module number, module name, assesments, credits etc. What im trying to achieve here is - some course details are loaded into listbox from xml (module name and code) but when user selects a module, label should display how many assessments that module has.
Here is my XML file sample
<module>
<moduleCode>ECWM618</moduleCode>
<moduleTitle>Semantic and Social Web</moduleTitle>
<credits>15</credits>
<semester>2</semester>
<assessmentDetails>
<assessment>
<assessmentName>Coursework1</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>25</assessmentWeighting>
</assessment>
<assessment>
<assessmentName>Coursework2</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>25</assessmentWeighting>
</assessment>
<assessment>
<assessmentName>Exam</assessmentName>
<assessmentType>Exam</assessmentType>
<assessmentWeighting>50</assessmentWeighting>
</assessment>
</assessmentDetails>
</module>
And here is the code i got
private void moduleSummaryBox_SelectedIndexChanged(object sender, EventArgs e)
{
// when module from modulelist is selected, it read all indicies assigned to the module.
//!!!!!!!! it reads last node only :(? wtf im tired ...lol
//
// read data from modulelist
string path = Directory.GetCurrentDirectory();
FileStream fs = new FileStream(#"myCourse.xml", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
XmlReader moduleReader = XmlReader.Create(fs);
moduleReader.Read();
while (moduleReader.Read())
{
int assessmentNo = 0;
bool match = false;
moduleReader.MoveToElement();
if (moduleReader.Name == "assessmentName")
{
moduleReader.Read();// reads xml file.
XmlNodeType nType = moduleReader.NodeType; //XmlNodeType Specifies the type of node. If node matches specified name = true.
if (nType == XmlNodeType.Text)// if node type match XmlNodeType ( and there is some text in it) statement becomes true
{
this.assno.Text = (moduleReader.Value.ToString()); //set mcode label to matched node.
}
}
if (moduleReader.Value.ToString() == moduleSummaryBox.Items[moduleSummaryBox.SelectedIndex].ToString())
{
match = true;
}
if (match == true)
{
break;
}
}
}
Help appreciated thank you :)
EDIT:
This is what goes into listbox
moduleSummaryBox.Items.Clear();
XmlDocument doc = new XmlDocument();
doc.Load(#"myCourse.xml");
XmlNodeList levelList = doc.GetElementsByTagName("level"+l_level);
foreach (XmlNode node in levelList)
{
XmlElement moduleElement = (XmlElement)node;
XmlNodeList modules_individ = moduleElement.GetElementsByTagName("module");
foreach (XmlNode nodes in modules_individ)
{
XmlElement moduleSeperator = (XmlElement)nodes;
string ll_moduleCode = moduleSeperator.GetElementsByTagName("moduleCode")[0].InnerText;
string ll_moduleTitle = moduleSeperator.GetElementsByTagName("moduleTitle")[0].InnerText;
moduleSummaryBox.Items.Add(ll_moduleCode+" : " + ll_moduleTitle+" ");
}
}
Can you Try With the code sample below:-
const string xmlString =
"<module><moduleCode>ECWM618</moduleCode><moduleTitle>Semantic and Social Web</moduleTitle><credits>15</credits>" +
"<semester>2</semester><assessmentDetails><assessment><assessmentName>Coursework1</assessmentName><assessmentType>Coursework</assessmentType>" +
"<assessmentWeighting>25</assessmentWeighting></assessment><assessment><assessmentName>Coursework2</assessmentName><assessmentType>Coursework</assessmentType>" +
"<assessmentWeighting>25</assessmentWeighting></assessment><assessment><assessmentName>Exam</assessmentName><assessmentType>Exam</assessmentType><assessmentWeighting>50</assessmentWeighting></assessment></assessmentDetails></module>";
var xml = XElement.Parse(xmlString);
var qry =
xml.Descendants()
.Where(e => e.Name == "moduleCode" && e.Value == "ECWM618")
.Ancestors()
.Descendants()
.Where(e => e.Name == "assessmentDetails")
.Elements("assessment").Count();

Categories

Resources