i am using the XmlSerializer.Serialize and XmlSerializer.Deserialize
i have a class MetricResult:
public class Metricresult
{
public string metric;
public string newvalue;
public string deltavalue;
}
and i am calculating some results that will be stored in :
List<Metricresult> metricresults = new List<Metricresult>();
i changed this list to xml file succefully and in an other project i need to deserialize this list but there is an exception thrown :
there-is-an-error-in-xml-document-0-0-during-deserialization
the xml File
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMetricresult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Metricresult>
<metric>numberofdeclaration</metric>
<newvalue>0</newvalue>
<deltavalue>0</deltavalue>
</Metricresult>
<Metricresult>
<metric>numberofdeclaration</metric>
<newvalue>0</newvalue>
<deltavalue>0</deltavalue>
</Metricresult>
<Metricresult>
<metric>numberofdeclaration</metric>
<newvalue>0</newvalue>
<deltavalue>0</deltavalue>
</Metricresult>
<Metricresult>
<metric>numberofdeclaration</metric>
<newvalue>0</newvalue>
<deltavalue>0</deltavalue>
</Metricresult>
<Metricresult>
<metric>numberofdeclaration</metric>
<newvalue>0</newvalue>
<deltavalue>0</deltavalue>
</Metricresult>
<Metricresult>
<metric>numberofdeclaration</metric>
<newvalue>0</newvalue>
<deltavalue>0</deltavalue>
</Metricresult>
</ArrayOfMetricresult>
Weird, coz the following works perfectly fine for me:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
public class MetricResult
{
public string Metric { get; set; }
public string NewValue { get; set; }
public string DeltaValue { get; set; }
}
class Program
{
static void Main()
{
// define some metric results to serialize
var metricResults = new[]
{
new MetricResult { Metric = "metric 1", NewValue = "new value 1", DeltaValue = "delta 1" },
new MetricResult { Metric = "metric 2", NewValue = "new value 2", DeltaValue = "delta 2" },
new MetricResult { Metric = "metric 3", NewValue = "new value 3", DeltaValue = "delta 3" },
}.ToList();
var serializer = new XmlSerializer(metricResults.GetType());
using (var writer = XmlWriter.Create("metrics.xml"))
{
// serialize the metric results we defined previously to metrics.xml
serializer.Serialize(writer, metricResults);
}
using (var reader = XmlReader.Create("metrics.xml"))
{
// read metrics.xml and deserialize back
metricResults = (List<MetricResult>)serializer.Deserialize(reader);
foreach (var result in metricResults)
{
Console.WriteLine("metric: {0}, new value: {1}, delta: {2}", result.Metric, result.NewValue, result.DeltaValue);
}
}
}
}
and metrics.xml looks as expected:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMetricResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MetricResult>
<Metric>metric 1</Metric>
<NewValue>new value 1</NewValue>
<DeltaValue>delta 1</DeltaValue>
</MetricResult>
<MetricResult>
<Metric>metric 2</Metric>
<NewValue>new value 2</NewValue>
<DeltaValue>delta 2</DeltaValue>
</MetricResult>
<MetricResult>
<Metric>metric 3</Metric>
<NewValue>new value 3</NewValue>
<DeltaValue>delta 3</DeltaValue>
</MetricResult>
</ArrayOfMetricResult>
An error at 0,0 usually means you have whitespace at the start of your xml file, before the first element. Look carefully at the xml (perhaps looking at the binary, rather than the text - it could also be a unicode invisible space, etc).
Also: whenever using XmlSerializer, look at the InnerExceptions:
catch(Exception ex) {
while(ex != null) {
Trace.WriteLine(ex.Message);
ex = ex.InnerException;
}
}
there are usually very detailed explanations, if you look all the way through the messages.
One very common error people make is when using streams, not rewinding them. The following will error with a 0,0 error:
using (var ms = new MemoryStream())
{
serializer.Serialize(ms, metricResults);
serializer.Deserialize(ms);
}
because the serialize left the stream at the end. If you have code like this, reset the stream to the start (ms.Position = 0;) between serialize and deserialize. See also: How many ways can you mess up IO?
Related
I need to create an XML document like this:
<Root>
<Data>
<Name>Name1</Name>
<Surname>Surname1</Surname>
<Gender>M</Gender>
</Data>
<Data>
<Name>Name2</Name>
<Surname>Surname2</Surname>
<Gender>F</Gender>
</Data>
</Root>
I've got the Xpath of the XML Elements, so I've create the following class
class XpathFieldValue
{
public string Xpath { get; set; }
public string Value { get; set; }
}
and then the following method
public static void CreateXml()
{
List<XpathFieldValue> fieldValues = new List<XpathFieldValue> {
new XpathFieldValue{ Xpath="/Root/Data/Name", Value="Name1" },
new XpathFieldValue{ Xpath="/Root/Data/Surname", Value="Surname1" },
new XpathFieldValue{ Xpath="/Root/Data/Gender", Value="M"},
new XpathFieldValue{ Xpath="/Root/Data/Name", Value="Name2" },
new XpathFieldValue{ Xpath="/Root/Data/Surname", Value="Surname2" },
new XpathFieldValue{ Xpath="/Root/Data/Gender", Value="F"}
};
XmlDocument document = new XmlDocument();
document.LoadXml("<Root/>");
foreach (XpathFieldValue fieldValue in fieldValues)
{
Set(document, fieldValue.Xpath, fieldValue.Value);
}
document.Save(#"C:\Temp\xmlDocOut.xml");
}
I've copyed the Set method from here: link
But when I run it it creates only the last parth of XML
<Root>
<Data>
<Name>Name2</Name>
<Surname>Surname2</Surname>
<Gender>F</Gender>
</Data>
</Root>
Can anyone help me?
XPath isn't really intended to generate documents but to access em.
Another (probably better) approach would be to serialize it.
But, since the question requires the fields of xml to be variable, serialization isn't a viable way. i STRONGLY advise you to change this requirement and you'll see why in the following example:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
using (var writer = new System.IO.StreamWriter(#"C:\Users\luigi.trabacchin\Desktop\asd.xml"))
{
var doc = new System.Xml.XmlDocument();
var root = doc.CreateElement("Root");
doc.AppendChild(root);
for (var i = 0; i <= 1; i++)
{
var dataNode = doc.CreateElement("Data");
root.AppendChild(dataNode);
{
var node = doc.CreateElement("Name");
dataNode.AppendChild(node);
var text = doc.CreateTextNode($"Name {i}");
node.AppendChild(text);
}
{
var node = doc.CreateElement("Surname");
dataNode.AppendChild(node);
var text = doc.CreateTextNode($"Surname {i}");
node.AppendChild(text);
}
{
var node = doc.CreateElement("Gender");
dataNode.AppendChild(node);
var text = doc.CreateTextNode(i %2 == 0 ? "M" : "F");
node.AppendChild(text);
}
}
doc.Save(writer);
}
Console.WriteLine("Hello World!");
}
}
}
It quickly becomes very tedious and hard to work with.
Still i hope this answer your question.
Next time, maybe, state all the requirements directly in the question!
List:
List<string> list = new List<string>();
XML File:
<memberlist>
<member>
<name>Name</name>
<status>Status</status>
</member>
</memberlist>
How would I go about parsing this file, lets say (file.xml) into the list?
I've tried many ways but none of them seem to be working.
I want to check to see if the status is 'gold', and if it is, I would like to put the name of that member into the list.
Load the xml into an XDocument. You can do this from a file, I have demonstrated from a string.
Do a linq query for elements named "status" (within "member") that also have a value of "gold".
Of those, grab the value of the "name" element.
Use AddRange on your list of strings.
List<string> lstGolds = new List<string>();
string xml ="<memberlist><member><name>Name</name><status>gold</status></member></memberlist>";
XDocument doc = XDocument.Parse(xml);
var goldStatus = doc.Descendants("member")
.Where(d => d.Element("status").Value == "gold")
.Select(d => d.Element("name").Value);
lstGolds.AddRange(goldStatus);
You should use using System.Xml.Linq;
using (FileStream fileStramWrite = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader streamReader = new StreamReader(fileStramWrite))
{
var xdoc = XDocument.Load(streamReader);
var xElement = xdoc.Element("memberlist");
var xElement2 = xElement.Element("member");
var name = xElement2.Element("name").Value;
var status = xElement2.Element("status").Value;
}
Convert your XML to a list of objects....
Use these two mehods:
public static string Serialize<T>(T dataToSerialize)
{
try
{
var stringwriter = new ISOEncodingStringWriter();
var serializer = new XmlSerializer(typeof(T));
var xns = new XmlSerializerNamespaces();
xns.Add(string.Empty, string.Empty);
serializer.Serialize(stringwriter, dataToSerialize, xns);
return stringwriter.ToString();
}
catch
{
throw;
}
}
public static T Deserialize<T>(string xmlText)
{
try
{
var stringReader = new System.IO.StringReader(xmlText);
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
catch
{
throw;
}
}
Make the following Class where you give the following attributes
[XmlRoot(ElementName = "Members", Namespace = "")]
public class Members
{
[XmlElement("Member")]
public Member[] member { get; set; }
}
public class Member
{
[XmlElementAttribute("Name")]
public string Name { get; set; }
[XmlElementAttribute("Status")]
public string Status { get; set; }
}
Then deserialize your data.
Members result = Deserialize<Members>(XML_String);
You got your members in a array and you ca convert that to a list if you want.
You can use LINQ
XElement xml = XElement.Load("locationToYourXmlFile");
var members = xml.Elements("member");
var list = members.Where(member => member.Element("status")?.Value == "Gold")
.Select(member => member.Element("name")?.Value)
.ToList();
Assuming your XML has a bunch of member elements under the root memberlist element, each with a name and status element inside that.
<?xml version="1.0" encoding="utf-8"?>
<memberlist>
<member>
<name>John</name>
<status>Gold</status>
</member>
<member>
<name>Sam</name>
<status>Silver</status>
</member>
<member>
<name>Sara</name>
<status>Gold</status>
</member>
</memberlist>
I'm trying to read an XML file and parse its content, but I'm having trouble extracting parameters from the file.
The XML file I'm trying to parse looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<register_map>
<Register ID="1" Index="0x100000" DataType="0x0007" ObjectType="0x07" Name="Device Type"/>
<Register ID="2" Index="0x100100" DataType="0x0005" ObjectType="0x07" Name="Error Register"/>
</register_map>
</root>
My code so far looks like this
namespace Test_XML
{
class Program
{
struct RegisterEntry
{
public UInt32 index;
public UInt16 dataType;
public UInt16 objectType;
public string name;
};
static void Main(string[] args)
{
XDocument doc = XDocument.Load("registers.xml");
var registers = doc.Descendants("register_map");
foreach (var register in registers)
{
// Fill up a list of RegisterEntrys with contents of XML
}
Console.ReadLine();
}
}
}
How can I extract the parameters from "registers" and place them in a RegisterEntry object?
You can use
var registers = doc.XPathSelectElements("/root/register_map/Register");
It will give you collection of Registernodes, so you wil be able to access their attributes and populate your RegisterEntry object something like:
foreach (var register in registers)
{
var dataType = register.Attribute("DataType").Value;
//the rest of the code
}
Notice XPathSelectElements is an extension method in System.Xml.XPath namespace. Make sure you've referenced System.Xml.Linq assembly in order to use it.
You should use .Attributes["name"].Value. I take it you want those values converted to Int as well, so we need an additional Convert.ToInt(string, base);
var RegisteryEntryList = new List<RegistryEntry>();
foreach (var register in registers)
{
//create a new RegistryEntry
var obj = new RegistryEntry();
//convert your string to an int value and save it
obj.index = Convert.ToInt32(register.Attributes["Index"].Value.Split('x')[1], 8);
obj.datatype = Convert.ToInt32(register.Attributes["DataType"].Value.Split('x')[1], 8);
//... your remaining properties
RegisteryEntryList.Add(obj);
}
Please note: If your Index is binary (base 2) you need to adapt the conversion accordingly. For more information see https://msdn.microsoft.com/en-us/library/1k20k614(v=vs.110).aspx
Your query will get you all elements with the name register_map - you want all Register elements. Change it to this:
var registers = doc.Descendants("Registers");
Then iterate through them and take the values you need, converting them to the required types.
foreach (var register in registers)
{
var indexHex = (string)register.Attribute("Index");
var index = Convert.ToUInt32(indexHex, 16);
var dataTypeHex = (string)register.Attribute("DataType");
var dataType = Convert.ToUInt16(dataTypeHex, 16);
var objectTypeHex = (string)register.Attribute("ObjectType");
var objectType = Convert.ToUInt16(objectTypeHex, 16);
var name = (string)register.Attribute("Name");
var entry = new RegisterEntry
{
index = index,
dataType = dataType,
objectType = objectType,
name = name,
};
// do something with entry
}
Use xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<root>" +
"<register_map>" +
"<Register ID=\"1\" Index=\"0x100000\" DataType=\"0x0007\" ObjectType=\"0x07\" Name=\"Device Type\"/>" +
"<Register ID=\"2\" Index=\"0x100100\" DataType=\"0x0005\" ObjectType=\"0x07\" Name=\"Error Register\"/>" +
"</register_map>" +
"</root>";
XDocument doc = XDocument.Parse(xml);
var results = doc.Descendants("Register").Select(x => new {
id = (int)x.Attribute("ID"),
index = int.Parse(x.Attribute("Index").Value.Substring(2), NumberStyles.HexNumber, CultureInfo.CurrentCulture),
dataType = int.Parse(x.Attribute("DataType").Value.Substring(2), NumberStyles.HexNumber, CultureInfo.CurrentCulture),
objectType = int.Parse(x.Attribute("ObjectType").Value.Substring(2), NumberStyles.HexNumber, CultureInfo.CurrentCulture),
name = (string)x.Attribute("Name")
}).ToList();
}
}
}
I wish to use this API with a c# application:
http://www.affjet.com/2012/11/26/4-4-affjet-api/#more-3099
After adding the wsdl to my projcet i wrote this simple code :
(getTransactions gets a object[] #params and returns a string)
Ws_ApiService service = new Ws_ApiService();
string apiKey = "*************";
var response = service.getTransactions(new object[] { apiKey });
i tried few more ways but couldnt get a right response,
i tried :
var response = service.getTransactions(new object[] { "apiKey:****"});
and
var response = service.getTransactions(new object[] { "apiKey","******"});
Here is the php code that does the same from their docs :
<?php
$nameSpace = "https://secure.affjet.com/ws/api";
//Creating AffJet client for SOAP
$client = new SoapClient($nameSpace."?wsdl");
$pageNumber = 0;
//Setting up parameters
$params = array();
$params["apiKey"] = "MY_API_KEY";
//Value for parameters (optional)
//$params["networkId"] = array(1,2);
//$params["pageNumber"] = 0;
//$params["pageSize"] = 10;
//Making Request
$response = $client->getNetworks($params);
//XML to SimpleXMLElement Object
$xmlResponse = new SimpleXMLElement($response);
if ($xmlResponse->success == "true"){
while (isset($xmlResponse->dataList->data)) {
//Iterate the results
foreach ($xmlResponse->dataList->data as $data){
var_dump(xml2array($data));
}
//Requesting next page of data
$pageNumber++;
$params["pageNumber"] = $pageNumber;
//Making Request
$response = $client->getNetworks($params);
//XML to SimpleXMLElement Object
$xmlResponse = new SimpleXMLElement($response);
}
} else {
//Error somewhere
echo $xmlResponse->errorMessage;
}
/**
* Transforms the object SimpleXmlElement into an array, easier to handle
*/
function xml2array($xml) {
$arr = array();
foreach ($xml as $element) {
$tag = $element->getName();
$e = get_object_vars($element);
if (!empty($e)) {
$arr[$tag] = $element instanceof SimpleXMLElement ? xml2array($element) : $e;
} else {
$arr[$tag] = trim($element);
}
}
return $arr;
}
?>
this was the response for what i tried :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://secure.affjet.com/ws/api"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getTransactionsResponse>
<return xsi:type="xsd:string">
<response><success>false</success><errorMessage>
API Key not provided</errorMessage><dataList>
</dataList></response>
</return>
</ns1:getTransactionsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
you can see :
API Key not provided
And the response should be something like this:
<response>
<success>true</success>
<errorMessage></errorMessage>
<dataList>
<data>
<date>2012-11-05 15:02:41</date>//Transaction Date
<amount>81.67</amount>
<commission>15.86</commission>
<status>confirmed</status>//Status, could be: declined, pending, confirmed or paid
<clickDate></clickDate>
<ip></ip>
<custom_id>MyCustomId</custom_id>//Custom Id for the transactions (SID, SubId,clickRef....)
<unique_id>2548462</unique_id>//Unique Id given from the network to this transaction
<merchantId>1</merchantId>//Id for the Merchant on AffJet
<networkId>1</networkId>//Id for the Network on AffJet
</data>
</dataList>
</response>
all i need to supply is a parameter named "apiKey" and its value
EDIT :
after contacting their support, they said the request should look like this :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://secure.affjet.com/ws/api"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns2="http://xml.apache.org/xml-soap"
xmlns:SOAP- ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getTransactions>
<params xsi:type="ns2:Map">
<item>
<key xsi:type="xsd:string">apiKey</key>
<value xsi:type="xsd:string">YOURAPIKEY</value>
</item>
</params>
</ns1:getTransactions>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Any ideas ?
I dug a little deeper into this fascinating topic and have to say that working with what amounts to an associative array is just a pain in the .NET SOAP implementation. An associative array is represented as an IDictionary (e.g. Hashtable) – but refuses to be serialized (try it!).
The below code is the closest I could get – and for some reason (bug?) it does not work on the .NET framework, but does work on Mono.
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Text;
public class Test
{
/*
* as per http://stackoverflow.com/a/1072815/2348103
*/
public class Item
{
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string key;
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string value;
}
[SoapType(TypeName = "Map", Namespace = "http://xml.apache.org/xml-soap")]
public class Map : List<Item>
{
}
public static void Main()
{
Map map = new Map();
map.Add( new Item { key="foo", value="bar" } );
map.Add( new Item { key="quux", value="barf" } );
XmlTypeMapping mapping =
(new SoapReflectionImporter()).ImportTypeMapping( map.GetType() );
XmlSerializer serializer = new XmlSerializer( mapping );
XmlTextWriter writer = new XmlTextWriter( System.Console.Out );
writer.Formatting = Formatting.Indented;
writer.WriteStartElement( "root" );
serializer.Serialize( writer, map );
writer.WriteEndElement();
writer.Close();
}
}
/*
//
// does not work - but see http://msdn.microsoft.com/en-us/magazine/cc164135.aspx
//
public class Map : IXmlSerializable
{
const string NS = "http://xml.apache.org/xml-soap";
public IDictionary dictionary;
public Map()
{
dictionary = new Hashtable();
}
public Map(IDictionary dictionary)
{
this.dictionary = dictionary;
}
public void WriteXml(XmlWriter w)
{
w.WriteStartElement("Map", NS);
foreach (object key in dictionary.Keys)
{
object value = dictionary[key];
w.WriteStartElement("item", NS);
w.WriteElementString("key", NS, key.ToString());
w.WriteElementString("value", NS, value.ToString());
w.WriteEndElement();
}
w.WriteEndElement();
}
public void ReadXml(XmlReader r)
{
r.Read(); // move past container
r.ReadStartElement("dictionary");
while (r.NodeType != XmlNodeType.EndElement)
{
r.ReadStartElement("item", NS);
string key = r.ReadElementString("key", NS);
string value = r.ReadElementString("value", NS);
r.ReadEndElement();
r.MoveToContent();
dictionary.Add(key, value);
}
}
public System.Xml.Schema.XmlSchema GetSchema() { return null; }
}
*/
Sample output from Mono:
<q1:Map xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="id1" d2p1:arrayType="Item[2]" xmlns:d2p1="http://schemas.xmlsoap.org/soap/encoding/" xmlns:q1="http://xml.apache.org/xml-soap">
<Item href="#id2" />
<Item href="#id3" />
</q1:Map>
[...]
Sample output from .NET:
<q1:Array xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="id1" q1:arrayType="Item[2]" xmlns:q1="http://schemas.xmlsoap.org/soap/encoding/">
<Item href="#id2" />
<Item href="#id3" />
</q1:Array>
[...]
Either you can use KeyValue pair class or Dictionary class as follows:
Dictionary<string, string> d = new Dictionary<string, string>();
d.Add("apiKey", "******");
var response = new object[] { d };
KeyValuePair<string, string> d = new KeyValuePair<string, string>("apiKey", "******");
var response = new object[] { d };
It appears the problem is the difference between array in PHP and C#. In PHP, its a key value pair. How doest his look in the generated class that was created from the wdsl? Here is a line to a SO question that is related to your issue.
C# equivalent to php associative array One answer says to try Dictionary<String, String>. Maybe be worth a try to use KeyValuePair<String, String> passed as an object array.
KeyValuePair<String, String> parm = new KeyValuePair<String, String>("apiKey","******");
var response = service.getTransactions(new object[] { parm });
I currently have a C# program that writes data to an XML file in using the .NET Framework.
if (textBox1.Text!="" && textBox2.Text != "")
{
XmlTextWriter Writer = new XmlTextWriter(textXMLFile.Text, null);
Writer.WriteStartDocument();
Writer.WriteStartElement("contact");
Writer.WriteStartElement("firstName");
Writer.WriteString(textBox1.Text);
Writer.WriteEndElement();
Writer.WriteEndElement();
Writer.WriteEndDocument();
Writer.Close();
}
else
{
MessageBox.Show("Nope, fill that textfield!");
}
The problem is that my XML file gets overwritten every time I try to save something new.
I've had both null and Encoding.UTF8 for the second parameter in the XmlTextWriter but it doesn't seem to be what changes the non-overwrite/overwrite function.
You could use a XDocument:
public static void Append(string filename, string firstName)
{
var contact = new XElement("contact", new XElement("firstName", firstName));
var doc = new XDocument();
if (File.Exists(filename))
{
doc = XDocument.Load(filename);
doc.Element("contacts").Add(contact);
}
else
{
doc = new XDocument(new XElement("contacts", contact));
}
doc.Save(filename);
}
and then use like this:
if (textBox1.Text != "" && textBox2.Text != "")
{
Append(textXMLFile.Text, textBox1.Text);
}
else
{
MessageBox.Show("Nope, fill that textfield!");
}
This will create/append the contact to the following XML structure:
<?xml version="1.0" encoding="utf-8"?>
<contacts>
<contact>
<firstName>Foo</firstName>
</contact>
<contact>
<firstName>Bar</firstName>
</contact>
</contacts>
The only way to add data to an XML file is to read it in, add the data, and then write out the complete file again.
If you don't want to read the entire file into memory, you can use the streaming interfaces (e.g., XmlReader/XmlWriter) to interleave your reads, appends, and writes.
Just to add to Darin's answer, here is an article that I was getting ready to include in my own answer as a good reference for how to use XDocument to append nodes to an existing XML document:
http://davidfritz.wordpress.com/2009/07/10/adding-xml-element-to-existing-xml-document-in-c/
Instead of writing out the XML manually, I would consider using the XmlSerializer along with a generic List. It looks like your needs are simple so memory usage isn't much of a concern. To add an item you will have to load the list and write it out again.
void Main()
{
var contacts = new List<Contact>
{
{new Contact { FirstName = "Bob", LastName = "Dole" }},
{new Contact { FirstName = "Bill", LastName = "Clinton" }}
};
XmlSerializer serializer = new XmlSerializer(typeof(List<Contact>));
TextWriter textWriter = new StreamWriter(#"contacts.xml");
serializer.Serialize(textWriter, contacts);
textWriter.Close();
}
public class Contact
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}