Ошибка сохранения XDocument в Mono «Этот XmlWriter не принимает текст в этом состоянии Пролог». - PullRequest
2 голосов
/ 04 февраля 2012

Я пытаюсь сохранить документ в формате xml и пытаюсь заставить свой код работать, но mono выдает очень странную ошибку. Я дал файл, который он пытается сохранить в полную собственность.

Примером может быть group.test.test для «Hello world!»

Вот код:

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

namespace Classic6
{
public class XmlSettings
{
    private Dictionary<string, XmlSetting> Values { get; set; }
    private string[] SettingFiles;
    public bool EnableSaving { get; set; }
    public event EventHandler<SettingChangedEventArgs> OnSettingChanged;
    /// <summary>
    /// The location of the XML file that new keys
    /// should be stored in (when a key is added
    /// via XmlSettings["key"] without a file, it
    /// will be saved here.
    /// </summary>
    public static string DefaultFile { get; set; }

    public XmlSettings()
    {
        Values = new Dictionary<string, XmlSetting>();
        EnableSaving = false;
    }

    public void Load(string SettingsDirectory)
    {
        SettingFiles = Directory.GetFiles(SettingsDirectory, "*.xml", SearchOption.AllDirectories);
        foreach (string file in SettingFiles)
        {
            try
            {
                Stream s = File.Open(file, FileMode.Open);
                XDocument d = XDocument.Load(s);
                s.Close();
                LoadRecursive(d.Root, file, string.Empty);
            }
            catch { }
        }

        if (string.IsNullOrEmpty(DefaultFile))
            DefaultFile = Path.Combine(SettingsDirectory, "bla.xml.bak.invalid");
    }

    private void LoadRecursive(XElement root, string sourceFile, string path)
    {
        foreach (XElement e in root.Elements())
        {
            if (e.Elements().Count() != 0)
                LoadRecursive(e, sourceFile, path + e.Name + ".");
            foreach (XAttribute a in e.Attributes())
            {
                Values[(path + e.Name.LocalName.ToString() + "." +
                    a.Name.LocalName.ToString()).ToLower()] = new XmlSetting(sourceFile, a.Value, true);
            }
            if (Values.ContainsKey((path + e.Name.LocalName.ToString()).ToLower()))
            {
                if (Values[(path + e.Name.LocalName.ToString()).ToLower()].Value != e.Value)
                {
                    if (OnSettingChanged != null)
                        OnSettingChanged(this, new SettingChangedEventArgs((path + e.Name.LocalName.ToString()).ToLower(),
                            Values[(path + e.Name.LocalName.ToString()).ToLower()].Value, e.Value));
                }
            }
            Values[(path + e.Name.LocalName.ToString()).ToLower()] = new XmlSetting(sourceFile, e.Value, false);
        }
    }

    public int GetInt(string Key)
    {
        int i = -1;
        if (!int.TryParse(this[Key], out i) && !Key.StartsWith("command") && !Key.Contains("port"))
            Server.server.Log("Setting error: " + Key + " is not a valid integer.");
        return i;
    }

    public bool GetBool(string Key)
    {
        bool b = false;
        if (!bool.TryParse(this[Key], out b))
            Server.server.Log("Setting error: " + Key + " is not a valid boolean.");
        return b;
    }

    public bool ContainsKey(string Key)
    {
        return Values.ContainsKey(Key.ToLower());
    }

    public string this[string key]
    {
        get
        {
            if (!Values.ContainsKey(key.ToLower()))
                return "";
            return Values[key.ToLower()].Value;
        }
        set
        {
            if (OnSettingChanged != null)
                OnSettingChanged(this, new SettingChangedEventArgs(key, Values.ContainsKey(key.ToLower()) ? Values[key.ToLower()].Value : DefaultFile, value));
            if (Values.ContainsKey(key))
                Values[key.ToLower()].Value = value;
            else
                Values[key.ToLower()] = new XmlSetting(DefaultFile, value, false);

            if (string.IsNullOrEmpty(DefaultFile))
                return;
            if (!EnableSaving)
                return;

            XDocument d = new XDocument();

            if (File.Exists(Values[key.ToLower()].SourceFile))
            {
                Stream s = File.Open(Values[key.ToLower()].SourceFile, FileMode.OpenOrCreate);
                d = XDocument.Load(s, LoadOptions.PreserveWhitespace);
                s.Close();
            }
            else
            {
                d = new XDocument();
                d.Add(new XElement("Classic6"));
            }
            // Locate this property
            string[] parts = key.ToLower().Split('.');
            XElement currentElement = d.Root;
            for (int i = 0; i < parts.Length; i++ )
            {
                bool found = false;
                if (parts.Length - 1 == i)
                {
                    foreach (XAttribute a in currentElement.Attributes())
                    {
                        if (a.Name.LocalName.ToLower() == parts[i])
                        {
                            found = true;
                            break;
                        }
                    }
                }
                foreach (XElement e in currentElement.Elements())
                {
                    if (e.Name.LocalName.ToLower() == parts[i])
                    {
                        currentElement = e;
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    XElement el = new XElement(parts[i]);
                    currentElement.Add(el);
                    currentElement = el;
                }
            }
            if (Values[key.ToLower()].IsAttribute)
                currentElement.SetAttributeValue(parts[parts.Length - 1], Values[key.ToLower()].Value);
            else
                currentElement.SetValue(Values[key.ToLower()].Value);

            d.Save(Values[key.ToLower()].SourceFile);
        }
    }
}

internal class XmlSetting
{
    public string SourceFile { get; set; }
    public string Value { get; set; }
    public bool IsAttribute { get; set; }

