Loading XML from StreamAssets not working

Hallo everyone,

I am trying to load the XML file “hspositions.xml”, located in “/Assets/StreamingAssets/” at runtime using C#'s XMLSerializer. This is working fine in the Editor and the Standalone build, but fails in WebGL.

First of all here is the class structure I am using to store the deserialized XML content, which also contains the DeSerialize() method:

[XmlRoot("Data")]
public class DataCollection
{
    [XmlElement("Hotspot")]
    public List<Hotspot> Hotspot;

    public static DataCollection DeSerialize(string path)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(DataCollection));
        using(var stream = new FileStream(path, FileMode.Open))
        {
            return serializer.Deserialize(stream) as DataCollection;
        }
    }
}

public class Hotspot
{
    [XmlElement("Properties")]
    public List<Properties> Properties = new List<Properties>();
}

public class Properties
{
    public float xPos;
    public float yPos;

    public float alphaValue;
}

And in a seperate class that I attach to an empty GameObject, I call the DeSerialize() method like that:

public class XMLDeserializer : MonoBehaviour

{

  public static DataCollection XmlData;


  void Awake ()

  {

  XmlData = DataCollection.DeSerialize(Path.Combine(Application.streamingAssetsPath, "hspositions.xml"));

  }

}

The deserialized data is then used by GUI elements to drive their position. However, I don’t think the XML data is ever read in.
When I make a WebGL Development Build, and run the application locally in Firefox, I receive this Debug information in the Firefox Browser Console:

And here the rest of the Debug Log:

The first part seems to indicate that the WebGL build doesn’t find the path the XML file is stored in. Not sure why though. For the rest, I have absolutely no idea how to interpret it as I am rather new to C# programming.

I would really appreciate any hint to a solution!

Thanks!

Sean

it looks like there is a slash at the beginning of the path, and a missing one after ‘file:/’. Which Unity version is this ?

Hi,

I am using Version 5.2.2f1. Is this a bug or is there something wrong with my code?

A small Update:

After reading this entry Unity - Scripting API: Application.streamingAssetsPath
in the documentation I converted my XMLDeserializer class to:

public class XMLDeserializer : MonoBehaviour
{
    public static DataCollection XmlData;

    public string filePath;

    public string result = "";


    IEnumerator Example()
    {
        if(filePath.Contains("://"))
        {
            WWW www = new WWW(filePath);
            yield return www;
            result = www.text;

            Debug.Log ("result: " +www.text);

            XmlData = DataCollection.DeSerialize(result);
        }
        else
        {
            XmlData = DataCollection.DeSerialize(filePath);
        }
    }
    void Awake ()
    {
        filePath = Path.Combine(Application.streamingAssetsPath, "hspositions.xml");

        StartCoroutine("Example");

    }

According to the Firefox Browser Controle, the path is now properly resolved with the other errors remaining:

Unforetunately the WebGL build still fails, even when I am doing a regular build, i.e. not a development build. I get the message:

" The browser could not allocate enought memory for the WebGL content. If you are the developer of this content, try allocating less memory to your WebGL build in the WebGL settings."

Currently I have it set to 512MB. Should I try even less?

Yes! How much do you need ? If you don’t know, the memory profiler “Reserved Total” will give you an idea (perhaps use a little extra to be safe)

Hm strange, I just closed Firefox and launched the index.html again and this time the application started without the memory error message. But the XML position data is still not being used. BUT I think it finally found the XML file. The Browser Console now reports:

That index out of range error is familiar to me. Could it be that the XML Serializer doesn’t like the List<> type in my DataCollection class? So it now seems to find the XML file, but can’t fill the Lists<> as it needs an array?

Since I’m using arrays, that index out of range error is gone, but the position data is still not used properly it seems. There are two errors remaining:

The Browser Console shows that the XML file is probably not read in in its entirety as the console windows displays only about half of the file contents. Not sure though if this is a certain indication that some contents weren’t loaded.

I now managed to read in the XML file. What I did was copy the XML file to the Assets/Resources which automatically converts the XML file into a TextAsset. Then I used Resources.Load to read the file. Here is my new DeSerialize() function:

    public static DataCollection DeSerialize()
    {
        using(TextReader textReader = new StringReader(Resources.Load<TextAsset>("hspositions").text))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataCollection));
          
            DataCollection XmlData = serializer.Deserialize(textReader) as DataCollection;

            return XmlData;
        }
    }

And simply calling it from another class like that:

void Awake()
{
XmlData = DataCollection.DeSerialize();
}

This did not work locally in Firefox, but only after I uploaded the WebGL files to a server.

1 Like

Cool, got it to work now with the XML in StreamingAssets. That even works locally in Firefox!

Here is the code:

    public static DataCollection DeSerialize(WWW www)
    {
        using(TextReader textReader = new StringReader(www.text))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataCollection));
          
            DataCollection XmlData = serializer.Deserialize(textReader) as DataCollection;

            return XmlData;
        }
    }

And the calling class:

public class XMLDeserializer : MonoBehaviour
{
    public static DataCollection XmlData;

    public static string filePath;

    IEnumerator ParseXML()
    {
        if(filePath.Contains("://"))
        {
            WWW www = new WWW(filePath);
            yield return www;

            XmlData = DataCollection.DeSerialize(www);
        }
        else
        {
            XmlData = DataCollection.DeSerialize(filePath);
        }
    }
    void Awake ()
    {
        filePath = Path.Combine(Application.streamingAssetsPath, "hspositions.xml");

        StartCoroutine("ParseXML");
    }

So basically I created an overload for the DeSerialize() method taking in a WWW object as paramter. Within the DeSerialize() method I’m then creating a TextReader with www.text as parameter which in turn I feed into the XmlSerializer. Hope this helps!

1 Like

how to download file using url ?