C# avoid overwritten xml file - c#

I created a C# Application to write data to xml file. It overrides all the new Data,
How to Avoid..?
Please help me.
This is my code
namespace BarcodeScaner
{
class WriteFile
{
DateTime dt=DateTime.Now;
public WriteFile()
{
}
public void createFile(string ptr,string value)
{
using (XmlWriter writer = XmlWriter.Create("Data.xml"))
{
writer.WriteStartDocument();
writer.WriteStartElement("Products");
writer.WriteStartElement("Details");
writer.WriteAttributeString("PTR", ptr);
writer.WriteAttributeString("Value", value);
writer.WriteAttributeString("DateTime", dt.ToString());
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
}
}

You can use XmlDocument to add custom nodes to an existing Xml Document:
XmlDocument doc = new XmlDocument();
doc.Load("Data.xml");
XmlElement el = doc.CreateElement("child");
el.InnerText = "Example of data being appendeed";
doc.DocumentElement.AppendChild(el);
doc.Save("test.xml");

You need to read the existing file, add your data to it. And then write the combined results to the file.
Because of the format of XML files, you can't simply append new data to the file as you might with some file formats.

I'm assuming that what you're wanting to do is add new data to an existing XML file, correct?
You can't just append data to an XML file, and your code actually creates a new file each time it's run, overwriting the old one.
What you need to do is read the XML data into memory, add the new nodes, and write the whole file out again. If there is a lot of data then it may be more efficient to stream from one file to another and insert the new nodes as you go.

Related

OutOfMemoryException when save XmlDocument from XmlReader.ReadInnerXml

I am using XmlReader.ReadInnerXml() to load part of an XML file and save it as an XmlDocument. I ran into OutOfMemoryException when the innerXml part was over 2 GB (an estimate). What is the best way to handle this error? Is there a better way to create a large xml from XmlReader? Can I save the content without loading into memory?
using (XmlReader xmlRdr = XmlReader.Create(file))
{
xmlRdr.MoveToContent();
while (xmlRdr.Read())
{
//when read to XmlNodeType.Element and xmlRdr.Name meets certain criteria
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
try
{
xmlDoc.LoadXml(xmlRdr.ReadInnerXml());
//get a few data from within the innerXml and eventually use XmlWritter to save the file
}
catch(Exception e)
{
string content = $"{e.GetType()} {e.Message} {NewLine} {objId}";
//send content to log file and email
}
}
}
As said in one of the comments maybe try using StreamReader and StreamWriter
This tutorial might help

Add new to xml file every time new content appears on the page [duplicate]

I'm building an Parts app in order to learn C# and WPF. I trying having trouble adding new parts using XmlWriter. I can create the xml file, but can not figure how to add additional parts. Should I be using something else like XmlDocument? Here is my code behind:
private void btnSave_Click(object sender, RoutedEventArgs e)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("f:\\MyParts.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("MyParts");
writer.WriteStartElement("parts");
writer.WriteStartElement("item");
writer.WriteString(txtbxitem.Text);
writer.WriteEndElement();
writer.WriteStartElement("color");
writer.WriteString(txtbxcolor.Text);
writer.WriteEndElement();
writer.WriteStartElement("size");
writer.WriteString(txtbxsize.Text);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
writer.Close();
}
}
This code creates the xml file and a node correctly, but how do I add additional parts? Here is what I am trying to create:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<MyParts>
<parts>
<item>Part1</item>
<color>Red</color>
<size>SM</size>
</parts>
<parts>
<item>Part2</item>
<color>Blue</color>
<size>XXL</size>
</parts>
</MyParts>
Personally I'd suggest using LINQ to XML. It's a much easier API to use than XmlDocument.
But yes, if you want to modify an existing document then typically using an in-memory representation is simpler than using a streaming API. It's possible to do the latter of course, but it's not easy.
Here's an example to create the same XML as you've already got (other than the declaration: any reason you'd want to use Latin-1 instead of something like UTF-8 which can represent the whole of Unicode, btw?)
var doc = new XDocument(
new XElement("MyParts",
new XElement("parts",
new XElement("item", "Part1"),
new XElement("color", "Red"),
new XElement("size", "SM")),
new XElement("parts",
new XElement("item", "Part2"),
new XElement("color", "Blue"),
new XElement("size", "XXL"))));
Then if you wanted to add another part:
doc.Root.Add(
new XElement("parts",
new XElement("item", "Part3"),
new XElement("color", "Green"),
new XElement("size", "L")));
Admittedly I'd expect you'd want to encapsulate the "create a parts element" bit into a method to avoid repeating it all the time... but hopefully you get the picture.
Use a loop, and you'll end up with something like:
var parts = new List<Part>() { ...... parts here ...... };
using (XmlWriter writer = XmlWriter.Create("f:\\MyParts.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("MyParts");
foreach(var part in parts)
{
writer.WriteStartElement("parts");
writer.WriteStartElement("item");
writer.WriteString(part.Item);
writer.WriteEndElement(); // </item>
writer.WriteStartElement("color");
writer.WriteString(part.Color);
writer.WriteEndElement();
writer.WriteStartElement("size");
writer.WriteString(part.Size);
writer.WriteEndElement(); // </size>
writer.WriteEndElement(); // </parts>
}
writer.WriteEndElement(); // </MyParts>
writer.WriteEndDocument();
writer.Flush();
writer.Close();
}
The general idea is that, for each part in your list of parts, you write the "parts" (should be "part"?) tag and all of its contents, filling item, color and size with data from a Part class, which in its simplest form might be:
class Part
{
public string Item { get; set; }
public Color Color { get; set; }
public string Size { get; set; }
}
The code above does exactly what it looks like: writes an element "MyParts" and then writes a child element "parts" and then a child element "item" with a value of whatever is in your text box.
This smells suspiciously like homework, and is readily Google-able, so I'm only going to give a quick pseudo-answer.
You (may) want to:
Create appropriate class(es) for parts that have the members you want
Create a collection of those items
Update that in-memory collection from your UI
Save the collection using the XML formatting and functionality of your choice (including but not limited to what you are doing above, or LINQ to XML, or XML Serialization, or...)
Have you considered using the out of the box XML Serialization that comes with .NET? You just populate your objects within some collection and then use the XML Serializer to persist to a file. You can then use the DeSerializer to hydrate your objects.
This would allow your to spend more time on your application's UI (WPF), and logic. All you need to do is all the Serializable attribute to your class.
Here's a good example: http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm
The biggest benefit is that as you build your data object over time, the serialization/de-serialization will grow with it.

How to add the contents of a Stream containing XML into an existing XmlElement as a child?

I have a Stream containing XML and I want to load its contents, then add its root element as a child to an existing XmlElement. I know there is already XmlDocument.Load(Stream stream); but that will create a full, standalone XML document. Instead I would like to, given an existing XmlDocument, specify an element in that document to load the stream under. Is this possible?
To add the XML from a stream as the child of an existing XmlElement, you can first load the XML into an XmlDocumentFragment, then append the fragments, as follows:
// stream is an opened Stream containing a valid XML document
// xmlElement is an xmlElement
using (var reader = XmlReader.Create(stream))
{
var fragment = xmlElement.OwnerDocument.CreateDocumentFragment();
using (var writer = fragment.CreateNavigator().AppendChild())
{
writer.WriteNode(reader, true);
}
foreach (var child in fragment.ChildNodes.OfType<XmlElement>().ToList())
xmlElement.AppendChild(child);
}
This solution is memory efficient in that it avoids loading the entire XML into a temporary string for parsing, instead chaining together an XML reader and writer using XmlWriter.WriteNode(XmlReader, Boolean).
Sample fiddle.

how to append a xml file in c#?

i am adding tracing for audit purposes of a simple process i have built as an .exe and set in the scheduler to run every 10 minutes. i want to have the application output the results into an xml file.
if the file exists then open and append data to it, if it does not exist i want to create a new xml file that will be persisted and used on next run.
here is my code now, what do i need to add, how do i open the xml file (on c:/file.xml) and use it to append nodes to?
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", null, null);
doc.AppendChild(dec);// Create the root element
XmlElement root = doc.CreateElement("STATS");
doc.AppendChild(root);
XmlElement urlNode = doc.CreateElement("keepalive");
urlNode.SetAttribute("runTime", DateTime.Now.ToString());
try
{
WebProxy wp = new WebProxy("http://proxy.ml.com:8083/");
WebClient w = new WebClient();
w.Proxy = wp;
if (w.DownloadString("http://wwww.example.com") != "")
urlNode.SetAttribute("result", "UP");
else
urlNode.SetAttribute("result", "DOWN");
}
catch
{
urlNode.SetAttribute("result", "DOWN");
}
finally
{
root.AppendChild(urlNode);
doc.Save("c:/keepAlive.xml");
}
}
You can't append an XML file - you'll have to load the file in memory , modify/add/etc, and then write it to disk.
EDIT :
Well, for loading a file you would use :
XmlDocument xmlDoc= new XmlDocument(); // create an xml document object.
if(System.IO.File.Exists("yourXMLFile.xml")
xmlDoc.Load("yourXMLFile.xml");// load from file
else{
// create the structure of your xml document
XmlElement root = xmlDoc.CreateElement("STATS");
xmlDoc.AppendChild(root);
}
and then start adding the keepalive stuff.
I would actually go a bit further and not mess around with xml. I'd create a class that contains everything I need and just serialize and deserialize it.
Like this:
[XmlRoot]
public class Stats{
public Stats(){}
public IList<StatsItem> Items{get;set;}
}
public class StatsItem{
public StatsItem(){}
public string UrlName{get;set;}
public DateTime Date{get;set;}
}
now just serialize this, and you have your xml document. When the time comes, deserialize it, add stuff to the Items list and serialize and save it to disk again.
There are lots of resources on google , so just search a bit for those.
using System;
using System.Xml.Linq;
using System.Xml.XPath;
...
public void Append(){
XDocument xmldoc = XDocument.Load(#"yourXMLFile.xml"));
XElement parentXElement = xmldoc.XPathSelectElement("yourRoot");
XElement newXElement = new XElement("test", "abc");
//append element
parentXElement.Add(newXElement);
xmldoc.Save(#"yourXMLFile.xml"));
}

determine if xml file contains data - c#

How do i know if my XML file has data besides the name space info:
Some of the files contain this:
<?xml version="1.0" encoding="UTF-8"?>
And if i encounter such a file, i want to place the file in an error directory
You could use the XmlReader to avoid the overhead of XmlDocument. In your case, you will receive an exception because the root element is missing.
string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
using (StringReader strReader = new StringReader(xml))
{
//You can replace the StringReader object with the path of your xml file.
//In that case, do not forget to remove the "using" lines above.
using (XmlReader reader = XmlReader.Create(strReader))
{
try
{
while (reader.Read())
{
}
}
catch (XmlException ex)
{
//Catch xml exception
//in your case: root element is missing
}
}
}
You can add a condition in the while(reader.Read()) loop after you checked the first nodes to avoid to read the entire xml file since you just want to check if the root element is missing.
I think the only way is to catch an exception when you try and load it, like this:
try
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(Server.MapPath("XMLFile.xml"));
}
catch (System.Xml.XmlException xmlEx)
{
if (xmlEx.Message.Contains("Root element is missing"))
{
// Xml file is empty
}
}
Yes, there is some overhead, but you should be performing sanity checks like this anyway. You should never trust input and the only way to reliably verify it is XML is to treat it like XML and see what .NET says about it!
XmlDocument xDoc = new XmlDocument();
if (xDoc.ChildNodes.Count == 0)
{ // xml document is empty }
if (xDoc.ChildNodes.Count == 1)
{ // in xml document is only declaration node. (if you are shure that declaration is allways at the begining }
if (xDoc.ChildNodes.Count > 1)
{ // there is declaration + n nodes (usually this count is 2; declaration + root node) }
Haven't tried this...but should work.
try
{
XmlDocument doc = new XmlDocument();
doc.Load("test.xml");
}
catch (XmlException exc)
{
//invalid file
}
EDIT: Based on feedback comments
For large XML documents see Thomas's answer. This approach can have performance issues.
But, if it is a valid xml and the program wants to process it then this approach seems better.
If you aren't worried about validity, just check to see if there is anything after the first ?>. I'm not entirely sure of the C# syntax (it's been too long since I used it), but read the file, look for the first instance of ?>, and see if there is anything after that index.
However, if you want to use the XML later or you want to process the XML later, you should consider PK's answer and load the XML into an XmlDocument object. But if you have large XML documents that you don't need to process, then a solution more like mine, reading the file as text, might have less overhead.
You could check if the xml document has a node (the root node) and check it that node has inner text or other children.
As long as you aren't concerned with the validity of the XML document, and only want to ensure that it has a tag other than the declaration, you could use simple text processing:
var regEx = new RegEx("<[A-Za-z]");
bool foundTags = false;
string curLine = "";
using (var reader = new StreamReader(fileName)) {
while (!reader.EndOfStream) {
curLine = reader.ReadLine();
if (regEx.Match(curLine)) {
foundTags = true;
break;
}
}
}
if (!foundTags) {
// file is bad, copy.
}
Keep in mind that there's a million other reasons that the file may be invalid, and the code above would validate a file consisting only of "<a". If your intent is to validate that the XML document is capable of being read, you should use the XmlDocument approach.

Categories

Resources