IMPORTANT:
this is not a Support Forum! Experienced users might answer from time to time questions posted here. If you need a professional and reliable answer, or if you want to report a bug, please contact Altova Support instead.

Getting the next sibling element Options · View
ts
Posted: Thursday, February 4, 2016 7:26:33 PM
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.
rasgeado
Posted: Monday, February 8, 2016 2:09:25 PM
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):
output.png

Users browsing this topic
guest

Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Use of the Altova User Forum(s) is governed by the Altova Terms of Use.