public string[] UnpackXML(string xml_string)
{
string response = xml_string;
string[] return_values = new string[6];
XmlDocument xml = new XmlDocument();
xml.LoadXml(response);
return_values[0] = xml.GetElementsByTagName("meas name=\"mt1\"")[0].InnerText.ToString();
return_values[1] = xml.GetElementsByTagName("meas name=\"mt2\"")[0].InnerText.ToString();
return_values[2] = xml.GetElementsByTagName("meas name=\"mt3\"")[0].InnerText.ToString();
return_values[3] = xml.GetElementsByTagName("meas name=\"mt4\"")[0].InnerText.ToString();
return_values[4] = xml.GetElementsByTagName("meas name=\"mt5\"")[0].InnerText.ToString();
return_values[5] = xml.GetElementsByTagName("meas name=\"mt6\"")[0].InnerText.ToString();
return return_values;
}
When running the above code, it fails with the given error code:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
In the first line where I try to give return_values[0] a new value:
return_values[0] = xml.GetElementsByTagName("meas name=\"mt1\"")[0].InnerText.ToString();
The input to the UnpackXML is just an API response given as an XML string. The XML document has the following format:
<response location='location1'>
<meas name='mt1'>14</meas>
<meas name='mt2'>23</meas>
<meas name='mt3'>65</meas>
<meas name='mt4'>31</meas>
<meas name='mt6'>32</meas>
</response>
Any ideas on how to fix this? I basically want to append specific fields from the XML file to an array. The XML attribute "name" exists with each line and has different values for the attribute. Is there a way to directly access the attribute values by giving the correct name = "nameValue", without looping through attributes and checking each specific value?
The .GetElementsByTagName() is not suitable for your scenario since you are querying with XPath but not only with tag name.
Instead, you should use .SelectNodes() or .SelectSingleNode().
return_values[0] = xml.SelectNodes("//meas[#name=\"mt1\"]")[0]?.InnerText.ToString();
return_values[1] = xml.SelectNodes("//meas[#name=\"mt2\"]")[0]?.InnerText.ToString();
return_values[2] = xml.SelectNodes("//meas[#name=\"mt3\"]")[0]?.InnerText.ToString();
return_values[3] = xml.SelectNodes("//meas[#name=\"mt4\"]")[0]?.InnerText.ToString();
return_values[4] = xml.SelectNodes("//meas[#name=\"mt5\"]")[0]?.InnerText.ToString();
return_values[5] = xml.SelectNodes("//meas[#name=\"mt6\"]")[0]?.InnerText.ToString();
Or
xml.SelectSingleNode("//meas[#name=\"mt1\"]")?.InnerText.ToString();
Demo # .NET Fiddle
Also work with the null-conditional operator ?. to handle the returned node is possible null to prevent Null Reference Exception (NRE).
For your further question for dynamic way instead of hard code (assume 6 names you need to write the statements for 6 times), you may work with loop and LINQ to get the node's InnerText by matching the attribute value as below:
string[] return_values = new string[6];
string[] names = new string[6] { "mt1", "mt2", "mt3", "mt4", "mt5", "mt6" };
XmlDocument xml = new XmlDocument();
xml.LoadXml(response);
for (int i = 0; i < return_values.Count(); i++)
{
var node = xml.DocumentElement
.ChildNodes
.Cast<XmlNode>()
.FirstOrDefault(x => x.Attributes["name"].Value == names[i]);
return_values[i] = node?.InnerText.ToString();
}
Or
for (int i = 0; i < return_values.Count(); i++)
{
return_values[i] = xml.SelectSingleNode($"//meas[#name=\"{names[i]}\"]")?.InnerText.ToString();
}
Demo # .NET Fiddle
In case you have multiple entries for the response, it's recommended to load the return_values dynamically instead of writing every possible entry manually:
public string[] UnpackXML(string xml_string)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(xml_string);
var response_childrens = xml.SelectSingleNode("response").ChildNodes;
string[] return_values = new string[response_childrens.Count];
for (int i = 0; i < response_childrens.Count; i++)
{
return_values[i] = response_childrens[i].InnerText;
}
return return_values;
}
Related
I am trying to read and store data from an xml file. I have been reading about various methods to read the data such as XmlReader, XmlTextReader, LinQ, etc.
My XML file is
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<circuit name="local">
<Device>device1</Device>
<Point>point1></Point>
</circuit>
<circuit name ="remote">
<Device>device2</Device>
<Point>point2</Point>
</circuit>
</configuration>
I am trying to extract Device and Point set so I can pass those along to be used in a database query. I used this code and the foreach loop to verify the contents, but it only gets the first set.
XDocument msrDoc = XDocument.Load("BNOC MSR.config");
var data = from item in msrDoc.Descendants("circuit")
select new
{
device = item.Element("Device").Value,
point = item.Element("Point").Value
};
foreach (var p in data)
Console.WriteLine(p.ToString());
I have also tried this, but my arrays were all null
String[] deviceList = new String[1];
String[] pointList = new String[1];
int n = 0;
XmlDocument msrDoc = new XmlDocument();
msrDoc.Load("BNOC MSR.config");
var itemNodes = msrDoc.SelectNodes("circuit");
foreach (XmlNode node in itemNodes)
{
var circuit = node.SelectNodes("circuit");
foreach (XmlNode cir in circuit)
{
deviceList[n] = cir.SelectSingleNode("Device").InnerText;
pointList[n] = cir.SelectSingleNode("Point").InnerText;
}
}
Any help would be greatly appreciated.
Are you sure you don't want to use the built-in Properties.Settings for this?
Circuit local = Properties.Settings.Default.localCircuit;
Circuit remote = Properties.Settings.Default.remoteCircuit;
https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/using-application-settings-and-user-settings
I believe there is something wrong with the way you are testing the result. The code:
void Main()
{
var fileLocation = #"C:\BrianTemp\input.txt";
var xml = File.ReadAllText(fileLocation);
XDocument msrDoc = XDocument.Load(fileLocation);
var data = from item in msrDoc.Descendants("circuit")
select new
{
device = item.Element("Device").Value,
point = item.Element("Point").Value
};
foreach (var p in data)
{
//It is best practice to use statement blocks {} to prevent silly errors.
//Sometimes you want to execute multiple statements, especially as code changes later
Console.WriteLine($"{p}");
}
}
Produces the expected output:
{ device = device1, point = point1 }
{ device = device2, point = point2 }
You said:
I used this code and the foreach loop to verify the contents, but it
only gets the first set.
As you can see the code produces 2 results as it should.
Note: I corrected the XML file to remove the extra >
<Point>point1></Point><==
I see two problems in your code (and I only tried the second method you posted):
Your string arrays are too small, change to:
String[] deviceList = new String[1];
String[] pointList = new String[1];
The line var itemNodes = msrDoc.SelectNodes("circuit"); should be
var itemNodes = msrDoc.SelectNodes("configuration");
I am using C# in my project. I have a long XML file. I want to import all of them at once in a CSV file. I am trying this by writing the following code, But there is mismatch inside column. Next column value comes previously. Suddenly I noticed that for some attributes (For example Note), the text is written with semicolon instead of Comman and as a result this text set in three columns instead of one.
Example "Review VAT query; draft simple VAT agreement; review law and reply to queries".How can I ingore Semicolon of that properties.
Here is my code.
var output = new StringBuilder();
output.AppendLine("EmployeeId;EmployeeFirstName;EmployeeLastName;AllocationId;TaskId;TaskName;ProjectName;CustomerName;InvoiceAmount;WorkHours");
if (workUnit != null)
{
foreach (XmlNode customer in workUnit)
{
var unit = new WorkUnit();
var childNodes = customer.SelectNodes("./*");
if (childNodes != null)
{
for (int i = 0; i < childNodes.Count; ++i)
{
XmlNode childNode = childNodes[i];
output.Append(childNode.InnerText);
if (i < childNodes.Count - 1)
output.Append(";");
}
}
output.Append(Environment.NewLine);
}
Console.WriteLine(output.ToString());
File.AppendAllText("c:\\..WorkUnits.csv", output.ToString());
}
You could try to use the StringToCSVCell method defined by #Ed Bayiates here for to escape any semi-colon in the cell values:
escaping tricky string to CSV format
XmlNode childNode = childNodes[i];
output.Append(StringToCSVCell(childNode.InnerText));
if (i < childNodes.Count - 1)
output.Append(";");
I'm developing a web service that will receive a XML string and will compare with the internalName string. I'm using LINQ to parse the XML (and I think I'm doing it correctly) but I'm not sure how to compare the "value" withinternalName, per example.
[WebMethod]
public string WMCompare (string xml, string internalName)
{
XDocument xmlDoc = XDocument.Load(xml);
var result = from ele in xmlDoc.Descendants("property")
select new
{
key = (string)ele.Element("key"),
value = (string)ele.Element("value")
};
foreach (var i in result)
{
}
}
}
Thank you for your attention and I'm sorry about the newbie question. It's my first time working with XML.
Considering that you are comparing string with value:
var newResult = result.Where(r => r.value.Equals(internalName))
Alternatively, you may also compare while parsing your XML:
var result1 = from ele in doc.Descendants("property")
where ele.HasElements && ele.Element("value") != null && ele.Element("value").Equals(internalName)
select new
{
key = (string)ele.Element("key"),
value = (string)ele.Element("value")
};
I'm getting a text string from a website and parsing it into an XDocument. I'm looking to feed the value of certain elements into a very simple object (named NWSevent). My problem is that the original string changes and the XML tree varies; sometimes there are numerous events, up to 40, sometimes there is only one, and sometimes there is only one that does not have all the characteristics. If there are no alerts, then the "event" element has a title, but no areaDesc, summary, or severity.
I have two constructors for NWSevent, one takes in a single string, the other takes in four string arguments. I'm having trouble getting around a NullReferenceException. The if statement below can't do it because there is no value to compare. I'd appreciate any help.
public static void ParseWeatherData(String xmlString)
{
String ticker = string.Empty;
XDocument root = XDocument.Parse(xmlString);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
XNamespace nsCap = XNamespace.Get("urn:oasis:names:tc:emergency:cap:1.1");
//get list of entry elements, set conditions for title, areaDesc, etc
var xlist = root.Descendants(ns + "entry").Select(elem => new
{ //use first or default to deal with possiblity of null return
Title = elem.Descendants(ns + "title").FirstOrDefault(),
AreaDesc = elem.Descendants(nsCap + "areaDesc").FirstOrDefault(),
Severity = elem.Descendants(nsCap + "severity").FirstOrDefault(),
Summary = elem.Descendants(ns + "summary").FirstOrDefault()
});
foreach (var el in xlist) //need to address null values when no alerts
{
if (el.AreaDesc.Value != null) //causes yellow null ERROR; no value exists for el.areaDesc.value
{
String titleIn = el.Title.Value;
String areaIn = el.AreaDesc.Value;
String severityIn = el.Severity.Value;
String summaryIn = el.Summary.Value;
new Models.NWSevent(titleIn, areaIn, severityIn, summaryIn);
}
else
{
String titleIn = el.Title.Value;
new Models.NWSevent(titleIn);
}
}
Embarassing! Props to Dweeberly for pointing it out. I just need to change the if statement from
if (el.AreaDesc.Value != null){}
to if (el.AreaDesc != null){}
I have an XElement that looks like this:
<User ID="11" Name="Juan Diaz" LoginName="DN1\jdiaz" xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/" />
How can I use XML to extract the value of the LoginName attribute? I tried the following, but the q2 "Enumeration yielded no results".
var q2 = from node in el.Descendants("User")
let loginName = node.Attribute(ns + "LoginName")
select new { LoginName = (loginName != null) };
foreach (var node in q2)
{
Console.WriteLine("LoginName={0}", node.LoginName);
}
var xml = #"<User ID=""11""
Name=""Juan Diaz""
LoginName=""DN1\jdiaz""
xmlns=""http://schemas.microsoft.com/sharepoint/soap/directory/"" />";
var user = XElement.Parse(xml);
var login = user.Attribute("LoginName").Value; // "DN1\jdiaz"
XmlDocument doc = new XmlDocument();
doc.Load("myFile.xml"); //load your xml file
XmlNode user = doc.getElementByTagName("User"); //find node by tag name
string login = user.Attributes["LoginName"] != null ? user.Attributes["LoginName"].Value : "unknown login";
The last line of code, where it's setting the string login, the format looks like this...
var variable = condition ? A : B;
It's basically saying that if condition is true, variable equals A, otherwise variable equals B.
from the docs for XAttribute.Value:
If you are getting the value and the attribute might not exist, it is more convenient to use the explicit conversion operators, and assign the attribute to a nullable type such as string or Nullable<T> of Int32. If the attribute does not exist, then the nullable type is set to null.
I ended up using string manipulation to get the value, so I'll post that code, but I would still like to see an XML approach if there is one.
string strEl = el.ToString();
string[] words = strEl.Split(' ');
foreach (string word in words)
{
if (word.StartsWith("LoginName"))
{
strEl = word;
int first = strEl.IndexOf("\"");
int last = strEl.LastIndexOf("\"");
string str2 = strEl.Substring(first + 1, last - first - 1);
//str2 = "dn1\jdiaz"
}
}