I am trying to get XML values from the following XML node:
<StockQuotes>
<Stock>
<Symbol>LLOY.L</Symbol>
<Last>76.27</Last>
<Date>8/29/2014</Date>
</Stock>
</StockQuotes>
Here is my code:
XmlDocument quoteXML = new XmlDocument();
string strData = myXMLfile;
quoteXML.LoadXml(strData);
XmlNode nodes = quoteXML.SelectSingleNode("StockQuotes/Stock/Last/Date");
string strPrice = nodes["Last"].InnerText;
string strDate = nodes["Date"].InnerText;
Response.Write( strPrice + strDate );
I am getting the error:
Object reference not set to an instance of an object.
when I write the whole string strData to the view I get all of the XML so I know the file is valid.
SOURCE OF THE PROBLEM:
quoteXML.SelectSingleNode("StockQuotes/Stock/Last/Date"); SelectSingleNode call will return representation of <Date>8/29/2014</Date>,
But you try to access subnodes ["Last"] and ["Date"], that are not child nodes of <Date>8/29/2014</Date> and taking into account that indexer returns:
The first XmlElement that matches the specified name. It returns a
null reference (Nothing in Visual Basic) if there is no match.
nodes["Last"] and nodes["Base"] will be both null, resulting in NullReferenceException on .InnerText property access.
SOLUTION:
Use
XmlNode nodes = quoteXML.SelectSingleNode("StockQuotes/Stock");
to access Stock node instead.
The issue was with special charchters in the XML feed. I have resolved the issue and used:
'string strData = WebService.GetDate(); // returns xml as string
string decoded = WebUtility.HtmlDecode(strData); quoteXML.LoadXml(decoded);
XmlDocument xml = new XmlDocument();
xml.LoadXml(decoded);
XmlNodeList xnList = xml.SelectNodes("/StockQuotes/Stock");
foreach (XmlNode xn in xnList)
{
strQuote = xn["Last"].InnerText;
}'
Related
I need to get data SHILS_V from XML file. I read .xml
XML code for example:
<SVED_PR_GS>
<ZGLV>
<VERSION>99</VERSION>
<DATA>9999</DATA>
<FILENAME>1234</FILENAME>
<FIRSTNAME>1234</FIRSTNAME>
</ZGLV>
<SVD>
<CODE></CODE>
<YEAR></YEAR>
<MONTH></MONTH>
</SVD>
<SV_PR_GS>
<OBSV>
<N_ZAP>1</N_ZAP>
<MO_SV_V>12345</MO_SV_V>
<SNILS_V>123456789</SNILS_V>
</OBSV>
</SV_PR_GS>
</SVED_PR_GS>
My code to read xml:
XmlDocument xml = new XmlDocument();
xml.Load(filename);
Console.WriteLine("this");
XmlNodeList nodes = xml.GetElementsByTagName("SVED_PR_GS/SV_PR_GS");
foreach (XmlNode n in nodes)
{
Console.WriteLine("in loop");
XmlNode snils_v = n["OBSV/SNILS_V"];
Console.WriteLine("Snils V: " + snils_v);
}
Where is the problem?
How to get the information from SNILS_V?
GetElementsByTagName expects a tagname, not an XPath expression, "SV_PR_GS" will work there. And the same goes for the indexer of your XmlNode instance called n, this XPath will not work n["OBSV/SNILS_V"], use a tagname there as well but you have to handle the extra OBSV child there.
Here is your adapted code that produces output for me:
XmlNodeList nodes = xml.GetElementsByTagName("SV_PR_GS");
foreach (XmlNode n in nodes)
{
Console.WriteLine("in loop");
// first get the OBSV element
XmlNode obsv = n["OBSV"];
// now we can reach the other childs
XmlNode snils_v = obsv["SNILS_V"];
// Value will be null for XmlElement types, use InnerText instead
Console.WriteLine("Snils V: {0}" , snils_v.InnerText);
}
Notice that the Value property will return null for XmlNode that are of type XmlElement. In the XmlNode.Value documentation it is stated:
null. You can use the XmlElement.InnerText or XmlElement.InnerXml properties to access the value of the element node.
As your SNILS_V element seem to contain just a value InnerText is appropriate here.
To select a single node from XML. You need to access that object using SelectSingleNode method.
xml.SelectSingleNode("xpath for node")
To get collection of nodes you can write
xml.SelectNodes("xpath for node collection")
You should be able to get the value as follows:
XmlDocument xml = new XmlDocument();
xml.Load(filename);
Console.WriteLine("this");
XmlNodeList nodes = xml.GetElementsByTagName("OBSV");
foreach (XmlNode n in nodes)
{
Console.WriteLine("in loop");
XmlNode snils_v = n.SelectSingleNode("SNILS_V");
Console.WriteLine("Snils V: " + snils_v.InnerText);
}
I have a xml like this:
<xmlRootNode>
<levelOneChildNode>
Some text
<levelTwoChildNode>
<levelThreeChildNode>More text</levelThreeChildNode>
</levelTwoChildNode>
</levelOneChildNode>
</xmlRootNode>
I can't change the xml format because my client wants this format. How I should create and decorate "levelOneChildNode" class for a correct serialization? I can't use XmlElement or XmlAttribute. The only way to do this than I've thought is put "Some text" as a XmlElement and make a
string.replace("<textNode>", string.empty).replace("</textNode>", string.empty)
with de serialized xml to remove de tag but this is a crapy solution.
Any ideas without manual xml manipulation?
I guess you have two options, both of them related to manual xml-manipulation:
Use
XmlWriter
to write elements one by one.
Fill general-purpose
XmlDocument,
and save it.
Set/Retrieve/Append/Create XmlNotes (values):
//file name
string filename = #"d:\temp\XMLFile2.xml";
//create new instance of XmlDocument
XmlDocument _doc = new XmlDocument();
//load from file
_doc.Load(filename);
// Change text in xml
XmlNode node= _doc.SelectSingleNode("xmlRootNode/levelOneChildNode"); // [index of user node]
node.InnerText = value;
_doc.Save(#"path");
// Retrive value from xml
XmlNode node = _doc.SelectSingleNode("xmlRootNode/levelOneChildNode/levelTwoChildNode/someAttribute");
string value = node.InnerText;
// read or write to more elements
foreach (XmlNode node in doc.SelectNodes("xmlRootNode/levelOneChildNode/levelTwoChildNode"))
{
string data= node.SelectSingleNode("someAttribute").InnerTex; // get value of someAttribute.
node.InnerText = value;
}
// Append Note to levelOneChildNode Note
// Create second node
XmlNode secondNode = doc.CreateElement("SecondLevelNode");
secondNode .InnerText = "This title is created by code"
XmlNode firstNode= _doc.SelectSingleNode("xmlRootNode/levelOneChildNode");
firstNode.AppendChild(secondNode );
_doc.Save(#"path");
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.
I am creating XML document by reading some objects and adding them to proper place (inside xml tree structure). To be able to add it to proper place I need parent XmlNode so I could call parentNode.AppendChild(node);
How can I get XmlNode object if I know value of one of its attributes?
XmlDocument dom = new XmlDocument();
XmlNode parentNode = null;
XmlNode node = dom.CreateElement(item.Title); //item is object that I am writing to xml
XmlAttribute nodeTcmUri = dom.CreateAttribute("tcmUri");
nodeTcmUri.Value = item.Id.ToString();
node.Attributes.Append(nodeTcmUri);
parentNode = ??? - how to get XML node if I know its "tcmUri" attribute value (it is unique value, no other node has same "tcmUri" attribute value)
You can do this using SelectSingleNode function and xpath query as below
XmlNode parentNode = dom.SelectSingleNode("descendant::yournodename[#tcmUri='" + item.Id.ToString() + "']");
Where yournodename has to be replaced with the node name of the parent elements
Try this
XmlDocument doc = new XmlDocument();
doc.LoadXml(content);
XmlNodeList list = doc.SelectNodes("mynode");
foreach (XmlNode item in list)
{
if (item.Attributes["tcmUri"].Value == some_value)
{
// do what you want, item is the element you are looking for
}
}
Use following code:
var nodeList = doc.SelectNodes("<Node Name>[#tcmUri = \"<Value>\"]");
if(list.Count>0)
parentNode = list[0];
Replace <Node Name> with the node name which you want to make the parent node.
Replace the <Value> with the value of tcmUri attribute of the Node which you want to make the parent node.
XPath is your friend :
string xpath = String.Format("//parentTag[#tcmUri='{0}']", "tcmUriValueHere");
//or in case parent node name (parentTag) may varies
//you can use XPath wildcard:
//string xpath = String.Format("//*[#tcmUri='{0}']", "tcmUriValueHere");
parentNode = dom.SelectSingleNode(xpath)
I have a simple XML doc with no Namespace
Here is the code I wrote in C# to search for a particular element based on Name.
public XmlElement SearchXML(string name)
{
XmlDocument xDoc = new XmlDocument();
string filePath = ConfigurationManager.AppSettings["path"];
xDoc.Load(filePath);
string xQryStr = "//NewPatient[Name='" + name + "']";
xDoc.SelectNodes(xQryStr);
XmlElement xmlEle = xDoc.DocumentElement;
return xmlEle;
}
The XML document is as follows
When I try to call the method SearchXML and pass Dennis as the arguement, instead of returning the xml element containing only the specific elements, it returns the entire document.
Where am I possibly erring?
Any help appreciated.
xDoc.SelectNodes(xQryStr) does not mutate the original doc. You need to store the return value of this method call and return that instead.
ATM you're simply returning the root element of the original doc (i.e. the entire tree)
EDIT
In answer to your comment, you could fish the first matched XmlElement as follows:
xDoc.SelectNodes(xQryStr).OfType<XmlElement>().FirstOrDefault()
This will return either null or an XmlElement
If you want to select a list of nodes based on an XPath expression, you need to use .SelectNodes in this fashion:
public XmlElement SearchXML(string name)
{
XmlDocument xDoc = new XmlDocument();
string filePath = ConfigurationManager.AppSettings["path"];
xDoc.Load(filePath);
string xQryStr = "//NewPatient[Name='" + name + "']";
XmlNodeList listOfNodes = xDoc.SelectNodes(xQryStr);
foreach(XmlNode node in listOfNodes
{
// do something with that list of XML nodes you've selected....
// XmlElement xmlEle = node;
// return xmlEle;
}
}
The call to .SelectNodes(xpath) returns a list of matching XML nodes (see the MSDN documentation on XmlDocument.SelectNodes) - once you have that list, you can iterate over the matched nodes and do something with them....
Or if you're expecting only a single XML node to match your XPath expression, you can use .SelectSingleNode, too:
string xQryStr = "//NewPatient[Name='" + name + "']";
XmlNode matchedNode = xDoc.SelectSingleNode(xQryStr);
if(matchedNode != null)
{
// do something with that list of XML nodes you've selected....
return matchedNode;
}
can you change
string xQryStr = "//NewPatient[Name='" + name + "']";
to
xQryStr = "/NewPatient[Name='" + name + "']";
see the below link
http://www.csharp-examples.net/xml-nodes-by-name/