How to change values of an xml file in C#? - c#

Whenever I run the program the xml file simply adds another parts over the original code rather than replacing it.
Here's my files
XML:
<?xml version="1.0" encoding="utf-8" ?>
<stuff>stuff</stuff>
C#:
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
FileStream f = new FileStream(#"C:\ file path", FileMode.Open);
doc.Load(f);
doc.SelectSingleNode("stuff").InnerText = "hi";
doc.Save(f);
}
Resulting XML:
<?xml version="1.0" encoding="utf-8" ?>
<stuff>stuff</stuff><?xml version="1.0" encoding="utf-8"?>
<stuff>hi</stuff>

I'm not sure why this is happening, but I think it has to do with loading stuff to the stream and assigning it more to the same stream.
Maybe you should do the simple way (that works):
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\Temp\Test.xml");
doc.SelectSingleNode("stuff").InnerText = "hi";
doc.Save(#"C:\Temp\Test.xml");
}

The overload for Save that takes the filename will achieve what you are looking for. It overwrites the existing file.
XmlDocument doc = new XmlDocument();
FileStream f = new FileStream(#"C:\file.xml", FileMode.Open);
doc.Load(f);
f.Close();
doc.SelectSingleNode("stuff").InnerText = "hi";
doc.Save(#"C:\file.xml");

Related

How to save class objects to XML in c#

I have a class and i need to save this class into an XML file. Since i have more objects from this class i need every object to be added under the same root.
I start out with the xml file as this:
<?xml version="1.0" encoding="utf-8"?>
<root>
</root>
My class looks like this:
class Save
{
string a;
string b;
List<subClass> L1;
List<subClass> L2;
subClass
{
string c;
double d;
}
}
The xml file after saveing should look like this:
<?xml version="1.0" encoding="utf-8"?>
<root>
<object>
<Element1>a</Element1>
<Element2>b</Element2>
<objectListL1>
<Element3>c</Element3>
<Element4>d</Element4>
</objectListL1>
...
<objectListL2>
<Element3>c</Element3>
<Element4>d</Element4>
</objectListL2>
...
</object>
</root>
Of course objectListL1 and objectListL2 are repeated as often as entries in the List are found. I just want to create a class, fill it with all my data and than do class.Save() and it should add a new object entry to my XMLfile.
I think i found an easy solution:
XmlSerializer serializer = new XmlSerializer(typeof(CLASSNAME));
StreamWriter sw = File.AppendText(FILEPATH);
using (sw)
{
serializer.Serialize(sw, OBJECT);
}
This will create a file FILEPATH and serialize everything into it. SInce it is with "AppendText" it can be used with a list ob onjects!
If appending is not needed, instead of the Streamwriter one can use:
using (TextWriter writer = new StreamWriter(FILEPATH))

I need to get data out of my xml file and save it into an array c#

Hi I'm currently learning to programm and i have run into a problem.
I'm Saving user inputs into an xml file
private static void AddEntry(string GameName, string SavePath, string ExePath)
{
if (!File.Exists(docname))
{
CreateXml();
}
XDocument doc = XDocument.Load(docname);
XElement Game = doc.Element("Game");
Game.Add(new XElement("GameName", GameName), new XElement("SavePath", SavePath), new XElement("ExePath", ExePath));
doc.Save(docname);
}
private static void CreateXml()
{
XDocument SaveGameManager = new XDocument();
SaveGameManager.Declaration = new XDeclaration("1.0", "utf-8", "yes");
XElement Game = new XElement("Game");
SaveGameManager.Add(Game);
SaveGameManager.Save(docname);
}
now i need to be able to use these values, more specifically i need to use the GameName string in a dropdown menu. What is the simplest option for me to get this considering im not very experienced yet :)
edit: here is my xmlfile
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Game>
<GameName>sfsdf</GameName>
<SavePath>6835-256x256x8 (1).png</SavePath>
<ExePath>arduino-1.8.2-windows.exe</ExePath>
<GameName>fasdf</GameName>
<SavePath>ClassDiagram simple.vsdx</SavePath>
<ExePath>GameOfLife.exe</ExePath>
</Game>

Update an xml file in a storage folder by adding nodes using C#

I'm making a universal app in C# and I'm trying to update an xml file in the storage folder by adding some nodes to it. Ideally, starting with a file like this
<?xml version="1.0" encoding="UTF-8"?>
<MyRoot>
<ParentNode>
<myNode1>value1</myNode1>
<myNode2>value2</myNode2>
</ParentNode>
</MyRoot>
I would like to add other nodes in order to obtain
<?xml version="1.0" encoding="UTF-8"?>
<MyRoot>
<ParentNode>
<myNode1>value1</myNode1>
<myNode2>value2</myNode2>
</ParentNode>
<ParentNode>
<myNode1>value3</myNode1>
<myNode2>value4</myNode2>
</ParentNode>
</MyRoot>
What I obtain instead is an invalid xml file with the content I want appended to the previous content like this
<?xml version="1.0" encoding="UTF-8"?>
<MyRoot>
<ParentNode>
<myNode1>value1</myNode1>
<myNode2>value2</myNode2>
</ParentNode>
</MyRoot><?xml version="1.0" encoding="utf-8"?>
<MyRoot>
<ParentNode>
<myNode1>value1</myNode1>
<myNode2>value2</myNode2>
</ParentNode>
<ParentNode>
<myNode1>value3</myNode1>
<myNode2>value4</myNode2>
</ParentNode>
</MyRoot>
Here is the code
StorageFile myFile = await ApplicationData.Current.LocalFolder.GetFileAsync("myFile.xml");
using (IRandomAccessStream writeStream = await myFile.OpenAsync(FileAccessMode.ReadWrite))
{
// convert IRandomAccessStream to IO.Stream
Stream s = writeStream.AsStreamForWrite();
//xml
XDocument document = XDocument.Load(s);
document.Root.Add(
new XElement("ParentNode",
new XElement("myNode1", "value3"),
new XElement("myNode2", "value4"))
);
document.Save(s);
}
After your call to XDocument.Load you are positioned at the end of the stream, so the call to document.Save will append the new contents at the end of the stream.
As long as you're only adding nodes to the existing XML making the file longer with every save, you could resolve the issue by moving to the beginning of the stream, before calling document.Save:
document.Root.Add(
new XElement("ParentNode",
new XElement("myNode1", "value3"),
new XElement("myNode2", "value4"))
);
s.Seek(0, SeekOrigin.Begin); // <-- add this line
document.Save(s);
If you start removing nodes, this won't work because not all of the old file will be overwritten and some remains will stay at the end. In this case you will need to close the stream after loading it and create a new file for saving by overwriting the existing one:
StorageFile newFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("myFile.xml",
CreationCollisionOption.ReplaceExisting);
Try something along the lines of:
XmlDocument doc = new XmlDocument();
doc.Load("yourfile.xml");
var root = doc.DocumentElement;
var parentNode = doc.CreateElement("ParentNode");
root.AppendChild(parentNode);
var myNode1 = doc.CreateElement("myNode1");
myNode1.Value = "value3";
parentNode.AppendChild(myNode1);
// ...add more nodes etc...
doc.Save("yourfile.xml");

Add <?xml version="1.0" ?> to the top of a xml file after xsl transform

I have successfully been able to transform a simple xml file with data to another xml file (excel template) using a xsl template, this is what my xsl file looks like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" standalone="yes"/>
<xsl:template match="/">
<xsl:processing-instruction name="mso-application">
<xsl:text>progid="Excel.Sheet"</xsl:text>
</xsl:processing-instruction>
...(stuff here)...
</xsl:template>
</xsl:stylesheet>
The resulting xml file is written out correctly BUT with the exception of including
<?xml version="1.0"?>
at the top of the file. How can I get it to appear at the top?
Currently my resulting xml file starts with:
<?mso-application progid="Excel.Sheet"?>
...(rest of file)...
But what I need it to do is:
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
.(rest of file)...
I'm doing this transform through a windows form with the following code:
XPathDocument myXPathDoc = new XPathDocument(xmlfile);
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load(xslfile);
XmlTextWriter myWriter = new XmlTextWriter(xmlexcelfile, null);
myWriter.Formatting = Formatting.Indented;
myWriter.Namespaces = true;
myXslTrans.Transform(myXPathDoc, null, myWriter);
myWriter.Close();
I've tried playing around with the xsl:output standalone="yes/no", as well as omit-xml-declaration="no". I've also tried (in the C#) code adding myWriter.WriteStartDocument(); before transforming but that was not allowed. I have tried searching online for this as well and keep coming back to the standalone="yes" but that isn't working. Is there something I am missing here? Oh and in case you are wondering why I need to have the
<?xml version="1.0"?>
at the top of the resulting file, it's because when opening the xml file with excel, excel doesn't recognize it correctly but if it is included then excel opens it correctly...
You can do this
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" />
or something similar to this using XmlWriterSettings
Edit: Added more code. Previous was missing some parts
XmlWriterSettings writerSettings = null;
XsltArgumentList transformationArguments = null;
XslCompiledTransform transformer = null;
MemoryStream memoryStream = null;
XPathDocument xPathDocument = null;
StringBuilder sb = null;
XmlWriter writer = null;
XmlDocument resultXml = null;
try
{
writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = false; // This does it
writerSettings.Indent = true;
transformationArguments = new XsltArgumentList();
transformer = new XslCompiledTransform();
memoryStream = new MemoryStream(System.Text.Encoding.Default.GetBytes(xml.OuterXml));
xPathDocument = new XPathDocument(new StreamReader(memoryStream));
sb = new StringBuilder();
// give the settings to the writer here
writer = XmlWriter.Create(sb, writerSettings);
// this is not mandatory, obviously, just passing parameters to my xslt file
foreach (KeyValuePair<string, object> parameter in parameters)
{
transformationArguments.AddParam(parameter.Key, string.Empty, parameter.Value);
}
using (Stream strm = Assembly.GetExecutingAssembly().GetManifestResourceStream("Lib.XSLTFile1.xslt"))
using (XmlReader reader = XmlReader.Create(strm))
{
transformer.Load(reader);
transformer.Transform(xPathDocument, transformationArguments, writer);
}
resultXml = new XmlDocument();
resultXml.LoadXml(sb.ToString());
// for testing only
File.AppendAllText(#"Your path goes here\result.xml", resultXml.OuterXml);
}
catch (Exception)
{
throw;
}
This is how I do it, but this code is specifically written to create an instance of a XmlDocument. I'm sure you can adapt to your needs.

How to write an xml attribute without replace all attributes?

I'm using this:
public void WriteSettings(string key, string value)
{
XmlWriterSettings xmlSettings = new XmlWriterSettings();
xmlSettings.Indent = true;
xmlSettings.NewLineOnAttributes = true;
XmlWriter writer = XmlWriter.Create(TMP_FULLPATH, xmlSettings);
writer.WriteStartElement("settings");
writer.WriteAttributeString(key, value);
writer.WriteEndAttribute();
writer.WriteEndDocument();
writer.Flush();
writer.Close();
}
But any modification replaces all attributes with only the last remaining attribute that I am trying to add. For example:
current XML:
<?xml version="1.0" encoding="utf-8"?>
<settings TitleFormat="name:%name% date:%date%" />
when I do:
WriteSettings("foo", "baa");
the XML is:
<?xml version="1.0" encoding="utf-8"?>
<settings foo="baa" />
instead of:
<?xml version="1.0" encoding="utf-8"?>
<settings TitleFormat="name:%name% date:%date%" foo="baa" />
How can I fix that?
You are writing a new file, with no consideration at all of the old. To update a document, you must load it into a DOM, edit the DOM, and save the DOM:
var doc = new XmlDocument();
doc.Load(path);
doc.DocumentElement.SetAttribute(key, value);
doc.Save(path);
you are creating new file each time you call XmlWriter.Create(), do something like this.

Categories