I was asked today to look at a new project - reading in some XML and doing some analysis. I know a little C#. I have gotten this far with this code that so far works. I get the 4 node lists successfully. I have a couple problems. First I am not sure how to access what is in the tag on any of the nodes in any of the lists. Second, I'd prefer to be able to use LINQ queries but XmlNodeList doesn't seem to support that syntax. In the sample XML below, I'd like to be able to get all the vdisks that belong to a particular IO Group or mdisk as determined by io_group_name or mdisk_grp_name property. Most of what I looked at gave examples for accessing the [Attribute] list and searches all used properties/atttributes interchanged.
What I tried is also below, it gave a null value exception. The Attributes list only has one attribute. I can't find any examples to do what I want and it isn't clear from inspecting the node in the debugger what I need to access to do what I want.
//this works
XmlTextReader reader = new XmlTextReader(_InputFile);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList clusterlist = doc.SelectNodes("//object[#type='cluster']");
XmlNodeList controllerlist = doc.SelectNodes("//object[#type='controller']");
XmlNodeList mdisklist = doc.SelectNodes("//object[#type='mdisk']");
XmlNodeList vdisklist = doc.SelectNodes("//object[#type='vdisk']");
// this did not work - got null value exception
foreach (XmlNode vdisknode in vdisklist)
{
string str = vdisknode.Attributes["mdisk_grp_name"].Value;
}
A sample of the XML:
<object type="vdisk">
<property name="id" value="0" />
<property name="name" value="nim01_vd06_gmt" />
<property name="IO_group_id" value="0" />
<property name="IO_group_name" value="ossvc06_iogrp0" />
<property name="status" value="online" />
<property name="mdisk_grp_id" value="0" />
<property name="mdisk_grp_name" value="T1_OSIBM06_MDG1" />
<property name="capacity" value="644245094400" />
<property name="type" value="striped" />
</object>
object node has only one attribute: type
string type = vdiskNode.Attributes["type"].Value;
property node has two attributes: name and value:
string name = propertyNode.Attributes["name"].Value;
string value = propertyNode.Attributes["value"].Value;
What you need I deem is to extend the XPath query:
"//object[#type='vdisk']/property[#name='mdisk_grp_name']/#value"
Or use LINQ to XML:
from obj in doc.Load(xml).Root.Elements("object")
where (string)obj.Attribute("type") == "vdisk"
from prop in obj.Elements("property")
//where (string)prop.Attribute("name") == name
select prop.Value
Related
Am trying to add a new element called entity after the last entity but it keeps adding it inside the selected entity. To understand better this is my xml sample.
<Root>
<Class Name="ECMInstruction" Style="Top">
<Entity Id="1" Name="DocumentInformation" />
<Entity Id="2" Name="CustomerInformation" />
<Property Id="1" Name="DocumentTitle">
</Property>
<Property Id="2" Name="DateCreated">
<Lists>
<ListName>ws_Users</ListName>
<ListName>dfdfdfd</ListName>
</Lists>
</Property>
<Property Id="3" Name="Deadline">
</Property>
</Class>
</Root>
This is how it looks like after is inserted. I've tried using insertAfter but it gives me error.
<Entity Id="1" Name="DocumentInformation">
<Entity Id="2" Name="sds" />
</Entity>
The code:
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load("sample.xml");
XmlNodeList cnode = xmldoc.DocumentElement.SelectNodes("//Class[#Name='" + CurrentClass + "']/Entity");
foreach (XmlNode c in cnode)
{
int value = 0;
String entitycount = cnode.Count.ToString();
int.TryParse(entitycount, out value);
value = value + 1;
XmlElement root = xmldoc.CreateElement("Entity");
root.SetAttribute("Id", value.ToString());
root.SetAttribute("Name", EntityNametxt.Text);
c.AppendChild(root);
xmldoc.Save("sample.xml");
}
"I've tried using insertAfter but it gives me error. "
As per documentation, InsertAfter() should be called on parent node of referenced XmlNode (the 2nd argument of the method), otherwise ArgumentException will be thrown :
//instead of this : c.AppendChild(root);
//..you could do as follow :
c.ParentNode.InsertAfter(root, c);
I have this XML String :
<RESPONSE>
<SINGLE>
<KEY name="sitename">
<VALUE>Stackoverflow</VALUE>
</KEY>
<KEY name="username">
<VALUE>this value</VALUE>
</KEY>
</SINGLE>
</RESPONSE>
How to get value from Key that name "username" ? I want to get value of "this value" in my code. I try deserialized and any other code but it doesnt work. Please help me, thanks :D
Edit:
I tried using this code :
XDocument doc = XDocument.Load( "myXML.xml" );
var keys = doc.Descendants( "KEY" );
foreach ( var VALUE in keys )
{
Console.WriteLine( VALUE.Value );
}
But how did I get the Value only from KEY that named "Username" ? Thanks :))
You can probably use an xpath to do this. The following is an example XPath that will provide a node with name matching "sitename":
//KEY[#name="sitename"]
You can modify this slightly to find all nodes with a "name" attribute or to just find specific names. For more examples of how to use XPath see the MSDN site for XPath. The following is a snippet of C# code that shows you how to use this XPath (again, you can generalize for whatever XPath you need):
const string example_xml = "<RESPONSE> <SINGLE> <KEY name=\"sitename\"> <VALUE>Stackoverflow</VALUE> </KEY> <KEY name=\"username\"> <VALUE>this value</VALUE> </KEY> </SINGLE> </RESPONSE>";
// load
XmlDocument doc = new XmlDocument();
doc.LoadXml(example_xml);
// Query single or multiple nodes using the XPath, do what you want with this node!
var desiredNode = doc.SelectSingleNode("//KEY[#name=\"sitename\"]");
Best of luck!
For completeness here is a System.Xml.Linq version, with the foreachs and where's being System.Linq for good measure. This basically the questioner's attempt, with a where to filter according to attribute.
const string example_xml = "<RESPONSE> <SINGLE> <KEY name=\"sitename\"> <VALUE>Stackoverflow</VALUE> </KEY> <KEY name=\"username\"> <VALUE>this value</VALUE> </KEY> </SINGLE> </RESPONSE>";
XDocument doc = XDocument.Parse(example_xml);
var keys = doc.Descendants("KEY");
var userKeys = keys.Where(item => item.Attribute("name").Value == "username").ToList();
userKeys.ForEach(item => Console.WriteLine(item.Value));
Lets consider your xml document as XYZ.xml, then you may try below code if you are using C#, below is the example only
XmlDocument Doc = new XmlDocument();
Doc.Load(Server.MapPath(".../xyz.xml"));
XmlNodeList itemList = Doc.DocumentElement.SelectNodes("KEY");
foreach (XmlNode currNode in itemList)
{
string name = string.Empty;
XmlNode item = currNode.SelectSingleNode("KEY");
if(currNode["name"].InnerText == "username")//if you are aware of key name, use this condition
{
name = item.Attributes["name"].Value.ToString(); // or currNode["name"].InnerText;
}
}
got this document:
<uniprot xmlns="http://uniprot.org/uniprot" xmlns:xsi="http://www.w3.org/2001/ XMLSchema-instance" xsi:schemaLocation="http://uniprot.org/uniprot http://www.uniprot.org/support/docs/uniprot.xsd">
<entry dataset="Swiss-Prot" created="1986-07-21" modified="2013-10-16" version="88">
<dbReference type="GO" id="GO:0006412">
<property type="term" value="P:translation"/>
<property type="evidence" value="IEA:InterPro"/>
</dbReference>
<dbReference type="HAMAP" id="MF_00294">
<property type="entry name" value="Ribosomal_L33"/>
<property type="match status" value="1"/>
</dbReference>
<dbReference type="InterPro" id="IPR001705">
<property type="entry name" value="Ribosomal_L33"/>
</dbReference>
Right now, I'm using this to grab the inner text of nodes, which works fine...BUT...
XmlDocument XMLdoc = new XmlDocument();
XMLdoc.Load(Datapath);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(XMLdoc.NameTable);
nsmgr.AddNamespace("ns", "http://uniprot.org/uniprot");
String NodeName = XMLdoc.SelectSingleNode("//ns:fullName", nsmgr).InnerText;
... I need to grab the attributes of and whether type's content is GO or not and if so, get the following data of that exact node, namely id and value. Been thinking about and googling for this for several hours and I just lack the knowledge to get anywhere.
I'd suggest using Linq to Xml, I find it a lot easier than XmlDocument and XPath queries, but that is at least partially personal preference.
I'm not quite sure what you mean by the "value" of each element with a type of "GO", but this should get you most of the way there. goTypeNodes will contain a collection of those nodes that have a type of "GO" with their ID and type values, and additionally contains the property elements underneath them, so if by "value" you mean the value of the property elements underneath them, it is trivial to get at that from there.
XNamespace ns = "http://uniprot.org/uniprot";
XDocument doc = XDocument.Load(#"C:\SO\Foo.xml");
var goTypeNodes = from n in doc.Descendants(ns + "dbReference")
select new { Id = n.Attribute("id").Value, Type = n.Attribute("type").Value, Properties = n.Elements()};
By the way, your sample XML is missing closing tags for uniprot and entry.
Actually I managed to solve the problem:
XmlNodeList Testi = XMLdoc.SelectNodes("//ns:dbReference", nsmgr);
foreach (XmlNode xn in Testi)
{
if (xn.Attributes["type"].Value == "GO")
{
String Testilator = xn.Attributes["id"].Value;
String Testilator2 = xn.FirstChild.Attributes["value"].Value;
}
}
I am trying to load an XML file onto my GUI using a TreeView control.
However, I am using a proprietary layout for my XML file.
The XML is structured like this:
<ConfiguratorConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Section>
<Class ID="Example" Name="CompanyName.Example" Assembly="Example.dll">
<Interface>
<Property Name="exampleProperty1" Value="exampleValue" />
<Property Name="exampleProperty2" Value="exampleValue" />
<Property Name="exampleProperty3" Value="exampleValue" />
</Interface>
</Class>
</Section>
</ConfiguratorConfig>
I'd like the output to be structured like:
Class "Example"
Property "exampleProperty1"
Property "exampleProperty2"
Property "exampleProperty3"
I'm totally new to using XML. I've been searching the web for the past few hours, and none of the results have helped. Some have come close, but perhaps properties won't show up, or node's names won't display, etc.
I'm writing in c# in Visual Studio 2005.
Thanks for the help!
You can iterate through nodes using XmlDocument, you can put this demo in a Main method of a console application:
string xml = #"<ConfiguratorConfig xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
<Section>
<Class ID=""Example"" Name=""CompanyName.Example"" Assembly=""Example.dll"">
<Interface>
<Property Name=""exampleProperty1"" Value=""exampleValue"" />
<Property Name=""exampleProperty2"" Value=""exampleValue"" />
<Property Name=""exampleProperty3"" Value=""exampleValue"" />
</Interface>
</Class>
</Section></ConfiguratorConfig>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode _class in doc.SelectNodes(#"/ConfiguratorConfig/Section/Class"))
{
string name = _class.Attributes["ID"].Value;
Console.WriteLine(name);
foreach (XmlElement element in _class.SelectNodes(#"Interface/Property"))
{
if (element.HasAttribute("Name"))
{
string nameAttributeValue = element.Attributes["Name"].Value;
Console.WriteLine(nameAttributeValue);
}
}
}
If you're using version of .NET higher than 3.0 you can use XDocument class (recommended if you can choose).
XDocument xdoc = XDocument.Parse(xml);
foreach (XElement _class in xdoc.Descendants("Class"))
{
string name = _class.Attribute("ID").Value;
Console.WriteLine(name);
foreach (XElement element in _class.Descendants("Property"))
{
XAttribute attributeValue = element.Attribute("Name");
if (attributeValue != null)
{
string nameAttributeValue = attributeValue.Value;
Console.WriteLine(nameAttributeValue);
}
}
}
Im in the process of working with XML data and what Im trying to do is;
User selects name value from a dropdownlist
for each node with above name, value is added to a list
list then converted to string array
**printing the array to test, no output is given
string array converted to int array (to allow computation on
array)
**Print provides no output again
Here is the code I've produced, I get no errors just no output so I cant tell if the arrays have been populated.
if (DropDownList1.SelectedItem.Text=="Cabin")
{
//Load XML document
XmlDocument xml = new XmlDocument();
xml.LoadXml(Server.MapPath("~/Upload/" + FileUpload1.FileName));
// xnList = nodes -> rows with Cabin
XmlNodeList xnList = xml.SelectNodes("/root/row[#name='Cabin']");
//create a string list
List<string> strvalues = new List<string>();
//populate list with values # node Cabin
foreach (XmlNode xn in xnList)
{
strvalues.Add(xn["value"].InnerText);
}
//convert list to array
strvalues.ToArray();
for (int i = 0; i < 2; i++)
{
//print array
Console.WriteLine(strvalues[i]);
}
//convert string array to int array for data manipulation
int[] values = strvalues.Select(x => int.Parse(x)).ToArray();
for (int i = 0; i < values.Length; i++)
{
//print array
Console.WriteLine(values[i]);
}
}
Here is a section of the XML file also;
<root>
<row>
<var name="Name" value="Garcia" />
<var name=" Surname" value=" Jose" />
<var name=" Country" value=" Cuba" />
<var name=" Job" value="Software Developer" />
<var name=" Cabin" value="345" />
</row>
<row>
<var name="Name" value="Lenon" />
<var name=" Surname" value="Tim" />
<var name=" Country" value="USA" />
<var name=" Job" value="SoftwareDeveloper" />
<var name=" Cabin" value="444" />
</row>
</root>
Your XPath expression is wrong, as the <row> element has no attribute named name (and it's also missing the space in the actual name attribute value).
Did you mean /root/row/var[#name=' Cabin'] or possibly /root/row[var/#name=' Cabin'] (if you wanted the <row> element; though looking at your code that's not the case).
Additionally, the line strvalues.ToArray() does nothing, because you don't assign the result to anything. ToArray doesn't modify the list, it returns a new array with the same contents as the list. There is no real reason to convert the list to an array in this code either.
The attribute value for name in the sample XML is " Cabin" - note the leading space.
The attribute value tested against name in the XPath query is "Cabin" - no leading space.
So you never find any nodes.
The generic answer to looking at this would be to set a breakpoint immediately after you create the node list and to check the content at that point.
As a further aside, Linq to XML is much more pleasant to work with if that's available to you.
Do you have a console window associated with your solution? I think you're using a UI and there is no console window (so Console.WriteLine won't output anything). You can attach one, but for debug I can suggest Debug.WriteLine:
http://www.dotnetperls.com/debug-write
Also, you should check if your arrays being populated in debug mode.