2012-02-03 1 views
2

Я пытаюсь сохранить XML-документ, и я пытался заставить свой код работать, но моно выплескивает очень странную ошибку. Я дал файл, который он пытается сохранить в полной собственности.Ошибка сохранения XDocument в моно "Этот XmlWriter не принимает текст в этом состоянии Prolog."

Примером может быть 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> 
+1

Как вы называете этот код? И не могли ли вы опубликовать только соответствующие биты кода? – svick

+0

Извините. Я новичок в этом. Ошибка вызывается в ' "d.Save (значения [key.ToLower()] SourceFile.);"' и я называю этот код ' "server.settings [" group.test.test» ] = «Привет, мир!»; ' –

+0

+1 для svick. Да, сведение к минимуму кода, вызывающего проблему, будет чрезвычайно полезным. Эта проблема может быть воспроизведена в 1 или 2 строках кода, как указано в [этот вопрос] (http://stackoverflow.com/questions/9157642/mono-xdocument-load-fails-with-loadoptions-preservewhitespace). Cheers and happing code – cod3monk3y

ответ

2

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

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

вместо этого

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

позволит ей сохранить должным образом.

+0

Одинаковая проблема здесь. Я пишу скрипт сборки для изменения информации.plist для MonoTouch для автоматического обновления номера версии из моей сборки Jenkins. Поскольку файл хранится в git, я бы скорее сохранил пробел в такте. – cod3monk3y

+0

См. [Mono-xdocument-load-fail-with-loadoptions-preservewhitespace] (http://stackoverflow.com/questions/9157642/mono-xdocument-load-fails-with-loadoptions-preservewhitespace) для легкого обходного пути, если вы хотите сохранить пробелы: 'doc.Root.Save (" out.xml ")' – cod3monk3y

1

Вы можете проверить кодировки файлов, которые вы читали и как написано это может быть порядок байтов знак, что делает XmlWriter идут гайки

+0

Это UTF-8 и не имеет BOM (я проверил через шестнадцатеричный), я использую linux. –

1

Я смог найти другое обходное решение, сохраняя пробелы. Очевидно, что 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.

 Смежные вопросы

  • Нет связанных вопросов^_^