Reputation: 325
For the life of me, I can't figure out why more people haven't asked this or why I can't find the solution online, unless there happens to be none.
The general XML layout is as follows, however the position of the interfaces and interface count may change from XML document to XML document (so counting child nodes is not an option):
<?xml version="1.0" ?>
<rspec type=manifest xmlns="link2ns" xmlns:jacks="jacksNSurl">
<node id="node-1">
<icon url="someurl" xmlns="jacksNSurl"/>
<services>
<login username="user1"/>
<login username="user2"/>
</services>
<interface id="interface-0"></interface>
<interface id="interface-1"></interface>
<interface id="interface-2"></interface>
</node>
<node id="node-2">
<icon url="someurl"/>
<services>
<login username="user1"/>
<login username="user2"/>
</services>
<interface id="interface-3"></interface>
<interface id="interface-4"></interface>
<interface id="interface-5"></interface>
</node>
<node id="node-3">
<icon url="someurl"/>
<services>
<login username="user1"/>
<login username="user2"/>
</services>
<interface id="interface-6"></interface>
<interface id="interface-7"></interface>
<interface id="interface-8"></interface>
</node>
</rspec>
And my code works as follows:
List<MyClass> nodeList = new List<MyClass>();//Where I store what I got
XmlNodeList vmNodes = xmlDoc.GetElementsByTagName("node");//Gets all nodes
foreach (XmlNode vmNode in vmNodes) //go through each node and get stuff
{
MyClass tempNode = new MyClass();//create a temporary class to be added to class list
//get node ID and store it
string nodeID = vmNode.Attributes["id"].Value;
tempNode.ID = nodeID;
//Here I want to get a temporary list of the interfaces and their for this specific node
//The following line gives me all interfaces, NOT the ones of the current vmNode, which is all I want
XmlNodeList xmlInterfaces = vmNode.SelectNodes("//ns:interface",nsmgr);
//nsmgr is a namespace manager created at start of program and includes the following namespaces: xml, xmlns, ns, jacks, emulab, tour, xsi
nodeList.Add(tempNode);
}
My problem is I can't rely on the position or count of interfaces with each node, so using ChildNodes then eliminating non-interface children by counting nodes won't work as interface count and position may change from XML document to XML document.
Am I missing something? I've looked through Microsoft's documents and through a bunch of forums including here, and all I ever find are tangent answers, all of which result in either the childnode counting approach, or a list of all interfaces (not just the ones from the current vmNode). Should I be using Linq instead and if so, how do I adjust the code?
Side-note: this is being used with unity to make a game.
Upvotes: 1
Views: 1056
Reputation: 325
Give Clay's comment an upvote as he really helped and was right and gave a very simple answer (without requiring me to use or convert to Linq).
Apparently there aren't enough non-Linq examples out there to filter through all the useless examples that uses the root, aka "//".
What my XMLnode list line for the interfaces should be:
XmlNodeList xmlInterfaces = vmNode.SelectNodes("ns:interface",nsmgr);
The difference is the "//", which tells C# to use the root XML node, which is "<rspec>
", not "<node id=x>
. By getting rid of "//", I tell it to use the current XMLNode element, aka vmNode
, as the parent and only get the child nodes with the selected name "interface". Note that the "ns:<childnode name>
" and nsmgr
are required in my C# code due to the namespace presence in the xml document.
I'm surprised there aren't more examples like this or people with this problem. Hopefully others can use this post in the future and find it helpful, especially since it uses namespaces as well.
Upvotes: 3
Reputation: 13955
I tried this out in a console application. Make sure you are using System.Xml.Linq;
string str = @"Your XML Here";
XDocument xDoc = XDocument.Parse(str);
var nodes = xDoc.Descendants("node").ToList(); // This gets you all <node>'s
var node = nodes.Where(n => n.Attribute("id").Value == "node-3").FirstOrDefault(); // This gets you just "node-3"
var interfaces = node.Descendants("interface").ToList();
'interfaces' contains:
<interface id="interface-6"></interface>
<interface id="interface-7"></interface>
<interface id="interface-8"></interface>
Note that to get this to work, I had to change the first line of your XML from:
<rspec type=manifest xmlns="link2ns" xmlns:jacks="jacksNSurl">
to:
<rspec>
Upvotes: 0