c# - error in XML document. Unexpected XML declaration. XML declaration must be the first node in the document -
there error in xml document (8, 20). inner 1: unexpected xml declaration. xml declaration must first node in document, , no white space characters allowed appear before it.
ok, understand error.
how it, however, perplexes me.
i create document microsoft's serialize tool. then, turn around , attempt read back, again, using microsoft's deserialize tool.
i not in control of writing xml file in correct format - can see.
here single routine use read , write.
private string xmlpath = system.web.hosting.hostingenvironment.mappath(webconfigurationmanager.appsettings["data_xml"]); private object objlock = new object(); public string errormessage { get; set; } public storedmsgs operation(string from, string message, fileaccess access) { storedmsgs list = null; lock (objlock) { errormessage = null; try { if (!file.exists(xmlpath)) { var root = new xmlrootattribute(rootname); var serializer = new xmlserializer(typeof(storedmsgs), root); if (string.isnullorempty(message)) { = "code window"; message = "created file"; } var item = new storedmsg() { = from, date = datetime.now.tostring("s"), message = message }; using (var stream = file.create(xmlpath)) { list = new storedmsgs(); list.add(item); serializer.serialize(stream, list); } } else { var root = new xmlrootattribute("messagehistory"); var serializer = new xmlserializer(typeof(storedmsgs), root); var item = new storedmsg() { = from, date = datetime.now.tostring("s"), message = message }; using (var stream = file.open(xmlpath, filemode.open, fileaccess.readwrite)) { list = (storedmsgs)serializer.deserialize(stream); if ((access == fileaccess.readwrite) || (access == fileaccess.write)) { list.add(item); serializer.serialize(stream, list); } } } } catch (exception error) { var sb = new stringbuilder(); int index = 0; sb.appendline(string.format("top level error: <b>{0}</b>", error.message)); var err = error.innerexception; while (err != null) { index++; sb.appendline(string.format("\tinner {0}: {1}", index, err.message)); err = err.innerexception; } errormessage = sb.tostring(); } } return list; }
is wrong routine? if microsoft write file, seems me should able read back.
it should generic enough use.
here storedmsg class:
[serializable()] [xmltype("storedmessage")] public class storedmessage { public storedmessage() { } [xmlelement("from")] public string { get; set; } [xmlelement("date")] public string date { get; set; } [xmlelement("message")] public string message { get; set; } } [serializable()] [xmlroot("messagehistory")] public class messagehistory : list<storedmessage> { }
the file generates doesn't me has issues.
i saw solution here:
error: xml declaration must first node in document
but, in case, seems had xml document wanted read. had fix it.
i have xml document created microsoft, should read in microsoft.
the problem adding file. deserialize, re-serialize same stream without rewinding , resizing zero. gives multiple root elements:
<?xml version="1.0"?> <storedmessage> </storedmessage <?xml version="1.0"?> <storedmessage> </storedmessage
multiple root elements, , multiple xml declarations, invalid according xml standard, .net xml parser throws exception in situation default.
for possible solutions, see xml error: there multiple root elements, suggests either:
enclose list of
storedmessage
elements in synthetic outer element, e.g.storedmessagelist
.this require load list of messages file, add new message, , truncate file , re-serialize entire list when adding single item. performance may worse in current approach, xml valid.
when deserializing file containing concatenated root elements, create xml writer using
xmlreadersettings.conformancelevel = conformancelevel.fragment
, iteratively walk through concatenated root node(s) , deserialize each 1 individually shown, e.g., here. usingconformancelevel.fragment
allows reader parse streams multiple root elements (although multiple xml declarations still cause error thrown).later, when adding new element end of file using
xmlserializer
, seek end of file , serialize using xml writer returnedxmlwriter.create(textwriter, xmlwritersettings)
xmlwritersettings.omitxmldeclaration = true
. prevents output of multiple xml declarations explained here.
for option #2, operation
following:
private string xmlpath = system.web.hosting.hostingenvironment.mappath(webconfigurationmanager.appsettings["data_xml"]); private object objlock = new object(); public string errormessage { get; set; } const string rootname = "messagehistory"; static readonly xmlserializer serializer = new xmlserializer(typeof(storedmessage), new xmlrootattribute(rootname)); public messagehistory operation(string from, string message, fileaccess access) { var list = new messagehistory(); lock (objlock) { errormessage = null; try { using (var file = file.open(xmlpath, filemode.openorcreate)) { list.addrange(xmlserializerhelper.readobjects<storedmessage>(file, false, serializer)); if (list.count == 0 && string.isnullorempty(message)) { = "code window"; message = "created file"; } var item = new storedmessage() { = from, date = datetime.now.tostring("s"), message = message }; if ((access == fileaccess.readwrite) || (access == fileaccess.write)) { file.seek(0, seekorigin.end); var writersettings = new xmlwritersettings { omitxmldeclaration = true, indent = true, // optional; remove if compact xml desired. }; using (var textwriter = new streamwriter(file)) { if (list.count > 0) textwriter.writeline(); using (var xmlwriter = xmlwriter.create(textwriter, writersettings)) { serializer.serialize(xmlwriter, item); } } } list.add(item); } } catch (exception error) { var sb = new stringbuilder(); int index = 0; sb.appendline(string.format("top level error: <b>{0}</b>", error.message)); var err = error.innerexception; while (err != null) { index++; sb.appendline(string.format("\tinner {0}: {1}", index, err.message)); err = err.innerexception; } errormessage = sb.tostring(); } } return list; }
using following extension method adapted read nodes of xml file in c#:
public partial class xmlserializerhelper { public static list<t> readobjects<t>(stream stream, bool closeinput = true, xmlserializer serializer = null) { var list = new list<t>(); serializer = serializer ?? new xmlserializer(typeof(t)); var settings = new xmlreadersettings { conformancelevel = conformancelevel.fragment, closeinput = closeinput, }; using (var xmltextreader = xmlreader.create(stream, settings)) { while (xmltextreader.read()) { // skip whitespace if (xmltextreader.nodetype == xmlnodetype.element) { using (var subreader = xmltextreader.readsubtree()) { var logevent = (t)serializer.deserialize(subreader); list.add(logevent); } } } } return list; } }
note if going create xmlserializer
using custom xmlrootattribute
, must cache serializer avoid memory leak.
sample fiddle.
Comments
Post a Comment