Rank: Newbie
Joined: 2/4/2016 Posts: 1 Location: USA
|
I have some XML I am trying to parse, and it has the following structure in it: Note, this is a contrived example, but the XML I am using has this exact structure... ... <MovieType> <Name>Excellent.Adventure</Name> <Value> <ValueName>Bill</ValueName> </Value> <Value> <ValueName>Ted</ValueName> </Value> <Name>Action</Name> <Value> <ValueName>Arnold</ValueName> </Value> <Name>Musical</Name> <Value> <ValueName>Julie</ValueName> </Value> </MovieType> ...
I am given a MovieType name, and I need to find that name along with the list of valuenames that go with it (the values after the name, but before the next name). The documentation seems to indicate that I can get a list of elements in a complex type, and I thought I could use that to get all of the elements, search the list for the Name attributes and separate them into separate lists. However, the GetElements method does not appear to be available for the type XMLSpy generated for this.
The documentation for working with generated code is not complete, and it is not very good either. I was hoping someone would have an idea of how to do this. I realize this is a goofy structure, and I would change it if I could, but it is a format provided by my customer, and it is used in a legacy system that I have to be compatible with.
|
Rank: Member
Joined: 3/25/2015 Posts: 19
|
If you're still looking for an answer, I was able to get around this by using a combination of Altova-generated classes and the System.Xml classes.
Here is the schema from which I generated code:
Code:<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="Movies"> <xs:complexType> <xs:sequence maxOccurs="unbounded"> <xs:element name="MovieType"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="unbounded"/> <xs:element name="Value" minOccurs="1" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="ValueName" type="xs:string" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
This schema validates successfully the following XML like yours:
Code: <?xml version="1.0" encoding="UTF-8"?> <Movies xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Movies.xsd"> <MovieType> <Name>Excellent.Adventure</Name> <Value> <ValueName>Bill</ValueName> </Value> <Value> <ValueName>Ted</ValueName> </Value> <Name>Action</Name> <Value> <ValueName>Arnold</ValueName> </Value> <Name>Musical</Name> <Value> <ValueName>Julie</ValueName> </Value> </MovieType> </Movies>
Finally, here is the actual C# code:
Code:using System; using Altova.Types; using System.Collections.Generic;
namespace Movies { /// <summary> /// Summary description for MoviesTest. /// </summary> class MoviesTest { protected static void Example() { // Load the XML structure and get the root element Movies2 doc = Movies2.LoadFromFile("Movies.xml"); MoviesType root = doc.Movies3.First;
// I'm creating here a dictionary object to store the info you need as key-value pairs. /// Each dictionary key stores the value of the <Name> element in your XML. /// Each dictionary value stores a list of string, where one string corresponds to one <ValueName> Dictionary<String, List<string>> dict = new Dictionary<string, List<string>>();
// Here I declare a "stack" which keeps in memory only one dictionary key at a time // We will iterate through all children nodes // of <MovieType>, and everytime a new name if found, all values previously accumulated on the // stack will be added to the dictionary object as a new dictionary key. // Initially the stack values are empty/null. string stackName = ""; List<string> stackValueNames = new List<string>();
// Iterate through all "MovieType" elements foreach (MovieTypeType movie in root.MovieType) { foreach (System.Xml.XmlNode NameOrValueNode in movie.Node.ChildNodes) { if (NameOrValueNode.LocalName == "Name") { // Found a new <Name> element, so let's put it on the stack stackName = NameOrValueNode.InnerText;
// Create a brand new list of <ValueNames> for this <Name> stackValueNames = new List<string>(); } else { // check if the next sibling exists if (NameOrValueNode.NextSibling != null) { // if the next sibling is a name node if (NameOrValueNode.NextSibling.LocalName == "Name") { // Add the current <ValueName> to the stack stackValueNames.Add(NameOrValueNode.ChildNodes[0].InnerText);
// Add a new dictionary entry dict.Add(stackName, stackValueNames); } else { // Found a <ValueName>, so add it to the stack stackValueNames.Add(NameOrValueNode.ChildNodes[0].InnerText); } } else // If this is the last node { // Add the last <ValueName> to the stack stackValueNames.Add(NameOrValueNode.ChildNodes[0].InnerText);
// Add a new dictionary entry dict.Add(stackName, stackValueNames); } } } }
// This merely outputs the contents of the dictionary object to the console foreach (KeyValuePair<string, List<string>> entry in dict) { // Output the key Console.WriteLine(entry.Key); // Output the values foreach (string value in entry.Value) { Console.WriteLine(" " + value); } }
} /// <summary> /// The main entry point for the application. /// </summary> [STAThread] public static int Main(string[] args) { try { Example(); Console.Read(); return 0; } catch (Exception e) { Console.WriteLine(e); return 1; } } } }
rasgeado attached the following image(s):
|