Laden...

Exception: Zu viele Stummelstücke in XML

Erstellt von xasz vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.042 Views
X
xasz Themenstarter:in
11 Beiträge seit 2011
vor 12 Jahren
Exception: Zu viele Stummelstücke in XML

Hallo Leute,

ich schreibe gerade eine kleine Funktion, die mir eine xml-file parst.

Leider bekomme ich immer ne Exception an den Kopf geworfen mit der ich nichts anfangen kann.
Sie besagt, dass zu viele Stummelstücke in meinem File sind in Zeile 2 Postion 2.

Meine XML-File sieht so aus:

<LogInfo Time="06.07.2011 16:03:20" Error="False" Body="Syncronisierung wird gestartet" />
<LogInfo Time="06.07.2011 16:03:21" Error="False" Body="Syncronisierung erfolgreich abgeschlossen." />

Meine Readfunktion sieht so aus:

        public EventInfo[] getEventsFromLog(ProgrammOptionenKeeper pok)
        {
            List<EventInfo> events = new List<EventInfo>();
            string path = pok.JobFolder + "\\" + myjobid + "\\eventlog.xml";
            if (File.Exists(path))
            {
                FileStream fs = new FileStream(path,FileMode.Open);
                XmlTextReader r = new XmlTextReader(fs);
                
                    EventInfo info = new EventInfo();
                    try
                    {
                        while (r.Read())
                        {
                            if (r.Name == "LogInfo")
                            {
                                events.Add(new EventInfo(r.GetAttribute("Body"), Convert.ToBoolean(r.GetAttribute("Error")), Convert.ToDateTime(r.GetAttribute("Time"))));
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        string bla = ex.Message;
                    }
                    fs.Close();
                    return events.ToArray();
                             
            }
            return null;            
        }

Ich sitz jetzt seit mehreren Stunden dran und schaffe es einfach nicht, das Teil einzulesen.

Rausschreiben tue ich es übrigens mit dieser Funktion:

        public void LogEvent(string line, bool error, ProgrammOptionenKeeper pok)
        {

            string path = pok.JobFolder + "\\" + myjobid + "\\eventlog.xml";

            StringBuilder sbuilder = new StringBuilder();
            using (StringWriter sw = new StringWriter(sbuilder))
            {
                using (XmlTextWriter w = new XmlTextWriter(sw))
                {
                    w.WriteStartElement("LogInfo");
                    w.WriteAttributeString("Time", DateTime.Now.ToString());
                    w.WriteAttributeString("Error", error.ToString());
                    w.WriteAttributeString("Body", line);
                    w.WriteEndElement();
                }
            }
            using (StreamWriter w = new StreamWriter(path, true, Encoding.UTF8))
            {
                w.WriteLine(sbuilder.ToString());
            }
        }

Vielleicht habt ihr ne Idee, was ich falsch mache.

Vielen Dank schon mal.

grüße xasz

2.298 Beiträge seit 2010
vor 12 Jahren

Warum arbeitest du nicht einfach mit Serialisierung?

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo inflames2k,

Warum arbeitest du nicht einfach mit Serialisierung?

weil es kein korrektes XML ist und daher nicht gelesen werden kann.

Hallo xasz,

bitte die Fehlermeldung immer mitangeben. Da stehen nützliche Infos drin. Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 5.

Aber wenn ich das XML sehe so denke ich dass ich weiß worum es geht 😃
Es fehlen die Wurzel-Elemente bzw. die gesamte Hierarchie, da nur Elemente drin sind. Um es trotzdem zu lesen vewende diese Klasse (ist hier internal da ich es so gebraucht habe):


[System.Diagnostics.DebuggerNonUserCode]
internal sealed class XmlFragmentTextReader : TextReader
{
	private enum Location
	{
		RootOpen,
		Fragment,
		RootClose
	}
	//---------------------------------------------------------------------
	private StreamReader _fragmentReader;
	private Location _location = Location.RootOpen;
	private int _index = 0;
	private char[] _rootOpenBuffer;
	private char[] _rootCloseBuffer;
	//---------------------------------------------------------------------
	#region Konstruktor
	internal XmlFragmentTextReader(StreamReader reader, string rootElementName)
	{
		_fragmentReader = reader;
		_rootOpenBuffer = string.Format(
			"<{0}>\r\n",
			rootElementName).ToCharArray();
		_rootCloseBuffer = string.Format(
			"\r\n</{0}>",
			rootElementName).ToCharArray();
	}
	//---------------------------------------------------------------------
	internal XmlFragmentTextReader(Stream stream, string rootElementName)
		: this(new StreamReader(stream), rootElementName) { }
	#endregion
	//---------------------------------------------------------------------
	public override int Peek()
	{
		switch (_location)
		{
			case Location.RootOpen:
				return _rootOpenBuffer[_index];
			case Location.Fragment:
				return _fragmentReader.Peek();
			case Location.RootClose:
				return _rootCloseBuffer[_index];
			default:
				return -1;
		}
	}
	//---------------------------------------------------------------------
	public override int Read()
	{
		switch (_location)
		{
			case Location.RootOpen:
				if (_index < _rootOpenBuffer.Length)
					return _rootOpenBuffer[_index++];
				else
				{
					_location = Location.Fragment;
					return Read();
				}
			case Location.Fragment:
				if (!_fragmentReader.EndOfStream)
					return _fragmentReader.Read();
				else
				{
					_location = Location.RootClose;
					_index = 0;
					return Read();
				}
			case Location.RootClose:
				if (_index < _rootCloseBuffer.Length)
					return _rootCloseBuffer[_index++];
				else
					return -1;
			default:
				return -1;
		}
	}
	//---------------------------------------------------------------------
	public override void Close()
	{
		_fragmentReader.Close();
	}
}

Diese Klasse verwendest du statt dem XmlTextReader in deinem Code. Für das rootElementName-Argument des Ctor übergibts du "root" (wenn ich mich nicht irre, ist schon lange her als ich das benötigt habe).

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

X
xasz Themenstarter:in
11 Beiträge seit 2011
vor 12 Jahren

Hallo,
vielen Dank für Ihre Hilfen.

Erstmal. Warum ich keine Serialisierung benutze, ich weis ehrlich gesagt, nicht ob das mit Serialisierung so funktioniert wie ich mir das vorstelle, da ich bisher immer nur einzelne Objekte in ein File zu einer bestimmten Zeit serialisiert habe.

Hier ist es aber so, das die Methode, als Logging-Methode arbeitet und zu verschiedenen Zeitpunkten auf die Datei zugreift und ich dann eine solche XML Zeile anhänge.

Auch dir gfoidl vielen Dank für die Klasse, allerdings habe ich schon vor XML-Konform zu arbeiten und dachte, dass wäre so wie ich es mache legitim.
Könntest du mir bitte sagen wie mein XML aussehen müsste, damit es in Ordnung ist.

Vielen Dank für euere HIlfe.

edit:
Ich sehe gerade, dass du mit Wurzelelement meinst, dass das Dokument von einem Tag umschlossen ist. aber das ist für mich dir so einfach möglich, da ich ja immer wieder etwas anhänge. 😦

edit: Lösung:
Ich habe es jetzt so gemacht, auch wenn es nicht da schönste ist, dass ich die Datei in einen StringReader einlese, vorne und hinten ein Tag anhänge und dann in den XMLReader schicke. dadurch habe ich die Wurzelelemente erzeugt und es funktioniert.

2.298 Beiträge seit 2010
vor 12 Jahren

Ein Beispiel für valides XML:


<?xml version="1.0" encoding="utf-8" ?>
<Log>
     <LogInfo Time="06.07.2011 16:03:20" Error="False" Body="Syncronisierung wird gestartet" />
     <LogInfo Time="06.07.2011 16:03:21" Error="False" Body="Syncronisierung erfolgreich abgeschlossen." />
</Log>

Zur Serialisierung:

Du könntest es so gestalten, dass du zu Programmstart die Liste der Logeinträge deserialisierst und vorhältst. Kommt ein neuer Log-Eintrag hinzu, serialisierst du die komplette Liste wieder ins File, behältst aber deine eigentliche Liste bei und vewirfst diese nicht.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

U
1.578 Beiträge seit 2009
vor 12 Jahren

Logging in eine XML Datei halte generell ich für keine gute Idee.
Denn sobald der Prozess durch ein Fehler stirbt kann es sehr schnell passieren das die XML ungültig wird, dann muss man erstmal die XML wieder reparieren. Es kann sogar sein das Datenverlust eintritt da noch nicht alles in die XML geschrieben wurde.

Das ist nicht die Idee eines Loggings.
Logging muss Schnell, Fehlerfrei und Verlustfrei sein.

X
xasz Themenstarter:in
11 Beiträge seit 2011
vor 12 Jahren

@inflames2k: vielen Dank für die Info, so habe ich es jetzt quasi auch gemacht.
Mit der Serialisierung finde ich nicht so gut, weil wenn das Log sehr groß ist muss ich ja jedes mal ewig viel serialisierung und deserialisierung, ob das schnell ist weis ich nicht.

@David W: Du hast vollkommen Recht mit deinen Punkten Schell, Fehlerfrei und Verlustfrei. Leider war meine Idee und in meinem Kopf die schnellste möglichkeit eine Zeile in eine Datei zu schreiben.
Leider hast du kein Beispiel genannt wie man es besser machen könnte.

Trotzdem Danke an euch.

2.298 Beiträge seit 2010
vor 12 Jahren

@inflames2k: vielen Dank für die Info, so habe ich es jetzt quasi auch gemacht.
Mit der Serialisierung finde ich nicht so gut, weil wenn das Log sehr groß ist muss ich ja jedes mal ewig viel serialisierung und deserialisierung, ob das schnell ist weis ich nicht.

Äh, nö. 😃 Wenn du es schlau anstellst hast du für jeden Tag ein neues Log. Und da werden ja nicht täglich tausende Einträge geschrieben.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

U
1.578 Beiträge seit 2009
vor 12 Jahren

@David W: Du hast vollkommen Recht mit deinen Punkten Schell, Fehlerfrei und Verlustfrei. Leider war meine Idee und in meinem Kopf die schnellste möglichkeit eine Zeile in eine Datei zu schreiben.
Leider hast du kein Beispiel genannt wie man es besser machen könnte.



// Nach Formatierung der Message, ruf diese Methode zum Schreiben auf.
private void Write(string logFile, string message)
{
    using (var writer = new StreamWriter(logFile, true, Encoding.UTF-8)
        writer.WriteLine(message);
}

Zusammen mit dem Kommentar von inflames2k

Wenn du es schlau anstellst hast du für jeden Tag ein neues Log

hast du auch kein Performance Problem.

Der Vorteil: Es ist einfach. Es ist leicht lesbar. Es kann nur zu Datenverlust kommen wenn die Datei nicht geschrieben werden kann oder es genau in der nanosekunde abbricht. Aber auch dann fehlt immer nur eine Zeile.

Falls du doch bedenken hast kannst du die Datei auch mit Autoflush offen halten:

private StreamWriter _logWriter;

private void OpenLog(string logFile)
{
    _logWriter = new StreamWriter(logFile, true, Encoding.UTF8);
    _logWriter.AutoFlush = true;
}

// Nach Formatierung der Message, ruf diese Methode zum Schreiben auf.
private void Write(string message)
{
    _logWriter.WriteLine(message);
}
X
xasz Themenstarter:in
11 Beiträge seit 2011
vor 12 Jahren

Ok Vielen Dank für eure Antworten, dann werde ich das mal umsetzten 😃

U
1.578 Beiträge seit 2009
vor 12 Jahren

BTW, Sagt dein Visual Studio tatsächlich "Stummelstücke"?

X
xasz Themenstarter:in
11 Beiträge seit 2011
vor 12 Jahren

Ja es hat folgende Exception geschmissen, nicht wortgenu, aber so ähnlich:> Fehlermeldung:

Zu viele Stummelstücke in XMLReader in Zeile 2 Postion 2.