-1
\$\begingroup\$

I have a C# program that has a function that reads an XML. I took that function and brought it over to my Unity game which will be using the same XML. However, my reading method doesn't seem to work.

Libraries:

using System.Xml;
using System.Xml.Linq;

Reader:

static public XDocument ProjectXML = XDocument.Load(SaveHandler.gFolder + "xml");
    List<XElement> GameInfo = ProjectXML.Descendants("Project").Elements("Subsystems").Elements("Values").Where(x => x.Attribute("Name").Value == "GameInfo").Elements("Value").ToList();
    foreach (XElement elem in GameInfo)
    {
        if (elem.Attribute("Name").Value == "TerrainGenerationMode")
            GenerationMode = (elem.Attribute("Value").Value == "Flat");
        if (elem.Attribute("Name").Value == "WorldName")
            WorldName = elem.Attribute("Value").Value;
        if (elem.Attribute("Name").Value == "TerrainLevel")
            TerrainLevel = int.Parse(elem.Attribute("Value").Value);
        if (elem.Attribute("Name").Value == "TerrainBlockIndex")
            TerrainBlock = int.Parse(elem.Attribute("Value").Value);
        if (elem.Attribute("Name").Value == "TerrainOceanBlockIndex")
            OceanBlock = int.Parse(elem.Attribute("Value").Value);
    }
    PlayerPosition = new double[3]; // Temporary Line
    List<XElement> Player = ProjectXML.Descendants("Project").Elements("Entities").Elements("Entity").Where(x => x.Attribute("Name").Value == "Player").Elements("Values").Where(x => x.Attribute("Name").Value == "Body").Elements("Value").ToList();
    foreach (XElement elem in Player)
    {
        if (elem.Attribute("Name").Value == "Position")
            PlayerPosition = elem.Attribute("Value").Value.Split(',').Select(double.Parse).ToArray();
    }

That code is perfectly fine in my other program. But apparently Where and Select don't exist in Unity's libraries.

So what are my alternatives in Unity?

EDIT, Errors:

Error   1   'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' could be found (are you missing a using directive or an assembly reference?) F:\Repositories\SC TB 3D\Assets\Survivalcraft\Settings.cs   22  111 Assembly-CSharp
Error   2   'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' could be found (are you missing a using directive or an assembly reference?) F:\Repositories\SC TB 3D\Assets\Survivalcraft\Settings.cs   37  107 Assembly-CSharp
Error   3   'System.Array' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)   F:\Repositories\SC TB 3D\Assets\Survivalcraft\Settings.cs   41  75  Assembly-CSharp
\$\endgroup\$
2
  • \$\begingroup\$ Unity uses .NET 2.0. Enumerable.Select requires .NET 3.5 or higher. \$\endgroup\$ Feb 21, 2016 at 2:42
  • \$\begingroup\$ @Chris "So what are my alternatives in Unity?" \$\endgroup\$
    – Corey Iles
    Feb 21, 2016 at 2:43

3 Answers 3

2
\$\begingroup\$

LINQ expressions (Where, Select etc.) are a .NET 3.5 feature. By default, Unity only supports .NET 2.0.

You could change the used version of the .NET framework in the project settings of MonoDevelop / Visual Studio. But that will prevent your game from working on certain platforms.

When you want to keep compatibility with all available build targets, you have to implement .Where() yourself with a foreach loop.

foreach ( XElement element in ProjectXML.Descendants("Project").Elements("Entities").Elements("Entity")) {
    if (element.Attribute("Name").Value == "Player") {
         // ...etc...
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I was actually just about to answer the question myself because I already chose to do what you did. Except in my version I actually set the variable, loop, then set it again... \$\endgroup\$
    – Corey Iles
    Feb 21, 2016 at 4:03
2
\$\begingroup\$

You are missing:

using System.Linq;

While a little out of date at this point I find the Mono Compatibility page form the 4.10 documentation to be useful.

It lists IEnumarable.Where() as compatible with both .NET 2.0 and .NET 2.0 Subset. enter image description here

\$\endgroup\$
0
\$\begingroup\$

The code that I am using now is like Philipp's answer, but here's what I can up with for future reference:

    ProjectXML = XDocument.Load(SaveHandler.gFolder + "Project.xml");
    List<XElement> GameInfo = new List<XElement>(ProjectXML.Descendants("Project").Elements("Subsystems").Elements("Values"));//.ToList();
    foreach (XElement x in GameInfo)
    {
        if (x.Attribute("Name").Value == "GameInfo")
        {
            GameInfo = new List<XElement>(x.Elements("Value"));
            break;
        }
    }
    foreach (XElement elem in GameInfo)
    {
        if (elem.Attribute("Name").Value == "TerrainGenerationMode")
            GenerationMode = (elem.Attribute("Value").Value == "Flat");
        if (elem.Attribute("Name").Value == "WorldName")
            WorldName = elem.Attribute("Value").Value;
        if (elem.Attribute("Name").Value == "TerrainLevel")
            TerrainLevel = int.Parse(elem.Attribute("Value").Value);
        if (elem.Attribute("Name").Value == "TerrainBlockIndex")
            TerrainBlock = int.Parse(elem.Attribute("Value").Value);
        if (elem.Attribute("Name").Value == "TerrainOceanBlockIndex")
            OceanBlock = int.Parse(elem.Attribute("Value").Value);
    }

    Debug.Log("GenerationMode: " + GenerationMode);
    Debug.Log("WorldName: " + WorldName);
    Debug.Log("TerrainLevel: " + TerrainLevel);
    Debug.Log("TerrainBlock: " + TerrainBlock);
    Debug.Log("OceanBlock: " + OceanBlock);

    PlayerPosition = new double[3]; // Temporary Line
    List<XElement> Player = new List<XElement>(ProjectXML.Descendants("Project").Elements("Entities").Elements("Entity"));
    foreach (XElement x in Player)
    { // .Where(x => x.Attribute("Name").Value == "Player").Elements("Values")
        if (x.Attribute("Name").Value == "Player")
        {
            Player = new List<XElement>(x.Elements("Values"));
            break;
        }
    }
    foreach (XElement x in Player)
    { // .Where(x => x.Attribute("Name").Value == "Body").Elements("Value").ToList();
        if (x.Attribute("Name").Value == "Body")
        {
            Player = new List<XElement>(x.Elements("Value"));
            break;
        }
    }
    foreach (XElement elem in Player)
    {
        if (elem.Attribute("Name").Value == "Position")
        {
            string[] strings = elem.Attribute("Value").Value.Split(',');
            PlayerPosition = new double[] {
                double.Parse(strings[0]),
                double.Parse(strings[1]),
                double.Parse(strings[2])
            };
        }
    }

    Debug.Log("PlayerPosition: " + PlayerPosition);
\$\endgroup\$
2
  • \$\begingroup\$ That code won't do what you want it to do when one of the nodes is missing. It would be wiser to nest the foreach-loops instead of just assuming that the previous one set Player to a different value. \$\endgroup\$
    – Philipp
    Feb 21, 2016 at 4:12
  • \$\begingroup\$ @Philipp Well actually the nodes will always undoubtedly be there. They are generated by the game every time. But yeah, your's is the way to go for anyone else, which is why I marked your's as the answer and not mine. \$\endgroup\$
    – Corey Iles
    Feb 21, 2016 at 9:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .