I have an xml file about 900MB and i want to insert data from datatable to that existing xml.
There is a way to do this by using load and save like below;
XDocument xdoc = XDocument.Load(FilePath);
var root = xdoc.Descendants("DocumentElement").FirstOrDefault()
if (root != null){
root.Add(new XElement("tag", "value"));
xdoc.Save(FilePath);
}
However, its cost too much. Loading 900MB xml into datatable can cause memory exceptions and poor performance for couple of new rows.
How can i add new rows to big existing xml from datatable?
XDocument (and XmlDocument as well) loads whole file into memory. You should use XmlWriter with combination of XNode.WriteTo method
Example from XNode.WriteTo documentation:
StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = true;
using (XmlWriter xw = XmlWriter.Create(sb, xws))
{
XElement child2 = new XElement("AnotherChild",
new XElement("GrandChild", "different content"));
child2.WriteTo(xw);
xw.WriteEndElement();
}
Console.WriteLine(sb.ToString());
You can read big xml documents in the same way, check example in XNode.ReadFrom documentation
Related
I am getting the error "Token StartElement in state Epilog would result in an invalid XML document." when i get the data from datatable and try to convery it to xml file .
Code :
DataTable dtTest = new DataTable();
dtTest.Columns.Add("Name");
dtTest.Columns.Add("NickName");
dtTest.Columns.Add("Code");
dtTest.Columns.Add("reference");
dtTest.Rows.Add("Yash", "POPs", "Vapi", "None1");
dtTest.Rows.Add("shilpa", "shilpa", "valsad", "None2");
dtTest.Rows.Add("Dinesh", "dinu", "pune", "None3");
dtTest.Rows.Add("rahul", "mady", "pardi", "None4");
XmlWriterSettings settings = new XmlWriterSettings();
StringWriter stringwriter = new StringWriter();
XmlTextWriter xmlTextWriter = new XmlTextWriter(stringwriter);
xmlTextWriter.Formatting = Formatting.Indented;
xmlTextWriter.WriteStartDocument();
foreach (var row in dtTest.AsEnumerable())
{
xmlTextWriter.WriteStartElement("");
xmlTextWriter.WriteAttributeString("orderid", row.Field<string>("Name"));
xmlTextWriter.WriteElementString("type", row.Field<string>("Name"));
xmlTextWriter.WriteElementString("status", row.Field<string>("Name"));
xmlTextWriter.WriteElementString("productno", row.Field<string>("Name"));
xmlTextWriter.WriteEndElement();
}
XmlDocument docSave = new XmlDocument();
docSave.LoadXml(stringwriter.ToString());
What is the cause of this error, and how can it be fixed?
You have a few problems here:
You are writing multiple root elements to your document, one for each call to xmlTextWriter.WriteStartElement(""). However, a well-formed XML document must have one and only one root element, so you need to wrap your row elements in some container element.
(You might have been thinking that WriteStartDocument() would write the root element, but it does not. It just writes the XML declaration.)
You are using XmlTextWriter but this class is deprecated. From the docs:
Starting with the .NET Framework 2.0, we recommend that you create XmlWriter instances by using the XmlWriter.Create method and the XmlWriterSettings class to take advantage of new functionality.
If you switch to XmlWriter you will get clearer error messages and better error checking.
You are trying to write elements with no name:
xmlTextWriter.WriteStartElement("");
This would result in malformed XML. XmlTextWriter seems not to check for this, but XmlWriter does.
Putting all of the above together, your code can be modified as follows:
var stringwriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringwriter, new XmlWriterSettings { Indent = true }))
{
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("Root");
foreach (var row in dtTest.AsEnumerable())
{
xmlWriter.WriteStartElement("Row");
xmlWriter.WriteAttributeString("orderid", row.Field<string>("Name"));
xmlWriter.WriteElementString("type", row.Field<string>("Name"));
xmlWriter.WriteElementString("status", row.Field<string>("Name"));
xmlWriter.WriteElementString("productno", row.Field<string>("Name"));
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
}
var xml = stringwriter.ToString();
Demo fiddle here.
I would like to perform object serialization to only one branch in an existing XML file. While reading by using:
RiskConfiguration AnObject;
XmlSerializer Xml_Serializer = new XmlSerializer(typeof(RiskConfiguration));
XmlTextReader XmlReader = new XmlTextReader(#"d:\Projects\RiskService\WCFRiskService\Web.config");
XmlReader.ReadToDescendant("RiskConfiguration");
try
{
AnObject = (RiskConfiguration)Xml_Serializer.Deserialize(XmlReader);
AnObject.Databases.Database[0].name = "NewName";
}
finally
{
XmlReader.Close();
}
It is possible, I do not know how to edit the object again performed it can save the file without erasing other existing elements in an XML file. Can anyone help me?
I found a way to display the desired item serialization. How do I go now instead of the paste to the original element in XML?
StringWriter wr = new StringWriter();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.Encoding = System.Text.Encoding.Default;
using (XmlWriter writer = XmlWriter.Create(wr, settings))
{
XmlSerializerNamespaces emptyNamespace = new XmlSerializerNamespaces();
emptyNamespace.Add(String.Empty, String.Empty);
Xml_Serializer.Serialize(writer, AnObject, emptyNamespace);
MessageBox.Show(wr.ToString());
}
First of all, you should stop using new XmlTextReader(). That has been deprecated since .NET 2.0. Use XmlReader.Create() instead.
Second, XML is not a random-access medium. You can't move forward and backwards, writing into the middle of the file. It's a text-based file.
If you need to "modify" the file, then you'll need to write a new version of the file. You could read from the original file, up to the point where you need to deserialize, writing the nodes out to a new version of the file. You could then deserialize from the original file, modify the objects, and serialize out to the new version. You could then continue reading from the original and writing the nodes out to the new version.
The code below is causing the " Data at the root level is invalid. Line 1, position 1. "
I like to keep the code indent(linebreak) but keep having the problem as mentioned above. I could use the TextReader to load the xml but it will remove the indent which i don't like it. If you know how to fix problem please let me know. Thanks
public XmlDocument MYXML()
{
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = false;
wSettings.OmitXmlDeclaration = false;
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms, wSettings);// Write Declaration
xw.WriteStartDocument();
// Write the root node
xw.WriteStartElement("Library");
// Write the books and the book elements
xw.WriteStartElement("Book");
xw.WriteStartAttribute("BookType");
xw.WriteString("Hardback");
xw.WriteEndAttribute();
xw.WriteStartElement("Title");
xw.WriteString("Door Number Three");
xw.WriteEndElement();
xw.WriteStartElement("Author");
xw.WriteString("O'Leary, Patrick");
xw.WriteEndElement();
xw.WriteEndElement();
xw.WriteEndElement();
// Close the document
xw.WriteEndDocument();
// Flush the write
xw.Flush();
Byte[] buffer = new Byte[ms.Length];
buffer = ms.ToArray();
string xmlOutput = System.Text.Encoding.UTF8.GetString(buffer);
//The next 3 line works fine but it will remove the Indent from the XmlWriterSettings
//TextReader tr = new StreamReader(ms);
//ms.Seek(0, SeekOrigin.Begin);
//xmlOutput = tr.ReadToEnd() + "";
//Can't nload the xmlOutput from buffer
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlOutput);
return xmldoc;
}
The XmlWriter is writing a utf-8 byte-order mark to the stream. Encoding.UTF8.GetString doesn't account for this (since it's only supposed to occur in files) so the first character of the string becomes an invalid, unprintable character, which is what XmlDocument.LoadXml chokes on.
EDIT: Since you said you want to create an XmlDocument so you can reuse it, I recommend one of the following:
If using .Net 3.5 or newer, use XDocument which is much easier to use (I recommend this).
Create the XmlDocument directly by constructing nodes and adding them to the tree.
Create the XmlDocument directly from the writer by using XPathNavigator (XmlWriter writer = doc.CreateNavigator.AppendChild())
Note that you can't easily add insignificant whitespace to an XmlDocument. Using XDocument and writing it to the output using doc.Save(Response.Output) is by far the easiest option if you want to have nicely formatted output.
I am saving my files as xml documents, using XDocument.Save(path), and after saving and loading a document all of the line breaks have changed from "/r/n" to "/n/". Why is this happening and how can I fix it?
You can use XmlWriterSettings to control what your line-break characters are:
XmlWriterSettings xws = new XmlWriterSettings();
xws.NewLineChars = "\r\n";
using (XmlWriter xw = XmlWriter.Create("whatever.xml", xws))
{
xmlDocumentInstance.Save(xw);
}
Whatever you're using to read in your XML might be normalizing your line endings.
If you set the PreserveWhiteSpace property on your XmlDocument object before calling Load() and Save() then this will not happen:
var doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load("foo.xml");
...
doc.Save("bar.xml"); // Line endings will not be altered
I am editing csproj files with Linq-to-XML and need to save the XML without the <?XML?> header.
As XDocument.Save() is missing the necessary option, what's the best way to do this?
You can do this with XmlWriterSettings, and saving the document to an XmlWriter:
XDocument doc = new XDocument(new XElement("foo",
new XAttribute("hello","world")));
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
StringWriter sw = new StringWriter();
using (XmlWriter xw = XmlWriter.Create(sw, settings))
// or to write to a file...
//using (XmlWriter xw = XmlWriter.Create(filePath, settings))
{
doc.Save(xw);
}
string s = sw.ToString();
A simpler solution than the accepted answer is to use XDocument.ToString() to get the XML text without the header.
Example:
// Load the file
XDocument xDocument = XDocument.Load(fileName);
// Edit the XML...
// Save the edited XML text to file
File.WriteAllText(fileName, xDocument.ToString());