Getting sibling using xPath - c#

I am currently working on a .net C# solution that returns 2 sibling nodes. Using Xpath 1.0
A small example of my xml doc is this:
<PLAY>
<SCENE>
<SPEAKER>
</SPEAKER>
<LINE>
</LINE>
</SCENE>
</PLAY>
I am using the following code to get the line and the speaker but i dont know why i get the entire xml doc being passed in instead of just the sibling (speaker)
I have :
List speakers = new List();
XmlDocument myDoc = new XmlDocument();
myDoc.Load(textXMLFile.Text.ToString());
// Clear the text box...
textResults.Text = "";
// ADD THIS...
XPathNavigator theNav = myDoc.CreateNavigator();
XPathNavigator theNav2 = myDoc.CreateNavigator();
//XmlNodeList theNodes =
// myDoc.SelectNodes(textXPath.Text.ToString());
textXPath.Text = "//SPEECH/LINE";
string val = "//SPEECH/SPEAKER";
XPathNodeIterator theNodes = theNav.Select(textXPath.Text.ToString());
XPathNodeIterator theNodes2 = theNav2.Select(val);
StringBuilder output = new StringBuilder();
while (theNodes.MoveNext())
{
if (theNodes.Current.InnerXml.ToString() == "Upon my sword.")
{
break;
}
else
{
speakers.Add(theNodes2.Current.InnerXml.ToString());
speakers.Add(theNodes2.Current.InnerXml.ToString());
}
}
for (int i =0; i < speakers.Count; ++i)
{
output.Append (speakers[i]+" ");
}
MessageBox.Show(""+output);
theNodes.Current.InnerXml.ToString() works fine for returning the line but theNodes2.Current.InnerXml.ToString() seems to return the entire XML instead of the speaker.
Any comments or suggestions are appreciated.

After staring at this for awhile i totally missed that i needed to move theNodes2 also in the while loop like so
while(theNodes2.MoveNext())
Thanks All

//SPEECH/LINE is not going to find anything in a document where the elements are named "play", "scene", "speaker", and "line". Please try to be more careful in formulating your questions. Downvoting.

Related

XML - Write a single node

I got this function for simply get the inner text of my xml:
XmlDocument document = new XmlDocument();
document.Load("game.xml");
string content = document.SelectSingleNode("Game/Client-Version").InnerText;
(this is the xml file (due to complications with stackoverflow posted on pastebin)): http://pastebin.com/EEeFAJpC
And now I am exactly looking for the function above, just to write. Like
document.WriteSingleNode("Game/Client-Version", "texttowrite");
I did not find anything helping me out.
This should work
XmlElement x = document.SelectSingleNode("Game/Client-Version") as XmlElement;
x.InnerText = "texttowrite";
Create your own extension method:
public void WriteSingleNode(this XmlDocument document, string NodeName, string InnerText)
{
// Create a new element node.
XmlNode newElem = document.CreateNode("element", "pages", "");
newElem.InnerText = InnerText;
Console.WriteLine("Add the new element to the document...");
document.DocumentElement.AppendChild(newElem);
Console.WriteLine("Display the modified XML document...");
Console.WriteLine(document.OuterXml);
}

Create loops and parsing XML nodes value for Selenium tests

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.

How do I get a specific value from xml in c#

My problem is a bit typical and I am very new to working with xml. Please view the following code:
XmlDocument xDoc = new XmlDocument();
xDoc.Load(myxml);
Response.Write("<p><strong>First Result</strong><br/>");
for (int nodeCount = 0; nodeCount < xDoc.ChildNodes.Count; nodeCount++)
{
Response.Write(xDoc.ChildNodes[nodeCount].Name + ":");
Response.Write(xDoc.ChildNodes[nodeCount].InnerXml + "<br/>");
}
Response.Write("</p>");
.. and the output I get in the aspx page is as follows:
First Result
xml:
Response:OK122.160.37.198ININDIAWEST BENGALKOLKATA70015522.569788.3697+05:30
I want the values 'WEST BENGAL' and 'KOLKATA' from it. I am not being able to read/write this in xml format so that I can grab the required nodes and their values. How to do that?
You can use XPath to search the XML. use your "xDoc" variable
XPathDocument doc = new XPathDocument(XmlReader(xDoc));
XPathNavigator nav = doc.CreateNavigator();
XPathExpression exprName = nav.Compile(xPathName);
XPathNodeIterator iteratorName = nav.Select(exprName)
You could use the Descendants() function on the XDocument itself, consider this example:
(Note - have made assumptions about how your data looks)
using System.Xml.Linq;
static void Main()
{
var xml = "<Data><ININDIA>WEST BENGAL</ININDIA><ININDIA>KOLKATA</ININDIA></Data>";
var xd = XDocument.Parse(xml);
//get all `XElement` objects with the name "ININDIA"
foreach (var e in xd.Root.Descendants()
.Where(e=>e.Name.LocalName=="ININDIA"))
{
Console.WriteLine(e.Value);
}
}
will produce
WEST BENGAL
KOLKATA

Read the XML with different elements in C#

