Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Saturday, August 24, 2013 5:04 AM
How do I loop through each node in the following xml file in a way that can be parsed/formatted in a case statement as
If no child (e.g. <RegDate>, <Location> etc) then create a 2-dimensional array "MyArray1" containing the element name and the value.
If a node is like <SchoolType> then create a 2-dimensional array "MyArray2" containing the element name and the value.
If a node is like <CourseSelection> then iterate through each <subject> and create a 2-dimensional array "MyArray3" containing the element name and the value.
<School xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<SchoolType>
<School></School>
<Dept></Dept>
<Level></Level>
<Degree>Masters</Degree>
<Other></Other>
<SchoolType></SchoolType>
</SchoolType>
<RegDate>01-02-2013</RegDate>
<Location>Chicago</Location>
<CourseType>
<CourseType-A></CourseType-A>
<CourseType-B>Science</CourseType-B>
<CourseType-C>Art</CourseType-C>
<CourseType-D></CourseType-D>
</CourseType>
<CourseSelection>
<Subject>
<Instructor>
<FName>Brad</FName>
<LName>Pitt</LName>
<MName>na</MName>
</Instructor>
<Instructor>
<FName>Robert</FName>
<LName>Downey</LName>
<MName>x</MName>
</Instructor>
<InstructorCount>2</InstructorCount>
<InstructorMessage></InstructorMessage>
</Subject>
</CourseSelection>
<Undecided>true</Undecided>
<StartDate>02-03-2013</StartDate>
<ApprovedBy>Tom Cruise</ApprovedBy>
</School >
All replies (9)
Saturday, August 24, 2013 2:53 PM
See if the code below helps. I used an enumeration to create 3 types. then enumeration was needed so I could use a Case Statement.
1) Nodes with multiple Descendants
2) Nodes with one level of Decendants
3) Nodes with no Descendants
I put the XML data into a tree using my own custom class that contains dictionaries. Each level of the tree is a dictionary with the key being a sting and the value being one of the following
1) Another class which are the children
2) Another class that contains one class or a List of class. Your input had more than one instructor so I made a List of Insturctors. Each Instructor has it own dictionary.
3) An Attirbute
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Xml;using System.Xml.Linq;namespace ConsoleApplication1{ class Program { static string input = "<School xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + "<SchoolType>\n" + "<School></School>\n" + "<Dept></Dept>\n" + "<Level></Level>\n" + "<Degree>Masters</Degree>\n" + "<Other></Other>\n" + "<SchoolType></SchoolType>\n" + "</SchoolType>\n" + "<RegDate>01-02-2013</RegDate>\n" + "<Location>Chicago</Location>\n" + "<CourseType>\n" + "<CourseType-A></CourseType-A>\n" + "<CourseType-B>Science</CourseType-B>\n" + "<CourseType-C>Art</CourseType-C>\n" + "<CourseType-D></CourseType-D>\n" + "</CourseType>\n" + "<CourseSelection>\n" + "<Subject>\n" + "<Instructor>\n" + " <FName>Brad</FName>\n" + " <LName>Pitt</LName>\n" + " <MName>na</MName>\n" + "</Instructor>\n" + "<Instructor>\n" + " <FName>Robert</FName>\n" + " <LName>Downey</LName>\n" + " <MName>x</MName>\n" + "</Instructor>\n" + "<InstructorCount>2</InstructorCount>\n" + "<InstructorMessage></InstructorMessage>\n" + "</Subject>\n" + "</CourseSelection>\n" + "<Undecided>true</Undecided>\n" + "<StartDate>02-03-2013</StartDate>\n" + "<ApprovedBy>Tom Cruise</ApprovedBy>\n" + "</School >"; class MyElement { public NodeTypes type; public Dictionary<string, object> elements; } enum NodeTypes { HasChildren, IsNode, IsAttribute } static void Main(string[] args) { XDocument doc = new XDocument(); doc = XDocument.Parse(input); MyElement tree = new MyElement(); SpanXDocument(tree, doc.Root); } static void SpanXDocument(MyElement node, XElement elements) { NodeTypes nodeType; foreach (XElement element in elements.Elements()) { if (node.elements == null) { node.elements = new Dictionary<string, object>(); } if (element.Descendants().Count() > 0) { if (element.Descendants().Descendants().Count() > 0) { nodeType = NodeTypes.HasChildren; } else { nodeType = NodeTypes.IsNode; } } else { nodeType = NodeTypes.IsAttribute; } switch (nodeType) { case NodeTypes.HasChildren: MyElement newChild = new MyElement(); newChild.type = NodeTypes.HasChildren; node.elements.Add(element.Value, newChild); SpanXDocument(newChild, element); break; case NodeTypes.IsNode: MyElement newNode = new MyElement(); newNode.type = NodeTypes.IsNode; newNode.elements = new Dictionary<string, object>(); //types like instructor can contain on e or mor eitems //when more than one must make a list if (node.elements.ContainsKey(element.Name.LocalName)) { List<MyElement> ListElements = null; if (node.elements[element.Name.LocalName].GetType() == typeof(MyElement)) { //only one exists, change to a List<Dictionary> MyElement oldElement = (MyElement)node.elements[element.Name.LocalName]; //create a list ListElements = new List<MyElement>(); ListElements.Add(oldElement); node.elements[element.Name.LocalName] = ListElements; } else { ListElements = (List<MyElement>)node.elements[element.Name.LocalName]; } //add to a list of Myelement MyElement newElement = new MyElement(); newElement.type = NodeTypes.IsNode; foreach (XElement elementNode in element.Elements()) { newNode.elements.Add(elementNode.Name.LocalName, elementNode.Value); } ListElements.Add(newElement); } else { //add to a dictionary node.elements.Add(element.Name.LocalName, newNode); foreach (XElement elementNode in element.Elements()) { newNode.elements.Add(elementNode.Name.LocalName, elementNode.Value); } } break; case NodeTypes.IsAttribute: node.elements.Add(element.Name.LocalName, element.Value); break; } } } } }
jdweng
Saturday, August 24, 2013 5:00 PM
Thanks, but its a bit completed code for me.
I have seen a code somewhere a while code that used "if..else" statement to parse through the xml.
My goal is to identify each node if they contain children or not. If a node does not have a child then I just need to read the node value, otherwise, get the node name of the node containing child/children.
Saturday, August 24, 2013 8:37 PM
I simplified the code to the bare minimum. See if you like htis better
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Xml;using System.Xml.Linq;namespace ConsoleApplication1{ class Program { static string input = "<School xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + "<SchoolType>\n" + "<School></School>\n" + "<Dept></Dept>\n" + "<Level></Level>\n" + "<Degree>Masters</Degree>\n" + "<Other></Other>\n" + "<SchoolType></SchoolType>\n" + "</SchoolType>\n" + "<RegDate>01-02-2013</RegDate>\n" + "<Location>Chicago</Location>\n" + "<CourseType>\n" + "<CourseType-A></CourseType-A>\n" + "<CourseType-B>Science</CourseType-B>\n" + "<CourseType-C>Art</CourseType-C>\n" + "<CourseType-D></CourseType-D>\n" + "</CourseType>\n" + "<CourseSelection>\n" + "<Subject>\n" + "<Instructor>\n" + " <FName>Brad</FName>\n" + " <LName>Pitt</LName>\n" + " <MName>na</MName>\n" + "</Instructor>\n" + "<Instructor>\n" + " <FName>Robert</FName>\n" + " <LName>Downey</LName>\n" + " <MName>x</MName>\n" + "</Instructor>\n" + "<InstructorCount>2</InstructorCount>\n" + "<InstructorMessage></InstructorMessage>\n" + "</Subject>\n" + "</CourseSelection>\n" + "<Undecided>true</Undecided>\n" + "<StartDate>02-03-2013</StartDate>\n" + "<ApprovedBy>Tom Cruise</ApprovedBy>\n" + "</School >"; enum NodeTypes { HasChildren, IsNode, IsAttribute } static void Main(string[] args) { XDocument doc = new XDocument(); doc = XDocument.Parse(input); SpanXDocument(doc.Root); } static void SpanXDocument(XElement elements) { NodeTypes nodeType; foreach (XElement element in elements.Elements()) { if (element.Descendants().Count() > 0) { if (element.Descendants().Descendants().Count() > 0) { nodeType = NodeTypes.HasChildren; } else { nodeType = NodeTypes.IsNode; } } else { nodeType = NodeTypes.IsAttribute; } switch (nodeType) { case NodeTypes.HasChildren: Console.WriteLine("Has Children Name : {0}", element.Name.LocalName); SpanXDocument(element); break; case NodeTypes.IsNode: Console.WriteLine("Node Name : {0}", element.Name.LocalName); foreach (XElement elementNode in element.Elements()) { Console.WriteLine("Node Attribute Name : {0} Value : {1}", elementNode.Name.LocalName, elementNode.Value); } break; case NodeTypes.IsAttribute: Console.WriteLine("Attribute Name : {0} Value : {1}", element.Name.LocalName, element.Value); break; } } } }}
jdweng
Sunday, August 25, 2013 2:30 AM
Looks good, let me try it. Thanks
Sunday, August 25, 2013 6:04 AM
The original code I pust the results into tree structure with a dictionaries at each branch (dictionary<string, object>) to make it simply to lookup data. the 2nd code I simply removed the tree and dictionaries. The code got a little complicated because some Nodes (like instructor) had duplicte keys so I have to create a list object.
jdweng
Monday, August 26, 2013 1:25 AM
How do I modify the second code so it will create a 2-dimensional array (Key, Value) for <Instructor>?
Also, my XML is a file (MyXML.xml); how do I pass it as an input file to parse?
Monday, August 26, 2013 8:15 AM
Here are the answers
1) How do I modify the second code so it will create a 2-dimensional array (Key, Value) for <Instructor>?
Answer : The code below will create a dictionary of the objects below instructor. If you are trying to add more than one instructor to a dictionary then you need to make a List<> object of the instructors like in my original code like (Key, List<string, string>)
2)
Also, my XML is a file (MyXML.xml); how do I pass it as an input file to parse?
Answer : Use Load() instead of Parse(). See below
XDocument doc = new XDocument();
doc = XDocument.Load(@"c:\temp\abc.xml");
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Xml;using System.Xml.Linq;namespace ConsoleApplication1{ class Program { static string input = "<School xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + "<SchoolType>\n" + "<School></School>\n" + "<Dept></Dept>\n" + "<Level></Level>\n" + "<Degree>Masters</Degree>\n" + "<Other></Other>\n" + "<SchoolType></SchoolType>\n" + "</SchoolType>\n" + "<RegDate>01-02-2013</RegDate>\n" + "<Location>Chicago</Location>\n" + "<CourseType>\n" + "<CourseType-A></CourseType-A>\n" + "<CourseType-B>Science</CourseType-B>\n" + "<CourseType-C>Art</CourseType-C>\n" + "<CourseType-D></CourseType-D>\n" + "</CourseType>\n" + "<CourseSelection>\n" + "<Subject>\n" + "<Instructor>\n" + " <FName>Brad</FName>\n" + " <LName>Pitt</LName>\n" + " <MName>na</MName>\n" + "</Instructor>\n" + "<Instructor>\n" + " <FName>Robert</FName>\n" + " <LName>Downey</LName>\n" + " <MName>x</MName>\n" + "</Instructor>\n" + "<InstructorCount>2</InstructorCount>\n" + "<InstructorMessage></InstructorMessage>\n" + "</Subject>\n" + "</CourseSelection>\n" + "<Undecided>true</Undecided>\n" + "<StartDate>02-03-2013</StartDate>\n" + "<ApprovedBy>Tom Cruise</ApprovedBy>\n" + "</School >"; enum NodeTypes { HasChildren, IsNode, IsAttribute } static void Main(string[] args) { XDocument doc = new XDocument(); doc = XDocument.Parse(input); SpanXDocument(doc.Root); } static void SpanXDocument(XElement elements) { NodeTypes nodeType; foreach (XElement element in elements.Elements()) { if (element.Descendants().Count() > 0) { if (element.Descendants().Descendants().Count() > 0) { nodeType = NodeTypes.HasChildren; } else { nodeType = NodeTypes.IsNode; } } else { nodeType = NodeTypes.IsAttribute; } switch (nodeType) { case NodeTypes.HasChildren: Console.WriteLine("Has Children Name : {0}", element.Name.LocalName); SpanXDocument(element); break; case NodeTypes.IsNode: Console.WriteLine("Node Name : {0}", element.Name.LocalName); Dictionary<string, string> attributes = new Dictionary<string, string>(); foreach (XElement elementNode in element.Elements()) { attributes.Add(elementNode.Name.LocalName, elementNode.Value); Console.WriteLine("Node Attribute Name : {0} Value : {1}", elementNode.Name.LocalName, elementNode.Value); } break; case NodeTypes.IsAttribute: Console.WriteLine("Attribute Name : {0} Value : {1}", element.Name.LocalName, element.Value); break; } } } }}
jdweng
Tuesday, August 27, 2013 10:21 PM
Hi jdweng,
If I use your original code; how do I read keys and values so for nodes containing child/children?
Wednesday, September 4, 2013 7:22 AM
Hi Shayaan,
Welcome to MSDN Forum Support.
Depend on NodeTypes.HasChildren to judge it has children node or not.
Sincerely,
Jason Wang
<THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
Thanks
MSDN Community Support
Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.