0

Here is the error message:

XmlException: Root element is missing.
System.Xml.XmlTextReaderImpl.Throw (System.Exception e) (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.XmlTextReaderImpl.ThrowWithoutLineInfo (System.String res) (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.XmlTextReaderImpl.ParseDocumentContent () (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.XmlTextReaderImpl.Read () (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.XmlTextReader.Read () (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.XmlReader.MoveToContent () (at <3df1727680a4410c8922c5d71cde3a04>:0)
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderActorContainer.Read4_ActorCollection () (at <c06125c6813e448a84b3586be54913c5>:0)
System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <e40e5a8f982c4b618a930d29f9bd091c>:0)
Rethrow as InvalidOperationException: There is an error in XML document (0, 0).
System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.XmlReader xmlReader, System.String encodingStyle, System.Xml.Serialization.XmlDeserializationEvents events) (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.XmlReader xmlReader, System.String encodingStyle) (at <3df1727680a4410c8922c5d71cde3a04>:0)
System.Xml.Serialization.XmlSerializer.Deserialize (System.IO.Stream stream) (at <3df1727680a4410c8922c5d71cde3a04>:0)
GenshinImpactMovementSystem.SaveData.LoadActors (System.String path) (at Assets/GenshinImpactMovementSystem/Scripts/Characters/Player/Data/XML/SaveData.cs:54)
GenshinImpactMovementSystem.SaveData.Load (System.String path) (at Assets/GenshinImpactMovementSystem/Scripts/Characters/Player/Data/XML/SaveData.cs:19)
GenshinImpactMovementSystem.GameController+<>c.<OnEnable>b__9_1 () (at Assets/GenshinImpactMovementSystem/Scripts/Controllers/GameController.cs:76)
UnityEngine.Events.InvokableCall.Invoke () (at <4a31731933e0419ca5a995305014ad37>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <4a31731933e0419ca5a995305014ad37>:0)
UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:501)

I am not sure on what the error is but I think its because the xml file is blank but in the tutorial the code should already be written. There are 4 scripts that I am using to create the saving and loading system.

Actor script:

using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;

namespace GenshinImpactMovementSystem
{
public class Actor : MonoBehaviour
{
    public ActorData data =  new ActorData();

    public string name = "actor";

    public void StoreData()
    {
        data.name = name;
        Vector3 pos = transform.position;
        data.posX = pos.x;
        data.posY = pos.y;
        data.posZ = pos.z;
    }

    public void LoadData()
    {
        name = data.name;
        transform.position = new Vector3(data.posX, data.posY, data.posZ);
    }

    void OnEnable() 
    {
        SaveData.OnLoaded += delegate { LoadData(); };
        SaveData.OnBeforeSave += delegate { StoreData(); };
        SaveData.OnBeforeSave += delegate { SaveData.AddActorData(data); };
    }

    void OnDisable() 
    {
        SaveData.OnLoaded -= delegate { LoadData(); };
        SaveData.OnBeforeSave -= delegate { StoreData(); };
        SaveData.OnBeforeSave -= delegate { SaveData.AddActorData(data); };
    }
}

public class ActorData
{
    [XmlAttribute("Name")]
    public string name;
    
    [XmlElement("PosX")]
    public float posX;

    [XmlElement("PosY")]
    public float posY;

    [XmlElement("PosZ")]
    public float posZ;
}
}

Actor container script:

using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;

namespace GenshinImpactMovementSystem
{
    [XmlRoot("ActorCollection")]
    public class ActorContainer 
    {
        [XmlArray("Actors")]
        [XmlArrayItem("Actor")]
        public List<ActorData> actors = new List<ActorData>();
    }
}

Save data script:

using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using UnityEngine;

namespace GenshinImpactMovementSystem
{
    public class SaveData
    {
        public static ActorContainer actorContainer = new ActorContainer();

        public delegate void SerializeAction();
        public static event SerializeAction OnLoaded;
        public static event SerializeAction OnBeforeSave;

        public static void Load(string path)
        {
            actorContainer = LoadActors(path);

            foreach (ActorData data in actorContainer.actors)
            {
                GameController.CreateActor(data, GameController.playerPath, new Vector3(data.posX, data.posY, data.posZ), Quaternion.identity);
            }

            OnLoaded();
        }

        public static void Save(string path, ActorContainer actors)
        {
            OnBeforeSave();

            SaveActors(path, actors);

            ClearActors();
        }

        public static void AddActorData(ActorData data)
        {
            actorContainer.actors.Add(data);
        }

        public static void ClearActors()
        {
            actorContainer.actors.Clear();
        }

        private static ActorContainer LoadActors(string path)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(ActorContainer));

            FileStream stream = new FileStream(path, FileMode.Create);

            ActorContainer actors = serializer.Deserialize(stream) as ActorContainer;

            stream.Close();

            return actors;
        }

        private static void SaveActors(string path, ActorContainer actors)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(ActorContainer));

            FileStream stream = new FileStream(path, FileMode.Open);

            serializer.Serialize(stream, actors);

            stream.Close();
        }
    }
}

