Mono 中的 XDocument 保存错误“此 XmlWriter 在 Prolog 状态下不接受文本。”

发布于 2025-01-02 12:10:42 字数 10221 浏览 0 评论 0原文

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

I am trying to save an xml document, and I have been trying to get my code to work but mono is spitting out a very strange error. I have given the file it is trying to save to full ownership.

An example would be group.test.test to "Hello world!"

Here is the code:

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;
    }
}
}

Here is the error it gives me:

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

and in the xml file it overwrites it completely and only leaves this:

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

which is a lot different from this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

玻璃人 2025-01-09 12:10:42

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

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

而不是这样做,

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

可以让它正确保存。

We figured it out: Mono doesn't play well with whitespace, apparently, so doing this:

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

instead of this

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

will let it save properly.

陌若浮生 2025-01-09 12:10:42

您可以检查您读取的文件的编码以及它的写入方式吗?可能是字节顺序标记使 xmlwriter 发疯

Can you check the encodings of the files you read and how it is written it might be byte order mark that makes the xmlwriter go nuts

梦开始←不甜 2025-01-09 12:10:42

我能够在保留空格的同时找到另一种解决方法。很明显,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 平台上使用 Mono JIT 编译器版本 2.10.5 效果很好。

I was able to find out an another workaround while preserving whitespaces. It is evident that Mono fails to save XDocument that was opened using LoadOptions.PreserveWhitespace. It seems to be a bug in Mono runtime implementation. Because, I didn't encounter any issues in MS CLR implementation on Windows platform.

The workaround is as below: (Here, you can still using LoadOptions.PreserveWhitespace in XDocument.Load method)

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

Instead of using

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

It works well for me using Mono JIT compiler version 2.10.5 on Ubuntu 11.10 platform.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文