Home > OS >  XML Reading returning an empty object. (XML Localization File)
XML Reading returning an empty object. (XML Localization File)

Time:07-21

C# (CSharp/.cs) 7.0
.NET Framework 4.7.2

I'm making a Localization system for a mod (based on the game's language), so I used an XML file to store translations, which look like this :

<?xml version="1.0" encoding="utf-16" ?>
<LocalizationPackages>
    <LocalizationPackage Lang="English">
        <Text key="Ency_PrawnLaserArm">Prawn Laser module</Text>
        <Text key="EncyDesc_PrawnLaserArm">Description</Text>
        <Text key="EncyPath_Weaponry">Weaponry</Text>
        <Text key="ExplosiveTorpedoItemName">Explosive torpedo</Text>
        <Text key="ExplosiveTorpedoItemTooltip">A new lethal weapon designed by Alterra© for missions on 4546B after the result of previous Alterra© missions.</Text>
    </LocalizationPackage>
    <LocalizationPackage Lang="French">
        <Text key="Ency_PrawnLaserArm">Module laser pour Prawn</Text>
        <Text key="EncyDesc_PrawnLaserArm">Description</Text>
        <Text key="EncyPath_Weaponry">Armement</Text>
        <Text key="ExplosiveTorpedoItemName">Torpille explosive</Text>
        <Text key="ExplosiveTorpedoItemTooltip">Une nouvelle arme létale designée par Alterra® pour les missions sur 4546B après le résultat de la mission Alterra précédente sur la planète.</Text>
    </LocalizationPackage>
</LocalizationPackages>

However, while reading the XML file with my own system based on what I saw on the Microsoft Documentation, it returns a totally empty object.

using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Reflection;

using SMLHelper.V2.Handlers;
using Logger = QModManager.Utility.Logger;

namespace VELDsAlterraWeaponry
{
    namespace LocalizationHandler
    {
        [XmlRoot("LocalizationPackages")]
        public class LocalizationPackages
        {
            [XmlArray("LocalizationPackage")]
            public LocalizationPackage[] Localizations;
        }

        /// <summary>
        /// LocalizationPackage is a Localization Package ref - 
        /// </summary>
        public class LocalizationPackage
        {
            [XmlAttribute("Lang")]
            public string Lang;

            [XmlArray("Text")]
            public Text[] Texts;
        }

        public class Text
        {
            [XmlAttribute]
            public string key;

            public string value;
        }
    }

    class LanguagesHandler
    {
        // This is the path to my mod directory, this is the default schema for this modloader.
        private static string ModPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

        // This is the filename of my Localizations file
        private static string filename = "Localizations.xml";

        // This is the function that patch the language through the game, but we do not care about this.
        public static void LanguagePatch()
        {
            Logger.Log(Logger.Level.Info, "Starting patching the languages !");
            XmlSerializer serializer = new XmlSerializer(typeof(LocalizationHandler.LocalizationPackages));

            FileStream fs = new FileStream(Path.Combine(ModPath, filename), FileMode.Open);

            // My LocalizationPackage, that SHOULD be read and set by the definition some lines under...
            LocalizationHandler.LocalizationPackages lps;

            // This logs the current language of the game (prints "French" for me)
            Logger.Log(Logger.Level.Info, Language.main.GetCurrentLanguage());

            // Redefines normally the lps with the datas of the XML ?
            lps = (LocalizationHandler.LocalizationPackages)serializer.Deserialize(fs);

            // Have to log each Localization Lang name
            foreach (LocalizationHandler.LocalizationPackage lockalizationpack in lps.Localizations) Logger.Log(Logger.Level.Info, lockalizationpack.Lang);
            Logger.Log(Logger.Level.Info, "All LPs logged.");

            // Have to set each label in game with the value of the XML.
            // Do not care too lot about that, it's mainly managed by the SMLHelper lib.
            foreach(LocalizationHandler.Text text in lps.Localizations.Single(lp => lps.Localizations.Any(lp1 => lp1.Lang == Language.main.GetCurrentLanguage()) ? lp.Lang == Language.main.GetCurrentLanguage() : lp.Lang == Language.defaultLanguage).Texts)
            {
                Logger.Log(Logger.Level.Info, $"Checking string, key {text.key}");
                if (Language.main.Get(text.key) != null)
                {
                    LanguageHandler.SetLanguageLine(text.key, text.value);
                    Logger.Log(Logger.Level.Info, $"Patched key {text.key} with text '{(text.value.Length > 50 ? text.value.Substring(50) : text.value)}'");
                } 
                else
                {
                    Logger.Log(Logger.Level.Warn, $"Key {text.key} does not reference any key in game. Please check the case.");
                }
            }
            Logger.Log(Logger.Level.Info, "Language patching done.");
        }
    }
}

And when I try logging all the LocalizationPackages, it does not log anything, and immediately print "All LPs logged.". (foreach (LocalizationHandler.LocalizationPackage lockalizationpack in lps.Localizations) Logger.Log(Logger.Level.Info, lockalizationpack.Lang);)
So, where's my error ? Did I did something wrong with my classes ? My reading system is obsolete ?
(please don't be rude, I'm a very beginner in C#, I started 5 days ago C# with this project)

CodePudding user response:

Code below works. [XmlArray] expect two levels of tags . So use [XmlElement] when you have only one level of tags. Also added [XmlText]

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApp2
{
    class Program
    {

        const string FILENAME = @"c:\temp\test.xml";

        static void Main(string[] args)
        {
            StreamReader reader = new StreamReader(FILENAME);
            reader.ReadLine();  //skip utf-16
            XmlSerializer serializer = new XmlSerializer(typeof(LocalizationPackages));
            LocalizationPackages packages = (LocalizationPackages)serializer.Deserialize(reader);

        }

    }
    [XmlRoot("LocalizationPackages")]
    public class LocalizationPackages
    {
        [XmlElement("LocalizationPackage")]
        public LocalizationPackage[] Localizations;
    }

    public class LocalizationPackage
    {
        [XmlAttribute("Lang")]
        public string Lang;

        [XmlElement("Text")]
        public Text[] Texts;
    }

    public class Text
    {
        [XmlAttribute]
        public string key;
        [XmlText]
        public string value;
    }

}
  • Related