0

*Switched over to serailization.

Summary: I have all the variables pre-defined as null / 0. I want to set them using data from and XML document. The document contains the exact same names as the variables. I don't want to use a bunch of else ifs so I'm trying to do it based on the names I pull from the XML document.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Xml;
using System.IO;

public class ShipAttributes
{
    // Model Information
    string name;
    string modelName;
    string firingPosition;
    string cameraPosition;
    string cargoPosition;
    Vector3 cameraDistance;

    // Rotation
    float yawSpeed;
    float pitchSpeed;
    float rollSpeed;

    // Speed
    float maxSpeed;
    float cruiseSpeed;
    float drag;
    float maxAcceleration;
    float maxDeceleration;

    // Physics Properties
    float mass;

    // Collection Capacity
    float cargoSpace;

    // Combat [Defense]
    float structureHealth;
    float armorHealth;
    float shieldHealth;
    float shieldRadius;

    // Combat [Assault]
    float missileRechargeTime;
    float fireRate; 

    // Currency Related
    float cost;
    float repairMultiplier;

void PopulateShipList()
{
    if (shipList != null)
        return;

    string filepath = Application.dataPath + "/Resources/shipsdata.xml";

    XmlRootAttribute xml_Root = new XmlRootAttribute();
    xml_Root.ElementName = "SHIPS";
    xml_Root.IsNullable = true;
    //using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read)) 
    //{
        StringReader stringReader = new StringReader(filepath);
        stringReader.Read();
        XmlReader xRdr = XmlReader.Create(stringReader);
        XmlSerializer xml_s = new XmlSerializer(typeof(List<ShipAttributes>), xml_Root);
        shipList= (List<ShipAttributes>)xml_s.Deserialize(xRdr);
    //}
}
public ShipAttributes LoadShip(string inName)
{
    PopulateShipList();
    foreach (ShipAttributes att in shipList)
    {
        if (att.name == inName)
        {
            att.shipList = shipList;
            return att;
        }
    }

    return null;
}

*Note Variables in the XML files have the exact same Format and Name as the variables in the class. maxSpeed in Class is maxSpeed in XML file.

My XML looks like this --

<?xml version="1.0" encoding="UTF-8 without BOM" ?>

     <SHIPS>
        <SHIP>
            <name>Default</name>
            <id>0</id>
            <modelName>Feisar_Ship</modelName>
            <firingPosition>null</firingPosition>
            <cameraPosition>null</cameraPosition>
            <cargoPosition>null</cargoPosition>
            <cameraDistance>null</cameraDistance>
            <yawSpeed>2000.0</yawSpeed>
            <pitchSpeed>3000.0</pitchSpeed>
            <rollSpeed>10000.15</rollSpeed>
            <maxSpeed>200000.0</maxSpeed>
            <cruiseSpeed>100000.0</cruiseSpeed>
            <drag>0.0</drag>
            <maxAcceleration>null</maxAcceleration>
            <maxDeceleration>null</maxDeceleration>
            <mass>5000.0</mass>
            <cargoSpace>150.0</cargoSpace>
            <structureHealth>100.0</structureHealth>
            <armorHealth>25.0</armorHealth>
            <shieldHealth>25.0</shieldHealth>
            <shieldRadius>30.0</shieldRadius>
            <missileRechargeTime>2.0</missileRechargeTime>
            <fireRate>0.5f</fireRate>
            <cost>0</cost>
            <repairMultiplier>1.0</repairMultiplier>
        </SHIP>   
     </SHIPS

>

Yes Yes I know... Feisar! Just place holders for now from turbosquid.

Ken Rea
  • 67
  • 8
  • 1
    I don't understand your 3rd and 4th steps...? Are these variables of yours part of a class? And, could that class just be deserialised from the XML document directly? Lastly: not actually sure what you're asking :) – Kevin Versfeld Feb 14 '13 at 06:24
  • Sample of your class would be useful (assuming "variable" means property/field of a class, not a local variable of some method). – Alexei Levenkov Feb 14 '13 at 06:25
  • Updated with Code from what I'm doing. I'm trying to set the variables without saying speed = attribute.innertext. I want to say [Psuedo] attribute.name.thisIsNowTheVariable = attribute.innerText; Attribute being an XML node. – Ken Rea Feb 14 '13 at 06:32

2 Answers2

3

Create a class to hold the values you are reading in and use XML Serialization.

Microsoft Tutorial

Tech Pro Tutorial

MSDN: XmlSerializer

EDIT :

If the XML is exactly the same as the class code you posted, the following should allow you to get a class of ShipAttributes:

