Create loops and parsing XML nodes value for Selenium tests - c#

I am trying to write a test function in C# that read data from an XML file and parse into Selenium testing methods , the XML code is like:
<home>
<ask_frame>
<button>
<id>Object ID<id>
<xpath>Object XPath<xpath>
<textbox>
<id>Object ID<id>
<xpath>Object XPath<xpath>
</ask_frame>
<search_frame>
<id>Object ID<id>
<xpath>Object XPath<xpath>
</search_frame>
<home>
I am trying to create a loop that read the id and xpath value from these nodes and parse them into an method for searching a webpage element by id and xpath. My initial attempt was:
Code updated
public void CheckIdTest()
{
driver.Navigate().GoToUrl(baseURL + "FlightSearch");
XmlDocument xd = new XmlDocument();
xd.Load(#"C:\XMLFile1.xml");
XmlNodeList mainlist = xd.SelectNodes("//home/*");
XmlNode mainroot = mainlist[0];
foreach (XmlNode xnode in mainroot)
{
string objID = xnode.SelectSingleNode("id").InnerText;
string objXPath = xnode.SelectSingleNode("XPath").InnerText;
objID = objID.Trim();
objXPath = objXPath.Trim();
String checkValue = "ObjID value is: " + objID + Environment.NewLine+ "ObjXPath value is: " + objXPath;
System.IO.File.WriteAllText(#"C:\checkvalue.txt", checkValue);
objectCheck(objXPath, objID);
}
}
I have put a String and checked that correct values for ObjID and ObjXPath have been achieved, but this loop also went only twice (checked 2 nodes in first branch). How could I make it runs through every node in my XML?
Any suggestions and explanations to the code will be highly appreciated.

Basically these two lines are using incorrect XPath :
XmlNodeList idlist = xd.SelectNodes("id");
XmlNodeList xpathlist = xd.SelectNodes("XPath");
<id> and <xpath> nodes aren't located directly at the root level, so you can't access it just like above. Besides, xpath is case-sensitive so you should've used "xpath" instead of "XPath". Try to fix it like this :
XmlNodeList idlist = xd.SelectNodes("//id");
XmlNodeList xpathlist = xd.SelectNodes("//xpath");
or more verbose :
XmlNodeList idlist = xd.SelectNodes("home/*/id");
XmlNodeList xpathlist = xd.SelectNodes("home/*/xpath");
UPDATE :
Responding to your comment about looping problem, I think you want to change it like this :
foreach (XmlNode xnode in mainroot.ChildNodes)
{
string objID = xnode.SelectSingleNode("id").InnerText;
string objXPath = pathroot.SelectSingleNode("xpath").InnerText;
objectCheck(objID, objXPath);
}

You are getting this error because you are trying to use an object that is null i.e not instantiated.
Put in a breakpoint at the line
XmlDocument xd = new XmlDocument();
and step through line by line till you find where the nothing.null reference is.
It should not take long to find out what the problem is.

Related

Unable to get values from xml nodes

I am trying to parse through xml and get some values and have tried multiple approaches but i am unable to get the values.
this is what i have tried so far
string fileName = #"C:\Users\one\OneDrive\Desktop\PP\SnippetWithImage.idms";
string xmlString = System.IO.File.ReadAllText(fileName);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fileName);
XmlNodeList spreadNodes = xmlDoc.GetElementsByTagName("spread");
foreach (XmlNode spreadNode in spreadNodes)
{
var linkNodes = spreadNode.SelectNodes("//rectangle/image/link");
foreach (XmlNode linkNode in linkNodes)
{
Console.WriteLine("path : " + linkNode.SelectSingleNode("LinkResourceURI").InnerText);
}
}
Here spreadNodes count is always 0.
I have tried this with XElements as well and used Decendents but sill the same result.
Here is the xml structure https://codebeautify.org/xmlviewer/y22db1f26
the file which i am loading is an InDesign Snippet file. I am trying to get the linkResourceURI property value from links which is a child of image which is a child of rectangle which is a child of spread.
Some quick debugging shows that spreadNodes is empty, to start with. The most obvious cause is that the element name is Spread not spread, and if we make this change, we see spreadNodes has one element.
Next, it's obvious that spreadNode.SelectNodes("//rectangle/image/link") isn't returning anything. Again, that's probably capitalisation: change it to //Rectangle/Image/Link, and we get a NullReferenceException. Progress, at least.
We're getting that exception because linkNode.SelectSingleNode("LinkResourceURI") is returning null. It turns out that's because LinkResourceURI is an attribute, and you're looking for an element. Change that to linkNode.Attributes["LinkResourceURI"].InnerText, and everything works as expected.
XmlNodeList spreadNodes = xmlDoc.GetElementsByTagName("Spread");
foreach (XmlNode spreadNode in spreadNodes)
{
var linkNodes = spreadNode.SelectNodes("//Rectangle/Image/Link");
foreach (XmlNode linkNode in linkNodes)
{
Console.WriteLine("path : " + linkNode.Attributes["LinkResourceURI"].InnerText);
}
}

I'm unable to extract the Data from this XML

I'm currently working on a small weather application in C#. To do this, I need to extract data from this xml file: http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.places%20where%20text%3D%22london%22&format=xml
In this specific case I need the value of the first /query/results/place/woeid node. I've been looking around and tried many different methods, but didn't manage to get any values with any of those. My current code looks like this:
string query = String.Format("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.places%20where%20text%3D%22london%22&format=xml");
XmlDocument xml = new XmlDocument();
xml.Load(query);
XmlNodeList nodeList = wData.DocumentElement.SelectNodes("/query/results/place");
foreach (XmlNode node in nodeList)
{
return node.SelectSingleNode("woeid").InnerText;
}
return "NO WOEID FOUND!";
I'm just starting to learn C# so I might do some stupid mistakes. Still, I would really appreciate any kind of help.
You can use XDocument
string query = String.Format("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.places%20where%20text%3D%22london%22&format=xml");
XDocument xml = XDocument.Load(query);
XNamespace ns = "http://where.yahooapis.com/v1/schema.rng";
var woeid = xml.Element("query").Element("results").Elements(ns + "place").FirstOrDefault().Element(ns +"woeid").Value;
Make sure you check if there are any elements in the XDocuments

Read XML Attribute using C#

<Block ID="Ar0010100" BOX="185 211 825 278" ELEMENT_TYPE="h1" SEQ_NO="0" />
This is an example from my XML code. In C# I need to store ONLY ID'S inside of a block element in one variable, and ONLY Box's inside of a block element. I have been trying to do this for two days, and I don't know how to narrow down my question.
XmlNodeList idList = doc.SelectNodes("/Block/ID");
doesn't work... Any version of doc.selectnode, doc.GetElementBy... doesn't return the right element/children/whatever you call it. I'm not able to find documentation that tells me what I'm trying to reference. i don't know if ID or BOX are children, if they're attributes or what. This is my first time using XML, and I can't seem to narrow down my problem.
You can simply use following code
XmlNodeList elemList = doc.GetElementsByTagName("Your Element");
for (int i = 0; i < elemList.Count; i++)
{
string attrVal = elemList[i].Attributes["ID"].Value;
}
Demo: https://dotnetfiddle.net/5PpNPk
the above code is taken from here Read XML Attribute using XmlDocument
The problem is that ID is actually neither child nor part.
It's a node's attribute. You can access it this way:
doc.SelectSingleNode("/Block").GetAttribute("ID")
// or
doc.SelectSingleNode("/Block").Attributes["ID"].Value
Of course, you can iterate through them:
foreach (XmlElement element in doc.SelectNodes("/Block"))
{
Console.WriteLine(element.GetAttribute("ID"));
}
You also can ensure that it contains ID attribute, so, you won't get NullReferenceException or other exception. Use the following XPath:
foreach (XmlElement element in doc.SelectNodes("/Block[#ID]"))
{
Console.WriteLine(element.GetAttribute("ID"));
}
Your attempted xpath tried to find <Block> element having child element <ID>. In xpath, you use # at the beginning of attribute name to reference an attribute, for example /Block/#ID.
Given a correct xpath expression as parameter, SelectNodes() and SelectSingleNode() are capable of returning attributes. Here is an example :
var xml = #"<Block ID=""Ar0010100"" BOX=""185 211 825 278"" ELEMENT_TYPE=""h1"" SEQ_NO=""0"" />";
var doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList idList = doc.SelectNodes("/Block/#ID");
foreach(XmlNode id in idList)
{
Console.WriteLine(id.Value);
}
Demo

Get certain xml node and save the value

Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);

