6 Replies - 4771 Views - Last Post: 06 February 2012 - 04:16 AM Rate Topic: -----

#1 Snowl  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 5
  • Joined: 03-February 12

XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 03 February 2012 - 07:27 PM

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>



The error is called at
"d.Save(Values[key.ToLower()].SourceFile);"

and I call this code by
"Server.Settings["group.test.test"] = "Hello world!";


I'm at my wits end to fix this... any help would be very very appreciated.

Is This A Good Question/Topic? 0
  • +

Replies To: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

#2 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6052
  • View blog
  • Posts: 23,487
  • Joined: 23-August 08

Re: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 04 February 2012 - 02:32 PM

Two suggestions:

1. Run the program in a debugger and set a breakpoint on the Save call. Investigate the state of the d at that point.

Failing the ability to do that, use Console.WriteLine(d.ToString()); to find out what's in the object.
Was This Post Helpful? 0
  • +
  • -

#3 Snowl  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 5
  • Joined: 03-February 12

Re: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 04 February 2012 - 02:52 PM

I'm not too sure how to get the state of d when I put a breakpoint on it and monodevelop only gives me System.InvalidOperationException, no options:

Posted Image

Doing Console.WriteLine(d.ToString()); gives me this:
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.XNode.ToString (SaveOptions options) [0x00000] in <filename unknown>:0 
  at System.Xml.Linq.XNode.ToString () [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 


Was This Post Helpful? 0
  • +
  • -

#4 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6052
  • View blog
  • Posts: 23,487
  • Joined: 23-August 08

Re: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 04 February 2012 - 04:13 PM

You could try stepping through the code? I don't know much about LINQ and XDocument, so I can't be a terrible lot of help.

This is the relevant code, right?

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


Suggest changing this
if (string.IsNullOrEmpty(DefaultFile) || !EnableSaving)
    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"));
}


to

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

XDocument d = null;

if (File.Exists(Values[key.ToLower()].SourceFile))
{
    using (Stream s = File.Open(Values[key.ToLower()].SourceFile, FileMode.OpenOrCreate))
    {
        // Creates new instance of an XDocument from the loaded stream data
        d = Xdocument.Load(s, LoadOptions.PreserveWhitespace);
    }
}
else
{
    // Create a new XDocument from scratch, starting with the prolog/declaration 
    // and an initialized parent element
    d = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),new XElement("Classic6"));
}

Was This Post Helpful? 0
  • +
  • -

#5 Snowl  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 5
  • Joined: 03-February 12

Re: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 06 February 2012 - 02:56 AM

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

Was This Post Helpful? 1
  • +
  • -

#6 RexGrammer  Icon User is offline

  • Coding Dynamo
  • member icon

Reputation: 181
  • View blog
  • Posts: 777
  • Joined: 27-October 11

Re: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 06 February 2012 - 04:02 AM

On a side note:

What IDE are you using?
Was This Post Helpful? 0
  • +
  • -

#7 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6052
  • View blog
  • Posts: 23,487
  • Joined: 23-August 08

Re: XDocument Saving in Mono “XmlWriter does not accept Text at Prolog"

Posted 06 February 2012 - 04:16 AM

Quote

What IDE are you using?

Quote

I'm not too sure how to get the state of d when I put a breakpoint on it and monodevelop only gives me System.InvalidOperationException, no options:


Glad you got it figured out, and thanks for letting us know the solution!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1