ShipAttributes attributes = null;
string filepath = "/path/to/xml";

using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read)) {
    var xml_s = new XmlSerializer(typeof(ShipAttributes));

    attributes = (ShipAttributes)xml_s.Deserialize(stream);
}

Edit 2 : Multiple Ships

In your comment, you said that the file contains multiple ShipAttribute descriptions. The way to handle that is the same as above, but deserialize the file into the type List<ShipAttribute> as follows:

List<ShipAttributes> ships = null;
string filepath = "/path/to/xml";

using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read)) {
    var xml_s = new XmlSerializer(typeof(List<ShipAttributes>));

    ships= (List<ShipAttributes>)xml_s.Deserialize(stream);
}

Once you've done that, you have all of the ships in memory and can pick the one out of the list you need using Linq etc.

Brian Kintz
  • 1,983
  • 15
  • 19
  • I did come across this, haven't tried serializing yet. That'll be new to me. Will work it out tomorrow if the other way doesn't work. – Ken Rea Feb 14 '13 at 06:45
  • Edit: Interesting, so if I put the order of the variables in the XML in the same order they are in within the class, this would set all the attributes in the class as it was read in? – Ken Rea Feb 14 '13 at 21:01
  • Errr, The only problem with this is, I'll be storing multiple ships in the XML so I have to be able to skip through them until I find which ship I need. The deserialization doesn't seem to allow for this type of work. – Ken Rea Feb 14 '13 at 21:15
  • The order of the variables doesn't matter...the XmlSerializer is smart enough to figure out where they go based on name. See my edit for multiple ships – Brian Kintz Feb 15 '13 at 06:41
  • I guess I could set the name on creation of the class. Then have the serializer compare the name and then jump down into that ship node. But I almost have it working this way. I do want to give the serializer a shot as an alternative later but I'm sooooo close. – Ken Rea Feb 15 '13 at 06:48
  • With that being the case, this is probably a much better way ahaha. How would I be able to know to go down that node? – Ken Rea Feb 15 '13 at 06:51
  • OH, gotcha. But if I'm trying to run this on iOS memory might be a concern with using lists. – Ken Rea Feb 15 '13 at 06:52
  • 1
    I had this sudden urge to say Danke Schoen but I was like naaah he probably doesn't know german. Then I clicked your profile to see if I could thank you in a message and you were in Germany so Danke Schoen. – Ken Rea Feb 15 '13 at 06:56
  • Unless you have *thousands* of ships, memory shouldn't be a problem. It will also save you quite a bit of processing by only loading the data once instead of every time you want to access a different ship. – Brian Kintz Feb 15 '13 at 06:58
  • I've got it to the point where it's telling me Text node cannot appear in this state. I tried what they had on the Unity page but to no avail. S – Ken Rea Feb 15 '13 at 08:09
  • It looks like you've got one element too many in your XML. You want to have one element that contains all of your ships: ...... – Brian Kintz Feb 15 '13 at 08:30
  • I had actually done that last night before I logged off, It didn't work. I tried the tricks mentioned here http://answers.unity3d.com/questions/10904/xmlexception-text-node-canot-appear-in-this-state.html as I am using Unity. They don't seem to work. Also I updated my Original Code to reflect where I am at now. – Ken Rea Feb 15 '13 at 19:04
0

ASSUMING YOU XML FILE

<?xml version="1.0" encoding="utf-8"?>
<Variables>      
    <VariableName1>1</VariableName1>
    <VariableName2>test</VariableName2>
    <VariableName3>test2</VariableName3>    
</Variables>



var data = XDocument.Load("YourXML.xml");
var xmldata = from x in data.Descendants("Variables")                        
                        select x;

notes.Select(_BuildPropertyFromElement);



private Yourclassname _BuildNoteFromElement(XElement element)
    {
      var type = typeof(**Yourclassname**);
      var Details = new Yourclassname();

      foreach (var propInfo in type.GetProperties())
      {
         var rawValue = element.Element(propInfo.Name).Value;
         var convertedValue = propInfo.PropertyType == typeof(DateTime) ?         (object)Convert.ToDateTime(rawValue) : rawValue;
            propInfo.SetValue(Details , convertedValue, null);
                }

                return Details ;
            }

YOURCLASSNAME is the name of the class which would have all the properties you want to set to

Chief
  • 914
  • 1
  • 9
  • 26
  • The right way would be serializing it but i have posted in a way which you are trying – Chief Feb 14 '13 at 06:38
  • I'll give this a look see when my brain isn't falling asleep. I'll get back to you tomorrow on this. – Ken Rea Feb 14 '13 at 06:44