3
\$\begingroup\$

I've got a working program that turns XML into a XmlObject. The object can then be accessed using getName(), getValue(), and getChild(). The code works but I'm looking for recommendations. I couldn't find anything built into c# that creates an object from XML. I'm currently learning by doing games in Unity so hopefully the code isn't too awful.

The static class for creating an XmlObject

namespace XmlToObject
{
    using System.Collections.Generic;
    using System.Xml;
    using System.IO;
    using UnityEngine;

    /// XmlObjectCreator turns xml into an XmlObject
    public static class XmlObjectCreator
    {

        /// Generates the xml object.
        public static XmlObject generateXmlObject (TextAsset xmlTextFile, string nameOfFirstTag)
        {
            //load the xml document
            XmlDocument xmlDoc = new XmlDocument ();
            xmlDoc.Load (new StringReader (xmlTextFile.text));

            //Navigate to the first tag
            XmlNode firstNode = xmlDoc.SelectSingleNode ("//" + nameOfFirstTag);

            //Return the built object
            return recursiveBuildXmlObject (firstNode);
        }

        /// Recursivly builds an xml object.
        private static XmlObject recursiveBuildXmlObject (XmlNode startNode)
        {
            //Create the buildObject
            XmlObject buildObject = new XmlObject ();

            //Set the name and value
            buildObject.setName (startNode.Name);
            buildObject.setValue (startNode.InnerText);

            //Add child nodes to subList if they exist
            foreach (XmlNode child in startNode.ChildNodes) {
                buildObject.add (recursiveBuildXmlObject (child));
            }

            //Once children are done
            return buildObject;
        }
    }
}

The XmlObject is what is actually used for accessing the data taken from the XML document.

namespace XmlToObject
{
    using System.Collections.Generic;

    /// Xml object is the actual object used for navigating the data.
    public sealed class XmlObject
    {
        private string name;
        private string value;
        private List<XmlObject> subList;

        /// Initializes a new instance of the XmlObject class.
        public XmlObject ()
        {
            subList = new List<XmlObject> ();
            value = null;
        }

        /// Add the specified inputXmlObject.
        public void add (XmlObject inputXmlObject)
        {
            subList.Add (inputXmlObject);
        }

        /// Gets a xml child by name.
        public XmlObject getChild (string name)
        {
            foreach (XmlObject child in subList) {
                if (name.Equals (child.getName ())) {
                    return child;
                }
            }

            throw new System.ArgumentException ("Child with name: " + name + " does not exist.");
        }

        //Setters and getters for fields: name, value

        public string getName ()
        {
            return name;
        }

        public void setName (string newName)
        {
            name = newName;
        }

        public string getValue ()
        {
            return value;
        }

        public void setValue (string newValue)
        {
            value = newValue;
        }
    }
}

I've seen lots of code that deals with known XML structures, but few examples where the XML structure is not predefined/known. I'm sure that there is a better way to do what this code does, I'm just not sure what it is.

\$\endgroup\$
  • 1
    \$\begingroup\$ @t3chb0t Okay I added them back in. \$\endgroup\$ – Aoradon Jun 28 '17 at 18:32
5
\$\begingroup\$

It is a good Idea to create a generic object model that may represent an XML document. Therefore, the .Net Framework already contains such models: XmlDocument and XDocument.

I would really suggest to use them.


Some comments to your code:

  • Methods and properties usually start with a capital letter in C#.
  • The method getChild throws an exception if no element was found. Consider to return null instead because it is not an exceptional use case and returning null is more flexible.
  • The field subList could be read-only.
  • C# has the concept of Properties which should be used instead of get* and set* methods
buildObject.setName(startNode.Name);
buildObject.setValue(startNode.InnerText);

The code above does not produce the expected result because InnerText is not just the inner text of the current node but the text of the current and all sub nodes. The following XML for example:

<xml>
    <test>
        <blub>foo</blub>
        <blub>bar</blub>
    </test>
</xml>

Produces something like:

XmlObject(Name: xml, Value: foobar)
    XmlObject(Name: test, Value foobar)
        XmlObject(Name: blub, Value foo)
        XmlObject(Name: blub, Value bar)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.