    public XmlSetting(string SourceFile, string Value, bool IsAttribute)
    {
        this.SourceFile = SourceFile;
        this.Value = Value;
        this.IsAttribute = IsAttribute;
    }
}

public class SettingChangedEventArgs : EventArgs
{
    public string Key { get; set; }
    public string OldValue { get; set; }
    public string NewValue { get; set; }

    public SettingChangedEventArgs(string Key, string OldValue, string NewValue)
    {
        this.Key = Key;
        this.OldValue = OldValue;
        this.NewValue = NewValue;
    }
}
}

Вот ошибка, которую он мне дает:

Unhandled Exception: System.InvalidOperationException: This XmlWriter does not accept Text at this state Prolog.
at System.Xml.XmlTextWriter.ShiftStateContent (System.String occured, Boolean allowAttribute) [0x00000] in <filename unknown>:0 
at System.Xml.XmlTextWriter.WriteString (System.String text) [0x00000] in <filename unknown>:0 
at System.Xml.DefaultXmlWriter.WriteString (System.String text) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XText.WriteTo (System.Xml.XmlWriter w) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.WriteTo (System.Xml.XmlWriter w) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.Save (System.Xml.XmlWriter w) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.Save (System.String filename, SaveOptions options) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.Save (System.String filename) [0x00000] in <filename unknown>:0 
at Classic6.XmlSettings.set_Item (System.String key, System.String value) [0x00000] in <filename unknown>:0 
at Classic6.CmdSettings.Use (Classic6.RemoteClient c, System.String message) [0x00000] in <filename unknown>:0 
at Classic6.ClassicServer.HandleCommand (Classic6.RemoteClient c, System.String msg) [0x00000] in <filename unknown>:0 
at Classic6Server.Program.ParseInput (System.String input) [0x00000] in <filename unknown>:0 
at Classic6Server.Program.Main () [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: This XmlWriter does not accept Text at this state Prolog.
at System.Xml.XmlTextWriter.ShiftStateContent (System.String occured, Boolean allowAttribute) [0x00000] in <filename unknown>:0 
at System.Xml.XmlTextWriter.WriteString (System.String text) [0x00000] in <filename unknown>:0 
at System.Xml.DefaultXmlWriter.WriteString (System.String text) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XText.WriteTo (System.Xml.XmlWriter w) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.WriteTo (System.Xml.XmlWriter w) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.Save (System.Xml.XmlWriter w) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.Save (System.String filename, SaveOptions options) [0x00000] in <filename unknown>:0 
at System.Xml.Linq.XDocument.Save (System.String filename) [0x00000] in <filename unknown>:0 
at Classic6.XmlSettings.set_Item (System.String key, System.String value) [0x00000] in <filename unknown>:0 
at Classic6.CmdSettings.Use (Classic6.RemoteClient c, System.String message) [0x00000] in <filename unknown>:0 
at Classic6.ClassicServer.HandleCommand (Classic6.RemoteClient c, System.String msg) [0x00000] in <filename unknown>:0 
at Classic6Server.Program.ParseInput (System.String input) [0x00000] in <filename unknown>:0 
at Classic6Server.Program.Main () [0x00000] in <filename unknown>:0

и в xml-файле он полностью перезаписывает его и оставляет только следующее:

<?xml version="1.0" encoding="utf-8"?>

, который сильно отличается от этого:

<?xml version="1.0" encoding="utf-8" ?>
<Classic6>
  <group>
   <test>Will I change</test>
   <well>I hope so</well>
  </group>
</Classic6>

Ответы [ 3 ]

2 голосов
/ 06 февраля 2012

Мы поняли это: Mono плохо играет с пробелами, по-видимому, так:

            d = XDocument.Load(s, LoadOptions.None);

вместо этого

            d = XDocument.Load(s, LoadOptions.PreserveWhitespace);

позволит сохранить его правильно.

1 голос
/ 08 февраля 2012

Мне удалось найти другой обходной путь при сохранении пробелов. Очевидно, что Mono не удается сохранить XDocument, который был открыт с использованием LoadOptions.PreserveWhitespace . Кажется, это ошибка в реализации Mono во время выполнения. Потому что я не сталкивался с какими-либо проблемами в реализации MS CLR на платформе Windows.

Обходной путь выглядит следующим образом: (Здесь вы все еще можете использовать LoadOptions.PreserveWhitespace в методе XDocument.Load)

d.Root.Save(Values[key.ToLower()].SourceFile);

Вместо использования

d.Save(Values[key.ToLower()].SourceFile);

Это хорошо работает для меня при использовании компилятора Mono JIT версии 2.10.5 на платформе Ubuntu 11.10.

1 голос
/ 04 февраля 2012

Можете ли вы проверить кодировки прочитанных файлов и то, как они записаны, это может быть знак порядка байтов, который делает xmlwriter сумасшедшим

...