I know, that there are a lot of question about parsing C#, but I couldn't find answer.
So, I need to write a DLL for parsing XML, but with some features, as I don't know what elements are in XML file. I need to parse all nodes of file and their elements. How can I do it? Now, I'm working with simple file
<reg>
<email_login>paykforcycvert#reincarnate.com</email_login>
<email_password>nDOUn3TybD</email_password>
</reg>
and my dll code now is
public XmlNodeList GetElementsName(string path)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);
XmlNodeList nodeList = xmlDoc.GetElementsByTagName("email_login");
return nodeList;
}
It should return "paykforcycvert#reincarnate.com".
My console app:
XMLWorker worker = new XMLWorker();
string path = "file:///D:/temp/test.xml";
XmlNodeList nodeList = worker.GetElementsName(path);
for (int i = 0; i < nodeList.Count; i++)
Console.WriteLine(nodeList[i].InnerText);
Console.ReadLine();
But it returns "paykforcycvert#reincarnate.comnDOUn3TybD"
How can I parse differently?
Use LINQ to XML:
XElement reg = XElement.Load(path);
string login = (string)reg.Element("email_login");
BTW your code works fine for me. Make sure you are not selecting all elements instead of email_login only. I.e. if you are getting child nodes XmlNodeList nodeList = xmlDoc.ChildNodes; instead of getting elements by tag name, then you will have your results.
Or possibly you have several elements named as email_login. E.g. following xml will produce your results with your code:
<reg>
<email_login>paykforcycvert#reincarnate.com</email_login>
<email_login>nDOUn3TybD</email_login>
</reg>
i ran the exact same code you gave and got paykforcycvert#reincarnate.com as output so my guess is that you haven't build your project after you fixed something or it wasn't cleaned.
try to clean the project and run it again
You can do it this way
public List<String> getElementValues(string path,string elementName)
{
XElement doc= XElement.Load(path);
var elementList=doc.Descendants().Elements();
return elementList.Where(x=>x.Name.LocalName==elementName)
.Select(y=>y.Value)
.ToList();
}
You can now get all the values of element with name email_login
var values=getElementValues(path,"email_login");
I ran following code after coping the XML data you provided in XMLFile.xml to emulate output:
class Program
{
static void Main(string[] args)
{
XMLWorker worker = new XMLWorker();
//
string path = #"C:\Users\abc\Desktop\ConsoleApplication1\ConsoleApplication1\XMLFile.xml";
XmlNodeList nodeList = worker.GetElementsName(path);
for (int i = 0; i < nodeList.Count; i++)
Console.WriteLine(nodeList[i].InnerText);
Console.ReadLine();
}
}
public class XMLWorker
{
public XmlNodeList GetElementsName(string path)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);
XmlNodeList nodeList = xmlDoc.GetElementsByTagName("email_login");
return nodeList;
}
}
But for me it is working fine.
You can also use XPath query:
XmlNodesList nodesList = xmlDoc.SelectNodes("//email_login"));
foreach(string oneNode in nodesList)
{
Console.Write(oneNode.InnerText);
}

Overwrite specific XML attributes

Let's say I have a file like this:
<outer>
<inner>
<nodex attr="value1">text</attr>
<nodex attr="value2">text</attr>
</inner>
</outer>
Basically what I want to do is, in C# (constrained to .net 2.0 here), this (pseudocode):
foreach node
if(node eq 'nodex')
update attr to newvalue
When complete, the xml file (on disk) should look like:
<outer>
<inner>
<nodex attr="newvalue1">text</attr>
<nodex attr="newvalue2">text</attr>
</inner>
</outer>
These two look marginally promising:
Overwrite a xml file value
Setting attributes in an XML document
But it's unclear whether or not they actually answer my question.
I've written this code in the meantime:
Here's a more minimal case which works:
public static void UpdateXML()
{
XmlDocument doc = new XmlDocument();
using (XmlReader reader = XmlReader.Create("XMLFile1.xml"))
{
doc.Load(reader);
XmlNodeList list = doc.GetElementsByTagName("nodex");
foreach (XmlNode node in list)
{
node.Attributes["attr"].Value = "newvalue";
}
}
using (XmlWriter writer = XmlWriter.Create("XMLFile1.xml"))
{
doc.Save(writer);
}
}
The fastest solution would be to use a loop with XmlTextReader/XmlTextWriter. That way you do not need to load the whole xml in memory.
In pseudocode:
while (reader.read)
{
if (reader.Node.Name == "nodex")
......
writer.write ...
}
You can check here for ideas.
Here is a sample script that can be run from LinqPad
var x = #"<outer>
<inner>
<nodex attr=""value1"">text</nodex>
<nodex attr=""value2"">text</nodex>
</inner>
</outer>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(x);
foreach (XmlNode n in doc.SelectNodes("//nodex"))
{
n.Attributes["attr"].Value = "new" + n.Attributes["attr"].Value.ToString();
}
doc.OuterXml.Dump();
As starting point you can show us what you have tried, you could use XPATH to select the nodes you want to modify, search for select node by attribute value in xpath.
After you have found the nodes you want to update you can reassign the attribute value as needed with a normal assignment.

Categories

Resources