I'm developing my first WPF application with C# but I have a problem when I'm trying to read a Xml attribute.
I have the following Xml:
<?xml version="1.0" encoding="utf-8"?>
<Dictionary EnglishName="Italian" CultureName="Italian" Culture="">
<!-- MainWindow -->
<Value ID="WpfApplication1.MainWindow.BtnDrawCircle" Content="Circonferenza"/>
<Value ID="WpfApplication1.MainWindow.BtnDrawLine" Content="Linea"/>
....
....
</Dictionary>`
Now I try to get the Attribute "Content" with the following method:
public static string ReadNodeAttribute(string IDAttribute)
{
try
{
XmlDocument _Doc = new XmlDocument();
_Doc.Load("myPath\\Language\\it-IT.xml");
string _Value = _Doc.SelectSingleNode("//Value[#ID=" + IDAttribute + "]").Attributes["Content"].Value.ToString();
return _Value;
}
catch (Exception ex)
{
return null;
}
}
But it doesn't work:
Error : ex {"Object reference not set to an instance of an object."} System.Exception {System.NullReferenceException}
You got
null reference exception
because you didn't check for null in case your IDAttribute doesn't exist in the XML.
Just change to your path and it will work.
using System;
using System.Linq;
using System.Xml.Linq;
public static string ReadNodeAttribute(string IDAttribute)
{
string _Value = "";
try
{
//I used System.IO.Path.GetFullPath because I tried it with ConsoleApplication.
//Use what ever work for you to load the xml.
XDocument xdoc = XDocument.Load(System.IO.Path.GetFullPath("XMLFile1.xml"));
var myValue = xdoc.Descendants("Value").FirstOrDefault(i => i.Attribute("ID").Value == IDAttribute);
if (myValue != null)
{
_Value = myValue.Attribute("Content").Value;
return _Value;
}
}
catch (Exception ex)
{
return null;
}
return _Value;
}
I have tried using Linq to Xml
XDocument xdoc = XDocument.Load(Server.MapPath("path"));
var val = xdoc.Descendants("Value").Where(i => i.Attribute("ID").Value == IDAttribute).FirstOrDefault().Attribute("Content").Value;
Inorder to use this you have to include System.Xml.Linq namespace
Related
I have a class that I deserialize with:
public static bool FileDeserializer<T>(string xmlFileName, out T element, out string strError)
{
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StreamReader(xmlFileName))
{ element = (T)xmlSerializer.Deserialize(reader); }
strError = string.Empty;
return true;
}
catch (Exception exc)
{
strError = "XmlFileDeserializer exception: " + exc;
element = default(T);
return false;
}
}
and serialize with
public static bool FileSerializer<T>(T value, string strFilename, out string strError)
{
try
{
var serializer = new XmlSerializer(typeof(T));
using (var xmlWriter = XmlWriter.Create(strFilename))
{ serializer.Serialize(xmlWriter, value); }
strError = string.Empty;
return true;
}
catch (Exception exc)
{
strError = "XmlFileSerializer exception: " + exc;
return false;
}
}
Now everything works fine with serialize/deserialize.
But when I try to read it to modify it:
with visual studio it's on a single line (so very hard to read)
with an other editor (xml explorer) i get the message:
The document does not have a specified schema. Click to apply one.
So I have searched for documentation but didn't understand how to put that in my code.
Thanks
---ADD---
Here is the xml in question sorry for not having added it before
<?xml version="1.0" encoding="utf-8"?><CfgData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><DialogFileIniDir>C:\temp</DialogFileIniDir><HorSplitterPos>204</HorSplitterPos><VerSplitterPos>358</VerSplitterPos><GridStep>10</GridStep><Scale>0</Scale><TraceThickness>3</TraceThickness><ShadowsEnabled>false</ShadowsEnabled><Theme>LIGHT</Theme><LightForeground><A>255</A><R>0</R><G>0</G><B>0</B><ScA>1</ScA><ScR>0</ScR><ScG>0</ScG><ScB>0</ScB></LightForeground><LightBackgound><A>255</A><R>245</R><G>245</G><B>245</B><ScA>1</ScA><ScR>0.913098633</ScR><ScG>0.913098633</ScG><ScB>0.913098633</ScB></LightBackgound><LightTraceOkColor><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></LightTraceOkColor><LightTraceCancelColor><A>255</A><R>255</R><G>0</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>0</ScG><ScB>1</ScB></LightTraceCancelColor><LightTraceEndColor><A>255</A><R>0</R><G>0</G><B>255</B><ScA>1</ScA><ScR>0</ScR><ScG>0</ScG><ScB>1</ScB></LightTraceEndColor><LightHeaderUnselectedBG><A>255</A><R>0</R><G>206</G><B>209</B><ScA>1</ScA><ScR>0</ScR><ScG>0.6172066</ScG><ScB>0.637596846</ScB></LightHeaderUnselectedBG><LightHeaderSelectedBG><A>255</A><R>0</R><G>0</G><B>255</B><ScA>1</ScA><ScR>0</ScR><ScG>0</ScG><ScB>1</ScB></LightHeaderSelectedBG><LightHeaderStartEndBG><A>255</A><R>105</R><G>105</G><B>105</B><ScA>1</ScA><ScR>0.141263291</ScR><ScG>0.141263291</ScG><ScB>0.141263291</ScB></LightHeaderStartEndBG><LightHeaderFG><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></LightHeaderFG><LightBlockBG><A>255</A><R>220</R><G>220</G><B>220</B><ScA>1</ScA><ScR>0.7156935</ScR><ScG>0.7156935</ScG><ScB>0.7156935</ScB></LightBlockBG><LightBlockFG><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></LightBlockFG><DarkForeground><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></DarkForeground><DarkBackgound><A>255</A><R>19</R><G>56</G><B>53</B><ScA>1</ScA><ScR>0.00651209056</ScR><ScG>0.0395462364</ScG><ScB>0.0356013142</ScB></DarkBackgound><DarkTraceOkColor><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></DarkTraceOkColor><DarkTraceCancelColor><A>255</A><R>255</R><G>0</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>0</ScG><ScB>1</ScB></DarkTraceCancelColor><DarkTraceEndColor><A>255</A><R>0</R><G>0</G><B>255</B><ScA>1</ScA><ScR>0</ScR><ScG>0</ScG><ScB>1</ScB></DarkTraceEndColor><DarkHeaderUnselectedBG><A>255</A><R>220</R><G>220</G><B>220</B><ScA>1</ScA><ScR>0.7156935</ScR><ScG>0.7156935</ScG><ScB>0.7156935</ScB></DarkHeaderUnselectedBG><DarkHeaderSelectedBG><A>255</A><R>0</R><G>0</G><B>255</B><ScA>1</ScA><ScR>0</ScR><ScG>0</ScG><ScB>1</ScB></DarkHeaderSelectedBG><DarkHeaderStartEndBG><A>255</A><R>105</R><G>105</G><B>105</B><ScA>1</ScA><ScR>0.141263291</ScR><ScG>0.141263291</ScG><ScB>0.141263291</ScB></DarkHeaderStartEndBG><DarkHeaderFG><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></DarkHeaderFG><DarkBlockBG><A>255</A><R>220</R><G>220</G><B>220</B><ScA>1</ScA><ScR>0.7156935</ScR><ScG>0.7156935</ScG><ScB>0.7156935</ScB></DarkBlockBG><DarkBlockFG><A>255</A><R>255</R><G>255</G><B>255</B><ScA>1</ScA><ScR>1</ScR><ScG>1</ScG><ScB>1</ScB></DarkBlockFG></CfgData>
my source like this in C#:
string xml = null;
WebRequest req = WebRequest.Create("https://www.freegeoip.net/xml");
req.Credentials = CredentialCache.DefaultCredentials;
WebResponse res = req.GetResponse();
Stream dataStream = res.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
xml = reader.ReadToEnd();
reader.Close();
res.Close();
am getting response like this :
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>
/// XMl Reponse END///////////////////////////////
I want pass parameters to Database like :
objLogDetails.IPAddress = ???? //Here i want to pass IP :162.158.50.10 from XMl string
HEre are two methods, one using xpath and the other using linq 2 xml:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace stackexchange
{
class Program
{
private static string theXml = #"<?xml version='1.0' encoding='UTF-8'?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>";
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(theXml);
XmlNode ip = xml.SelectSingleNode("/Response/IP");
Console.Out.WriteLine($"Ip Address: {ip.InnerText}");
XElement root = XElement.Parse(theXml);
XElement address = (from a in root.Descendants() where a.Name == "IP" select a).Single();
Console.Out.WriteLine($"Ip Address: {address.Value}");
}
}
}
What you can do here, is use an XElement to get items from the response and insert into your request.
You can do so like this:
//sets the node or remove
public static void SetOrRemoveNodeValue(XElement root, string xPath, string attributeName, string value)
{
XElement currentNode = root.XPathSelectElement(xPath);
if (currentNode != null)
{
if (currentNode.Attributes().FirstOrDefault(att => att.Name.LocalName.Equals(attributeName)) != null)
{
if (value == string.Empty)
{
currentNode.Attribute(attributeName).Remove();
}
else
{
currentNode.Attribute(attributeName).Value = value;
}
}
then use it like this:
Formatter.SetOrRemoveNodeValue("node", "your value type", "your value");
To extract value from the response, simply use:
currentNode.XPathSelectElement("//Response").Element("Ip").value;
Or simply
currentNode.XPathSelectElement("//Ip").value;
Trying This Code ..
private string mStrXMLStk = Application.StartupPath + "\\Path.xml";
private System.Xml.XmlDocument mXDoc = new XmlDocument();
mXDoc.Load(mStrXMLStk);
XmlNode XNode = mXDoc.SelectSingleNode("/Response");
if (XNode != null)
{
if (XNode != null)
{
int IntChildCount = XNode.ChildNodes.Count;
for (int IntI = 1; IntI <= 1; IntI++)
{
string LocalName = XNode.ChildNodes[IntI].LocalName;
XmlNode Node = mXDoc.SelectSingleNode("/Response/" + LocalName);
string _ip = Node.InnerText;
MessageBox.Show("IP" + _ip);
}
}
}
Completely worked
so I'm a total noob to C# is there any way to make this work?
It would also be a great help if someone could explain why my system doesn't work, and why another version would.
using System;
using System.Xml;
public class XMLManager
{
private XmlTextReader reader;
private XmlDocument document;
private XmlNodeList nodeList;
public void OpenFile(string file)
{
try
{
reader = new XmlTextReader(file);
reader.WhitespaceHandling = WhitespaceHandling.None;
reader.MoveToContent();
document = new XmlDocument();
document.Load(reader);
nodeList = document.SelectNodes(#"Settings/Settings");
}
catch (System.IO.FileNotFoundException)
{
}
}
public void CloseFile()
{
if (reader != null)
{
((IDisposable)reader).Dispose();
reader.Close();
reader = null;
}
document = null;
nodeList = null;
}
public string Get(string attrib)
{
for (int i = 0; i < nodeList.Count; i++)
{
reader.MoveToAttribute(i);
if (reader.Name == attrib)
{
return reader.Value;
}
}
return null;
}
}
Edit: Sorry for my bad formatting, this is my first time posting on Stack Overflow.
You are making multiple mistakes here.
First of all, you don't need a reader to read xml content into an XmlDocument.
Second, while trying to get the attributes, you are trying to proceed to the attributes using the reader which is obviously not having the context of the selected nodes.
Here is your updated XmlManager, but I have to note, there is a logical error too, which is, when the GetAttribute is invoked, you are searching all the Settings/Settings nodes and if find the attribute in any of them, return it. If the xml file contains only one Settings/Settings node, SelectSingleNode is better. I assume the following format:
<Settings>
<Settings attr1="attr1val" attr2="attr2val" />
</Settings>
Note: I also removed CloseFile method because it is no longer required.
public class XMLManager
{
private XmlDocument document;
private XmlNodeList nodeList;
public void OpenFile(string file)
{
document = new XmlDocument();
document.Load(file);
nodeList = document.SelectNodes(#"Settings/Settings");
}
public string Get(string attrib)
{
for (int i = 0; i < nodeList.Count; i++)
{
if (nodeList[i].Attributes[attrib] != null)
{
return nodeList[i].Attributes[attrib].Value;
}
}
return null;
}
}
Overall, you're doing way too much work.
If you have XML in a file, load it directly into an XML (DOM) object using XmlDocument.Load( strFileName );
To iterate all nodes matching an XPath query, see how I run through them.
try {
string strFileName = HttpContext.Current.Server.MapPath("\\data.xml");
XmlDocument xml = new XmlDocument();
xml.Load( strFileName );
foreach (XmlElement ndRow in xml.SelectNodes("//row")) {
string strTemp = ndRow.GetAttribute("foo");
}
} catch (Exception ex) {
Response.Write(ex.Message);
}
I am creating xml from c# code.I am gettign the following error:
Cannot insert the node in the specified location.
My code to do so is:
try {
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(docNode);
// XmlNode openerpNode = doc.CreateElement("open");
doc.AppendChild(openerpNode);
XmlElement dataNode = doc.CreateElement("dataex");
openerpNode.AppendChild(dataNode);
doc.PrependChild(colName.GenerateColumnsForTable("code", doc, dataNode)); //THIS LINE CAUSES ERROR AND THIS FUNCTON RETURNS A XmlNode TYPE OBJECT "dataNode"
//I use PrependChild here because i will call this function again passing another string in first parameter and it should attach the same xml
Console.WriteLine("string is : " + doc);
Console.ReadKey();
doc.Save("C:/cod.xml");
return true;
} catch (Exception ex) {
Console.WriteLine("The error is :" + ex);
Console.ReadKey();
return false;
}
public class ReturnColumnName
{
public XmlNode GenerateColumnsForTable(string tableName, XmlDocument doc, XmlNode dataNode)
{
//Here i am using the same doc and dataNode to create xml
return dataNode;
}
}
EDIT:
I changed the code from this
doc.PrependChild(colName.GenerateColumnsForTable("code_pays_iso", doc, dataNode));
to
XmlNode nod = colName.GenerateColumnsForTable("code_colisage", doc,dataNode);
doc.AppendChild(doc.OwnerDocument.ImportNode(nod, true));
Now it gives this error :
The error is :System.NullReferenceException: Object reference not set to an instance of an object.
Could some one please help me in finding the cause of error
You can't add a node to itself
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
ReturnColumnName colName = new ReturnColumnName();
string input = "<?xml version=\"1.0\"?><open></open>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(input);
XmlElement opener = (XmlElement)doc.GetElementsByTagName("open")[0];
XmlElement dataNode = doc.CreateElement("dataex");
XmlElement child = (XmlElement)colName.GenerateColumnsForTable("code", doc, dataNode);
if (opener.ChildNodes.Count == 0)
{
opener.AppendChild(child);
}
else
{
opener.PrependChild(child);
}
}
catch (Exception ex)
{
Console.WriteLine("The error is :" + ex);
Console.ReadKey();
}
}
public class ReturnColumnName
{
public XmlNode GenerateColumnsForTable(string tableName, XmlDocument doc, XmlNode dataNode)
{
//Here i am using the same doc and dataNode to create xml
return dataNode;
}
}
}
}
I am trying to read xml file with XmlTextReader class my xml file is
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<AppXmlLogWritter>
<LogData><LogID>999992013021213232800001</LogID><LogDateTime>20130212132328</LogDateTime><LogType>Message</LogType><LogFlag>Flag</LogFlag><LogApplication>Application</LogApplication><LogModule>Module</LogModule><LogLocation>Location</LogLocation><LogText>Text</LogText><LogStackTrace>Stacktrace</LogStackTrace></LogData>
</AppXmlLogWritter>
with the following code
FileStream fileStream = File.Open(txtBrowseFilePath.Text, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
using (XmlTextReader objXmlReader = new XmlTextReader(fileStream))
{
IEnumerable<LogData> data = LogData.GetLogData(objXmlReader);
using(var item = data.GetEnumerator())
{
while (item.MoveNext())
{
DataRow dataRow;
dataRow = dataTable.NewRow();
dataRow[0] = item.Current.LogID;
dataRow[1] = item.Current.LogDateTime;
dataRow[2] = item.Current.LogType;
dataRow[3] = item.Current.LogFlag;
dataRow[4] = item.Current.LogApplication;
dataRow[5] = item.Current.LogModule;
dataRow[6] = item.Current.LogLocation;
dataRow[7] = item.Current.LogText;
dataRow[8] = item.Current.LogStackTrace;
dataTable.Rows.Add(dataRow);
}
}}
public static IEnumerable<LogData> GetLogData(XmlTextReader objXmlReader)
{
LogData objLogData = null;
IXmlLineInfo xmlInfo = (IXmlLineInfo)objXmlReader;
while(objXmlReader.Read())
{
if(objXmlReader.IsStartElement("LogData"))
{
objLogData = new LogData();
}
if(objXmlReader.Name == "LogData" && objXmlReader.NodeType == XmlNodeType.EndElement)
{
yield return objLogData;
}
if(objXmlReader.Name == "LogID")
{
objLogData.LogID = objXmlReader.ReadElementContentAsString();
}
else if (objXmlReader.Name == "LogDateTime")
{
objLogData.LogDateTime = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogType")
{
objLogData.LogType = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogFlag")
{
objLogData.LogFlag = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogApplication")
{
objLogData.LogApplication = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogModule")
{
objLogData.LogModule = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogLocation")
{
objLogData.LogLocation = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogText")
{
objLogData.LogText = objXmlReader.ReadElementContentAsString();
}
else if(objXmlReader.Name == "LogStackTrace")
{
objLogData.LogStackTrace = objXmlReader.ReadElementContentAsString();
}
}
}
but it give me an error "The ReadElementContentAsString method is not supported on node type EndElement "
but when my xml file is as
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AppXmlLogWritter>
<LogData>
<LogID>999992013021110381000001</LogID>
<LogDateTime>20130211103810</LogDateTime>
<LogType>Message</LogType>
<LogFlag>Flag</LogFlag>
<LogApplication>Application</LogApplication>
<LogModule>Module</LogModule>
<LogLocation>Location</LogLocation>
<LogText>Text</LogText>
<LogStackTrace>Stacktrace</LogStackTrace>
</LogData>
</AppXmlLogWritter>
its work fine but i didnt get yet what actual problem with abouve xml file why it give me an error as i menstion. error occured at this line
objLogData.LogDateTime = objXmlReader.ReadElementContentAsString();
Thnkx for ur reply
Well, the main cause of the problem is that you're using ReadElementContentAsString which moves the "cursor" to after the element you're reading - but you're then calling Read() again.
So when the XML data is like this:
<first>Foo</first><second>Bar</second>
... if you're positioned on the first element opening, then ReadElementContentAsString will move the reader onto the start of the second element. You then call Read() which moves into the text node ("Bar"). When you then call ReadElementContentAsString a second time, that will fail - because you're not on an element start node. However, I'd expect to get an exception of:
Unhandled Exception: System.InvalidOperationException:
The ReadElementContentAsString method is not supported on node type Text.
... whereas you've got a node type of EndElement, for some reason.
You should dig into exactly why that's happening (did you call Read manually while debugging, for example?) but the underlying problem you need to fix is calling Read() when you don't need to.
You are using IXmlLineInfo and from the msdn page:
Provides an interface to enable a class to return line and position
information.
which may be the cause of this error. I guess nothing is returned using yield return (since it is never called) and using item.MoveNext() results in objXmlReader move to the last element of the xml which results in an exception.
Note that, this is just a guess based on the data you have provided.