NodeList.SelectSingleNode() syntax

Having problems getting NodeList.SelectSingleNode() to work properly.
My XML looks like this:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<inm:Results xmlns:inm="http://www.namespace.com/1.0">
<inm:Recordset setCount="18254">
<inm:Record setEntry="0">
<!-- snip -->
<inm:Image>fileName.jpg</inm:Image>
</inm:Record>
</inm:Recordset>
</inm:Results>
The data is a long series of <inm:Record> entries.
I open the doc and get create a NodeList object based on "inm:Record". This works great.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNodeList xRecord = xdoc.GetElementsByTagName("inm:Record");
I start looping through the NodeList using a for loop. Before I process a given entry, I want to check and see if the <inm:Image> is set. I thought it would be super easy just to do
string strImage = xRecord[i].SelectSingleNode("inm:Image").InnerText;
My thinking being, "For the XRecord that I'm on, go find the <inm:Image> value ...But this doesn't work as I get the exception saying that I need a XmlNameSpaceManager. So, I tried to set that up but could never get the syntax right.
Can someone show me how to use the correct XmlNameSpaceManager syntax in this case.
I've worked around the issue for now by looping through all of the childNodes for a given xRecord, and checking the tag once I loop around to it. I would like to check that value first to see if I need to loop over that <inm:Record> entry at all.
No need to loop through all the Record elements, just use XPath to specify the subset that you want:
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNamespaceManager manager = new XmlNamespaceManager(xdoc.NameTable);
manager.AddNamespace("inm", "http://www.inmagic.com/webpublisher/query");
XmlNodeList nodes = xdoc.SelectNodes("/inm:Results/inm:Recordset/inm:Record[inm:Image != '']", manager);
Using the LINQ to XML libraries, here's an example for retrieving that said node's value:
XDocument doc = XDocument.Load(openFileDialog1.FileName);
List<XElement> docElements = doc.Elements().ToList();
XElement results = docElements.Elements().Where(
ele => ele.Name.LocalName == "Results").First();
XElement firstRecord = results.Elements().Where(
ele => ele.Name.LocalName == "Record").First();
XElement recordImage = firstRecord .Elements().Where(
ele => ele.Name.LocalName == "Image").First();
string imageName = recordImage.Value;
Also, by the way, using Hungarian notation for a type-checked language is overkill. You don't need to prepend string variables with str when it will always be a string.
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
string strImage = xRecord[i].SelectSingleNode("inm:Image",nsMgr).InnerText;
Should do it.
Using this Xml library, you can get all the records that have an Image child element with this:
XElement root = XElement.Load(openFileDialog1.FileName);
XElement[] records = root.XPath("//Record[Image]").ToArray();
If you want to be sure that the Image child contains a value, it can be expressed like this:
XElement[] records = root.XPath("//Record[Image != '']").ToArray();

Categories

Resources