XDocument Saving Error in Mono”;此XmlWriter不接受处于Prolog状态的Text

本文关键字:不接受 Prolog 状态 Text XmlWriter Error Saving in Mono XDocument | 更新日期: 2023-09-27 18:22:20

我正在尝试保存一个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>

XDocument Saving Error in Mono”;此XmlWriter不接受处于Prolog状态的Text

我们发现:Mono显然不能很好地处理空白,所以这样做:

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

而不是这个

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

将使其正确保存。

你能检查你读取的文件的编码以及它是如何写的吗?可能是字节顺序标记让xmlwriter发疯了。

我在保留空白的同时找到了另一种解决方法。很明显,Mono无法保存使用LoadOptions.PreserveWhitespace打开的XDocument。这似乎是Mono运行时实现中的一个错误。因为,我在Windows平台上实现MS CLR时没有遇到任何问题。

解决方法如下:(在这里,您仍然可以在XDocument.Load方法中使用LoadOptions.PreserveWhitespace

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

而不是使用

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

在Ubuntu 11.10平台上使用MonoJIT编译器2.10.5版本对我来说效果很好。