Game controller:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cinemachine;
using TMPro;

namespace GenshinImpactMovementSystem
{
    public class GameController : MonoBehaviour
    {
        public Button saveButton;
        public Button loadButton;

        public CinemachineVirtualCamera camera;

        public const string playerPath = "Prefabs/Player";

        private static string dataPath = string.Empty;

        void Awake() 
        {
            if (Application.platform == RuntimePlatform.IPhonePlayer)
            {
                dataPath = System.IO.Path.Combine(Application.persistentDataPath, "GenshinImpactMovementSystem/Resources/actors.xml");
            }
            else
            {
                dataPath = System.IO.Path.Combine(Application.dataPath, "GenshinImpactMovementSystem/Resources/actors.xml");
            }
        }

        void Start()
        {
            CreateActor(playerPath, new Vector3(0, 0, 0), Quaternion.identity);
        }

        public static Actor CreateActor(string path, Vector3 position, Quaternion rotation)
        {
            GameObject prefab = Resources.Load<GameObject>(path);

            GameObject go = GameObject.Instantiate(prefab, position, rotation) as GameObject;

            Player playerScript = go.GetComponent<Player>();
            
            Transform cameraLookAt = playerScript.cameraPointLookAt;

            CinemachineVirtualCamera cam = FindObjectOfType<CinemachineVirtualCamera>();

            cam.Follow = cameraLookAt;
            cam.LookAt = cameraLookAt;

            playerScript.CameraRecenteringUtility.VirtualCamera = cam;

            Actor actor = go.GetComponent<Actor>() ?? go.AddComponent<Actor>();

            return actor;
        }

        public static Actor CreateActor(ActorData data, string path, Vector3 position, Quaternion rotation)
        {
            GameObject prefab = Resources.Load<GameObject>(path);

            GameObject go = GameObject.Instantiate(prefab, position, rotation);

            Actor actor = go.GetComponent<Actor>() ?? go.AddComponent<Actor>();

            actor.data = data;

            return actor;
        }

        void OnEnable()
        {
            saveButton.onClick.AddListener(delegate {SaveData.Save(dataPath, SaveData.actorContainer);});
            loadButton.onClick.AddListener(delegate {SaveData.Load(dataPath);});
        }

        void OnDisable()
        {
            saveButton.onClick.RemoveListener(delegate {SaveData.Save(dataPath, SaveData.actorContainer);});
            loadButton.onClick.RemoveListener(delegate {SaveData.Load(dataPath);});
        }
    }
}
  • `XmlException: Root element is missing.` does indeed mean the file is empty. So what is your question exactly? Did you debug your program to see if the file was previously created properly? Can you share a [mcve] demonstrating the problem? – dbc Aug 19 '22 at 19:41
  • In `LoadActors(string path)` you do `new FileStream(path, FileMode.Create);`. Shouldn't that be `FileMode.Open`? Similarly in `SaveActors(string path, ActorContainer actors)` you do `new FileStream(path, FileMode.Open);` but you probably want `FileMode.Create`, – dbc Aug 19 '22 at 23:56

1 Answers1

0

XML well-formedness rules call for exactly one root element.

This example document is valid:

<doc>
  <entry>...</entry>
  <entry>...</entry>
</doc>

This example document is invalid because there's more than one top-level element:

<entry>...</entry>
<entry>...</entry>
Keyacom
  • 94
  • 5
  • XML specification allows for arrays at root which is not well formed. Net library gives errors when xml is not well formed unless you use XmlReader and change XmlReaderSettings : settings.ConformanceLevel = ConformanceLevel.Fragment; – jdweng Aug 20 '22 at 07:50