i have one xml string like this
string stxml="<Status>Success</Status>";
I also creaated one xml document
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode rootNode = doc.CreateElement("StatusList");
doc.AppendChild(rootNode);
i need an output like this.
<StatusList>
<Status>Success</Status>
</StatusList>
How can i achieve this.if we using innerhtml,it will insert.But i want to insert xml string as a xmlnode itself
A very simple way to achieve what you are after is to use the often overlooked XmlDocumentFragment class:
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode rootNode = doc.CreateElement("StatusList");
doc.AppendChild(rootNode);
//Create a document fragment and load the xml into it
XmlDocumentFragment fragment = doc.CreateDocumentFragment();
fragment.InnerXml = stxml;
rootNode.AppendChild(fragment);
Using Linq to XML:
string stxml = "<Status>Success</Status>";
XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("StatusList", XElement.Parse(stxml)));
You could instead use the XElement class:
string stxml = "<Status>Success</Status>";
var status = XElement.Parse(stxml);
var statusList = new XElement("StatusList", status);
var output = statusList.ToString(); // looks as you'd like
If you want to write the new statusList content to a file:
statusList.Save(#"C:\yourFile.xml", SaveOptions.None);
you ca try it using xmlwriter
using (XmlWriter writer = XmlWriter.Create("new.xml"))
{
writer.WriteStartDocument();
writer.WriteStartElement("StatusList");
writer.WriteElementString("Status", "Success"); // <-- These are new
writer.WriteEndDocument();
}
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Reflection;
using System.ComponentModel;
public class MyClass
{
public static void RunSnippet()
{
XmlNode node = default(XmlNode);
if(node == null)
Console.WriteLine(bool.TrueString);
if(node != null)
Console.WriteLine(bool.FalseString);
XmlDocument doc = new XmlDocument();
node = doc.CreateNode (XmlNodeType.Element,"Query", string.Empty);
node.InnerXml=#"<Where><Eq><FieldRef Name=""{0}"" /><Value Type=""{1}"">{2}</Value></Eq></Where>";
string xmlData = ToXml<XmlNode>(node);
Console.WriteLine(xmlData);
XmlNode node1 = ConvertFromString(typeof(XmlNode), #"<Query><Where><Eq><FieldRef Name=""{0}"" /><Value Type=""{1}"">{2}</Value></Eq></Where></Query>") as XmlNode;
if(node1 == null)
Console.WriteLine(bool.FalseString);
if(node1 != null)
Console.WriteLine(bool.TrueString);
string xmlData1 = ToXml<XmlNode>(node1);
Console.WriteLine(xmlData1);
}
public static string ToXml<T>(T t)
{
string Ret = string.Empty;
XmlSerializer s = new XmlSerializer(typeof(T));
using (StringWriter Output = new StringWriter(new System.Text.StringBuilder()))
{
s.Serialize(Output, t);
Ret = Output.ToString();
}
return Ret;
}
public static object ConvertFromString(Type t, string sourceValue)
{
object convertedVal = null;
Type parameterType = t;
if (parameterType == null) parameterType = typeof(string);
try
{
// Type t = Type.GetType(sourceType, true);
TypeConverter converter = TypeDescriptor.GetConverter(parameterType);
if (converter != null && converter.CanConvertFrom(typeof(string)))
{
convertedVal = converter.ConvertFromString(sourceValue);
}
else
{
convertedVal = FromXml(sourceValue, parameterType);
}
}
catch { }
return convertedVal;
}
public static object FromXml(string Xml, Type t)
{
object obj;
XmlSerializer ser = new XmlSerializer(t);
using (StringReader stringReader = new StringReader(Xml))
{
using (System.Xml.XmlTextReader xmlReader = new System.Xml.XmlTextReader(stringReader))
{
obj = ser.Deserialize(xmlReader);
}
}
return obj;
}
#region Helper methods
public static void Main()
{
try
{
RunSnippet();
}
catch (Exception e)
{
string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
Console.WriteLine(error);
}
finally
{
Console.Write("Press any key to continue...");
Console.ReadKey();
}
}
private static void WL(object text, params object[] args)
{
Console.WriteLine(text.ToString(), args);
}
private static void RL()
{
Console.ReadLine();
}
private static void Break()
{
System.Diagnostics.Debugger.Break();
}
#endregion
}
From my experience it is always better to work with unique id's i suggest u look in that situation first and then come back to this page, and research/position my code for a try if u did not yet have a solution for it.
I just finished it on my side for my own project, i have modified abit to look more integrated for your project.
Good luck. Sorry for the late response ;-)
XmlDocument xDoc = new XmlDocument();
string Bingo = "Identification code";
xDoc.Load(pathFile);
XmlNodeList idList = xDoc.GetElementsByTagName("id");
XmlNodeList statusList = xDoc.GetElementsByTagName("Status");
for (int i = 0; i < idList.Count; i++)
{
StatusNode = "<Status>fail</Status>";
XmlDocumentFragment fragment = xDoc.CreateDocumentFragment();
fragment.InnerXml = StatusNode;
statusList[i].InnerXml = "";
statusList[i].AppendChild(fragment);
if (statusList[i].InnerText == Bingo)
{
StatusNode = "<Status>Succes!</Status>";
fragment.InnerXml = Status;
statusList[i].InnerXml = "";
statusList[i].AppendChild(fragment);
}
}
xDoc.Save(pathFile);
Related
In my MakeEnvelope method, I have added an event notification as follows:
var en = new EventNotification
{
Url = "<Listener URL>",
LoggingEnabled = "true",
RequireAcknowledgment = "true",
EnvelopeEvents = new List<EnvelopeEvent>
{
new EnvelopeEvent
{
EnvelopeEventStatusCode = "Completed",
IncludeDocuments = "true"
},
new EnvelopeEvent
{
EnvelopeEventStatusCode = "Delivered",
IncludeDocuments = "false"
},
new EnvelopeEvent
{
EnvelopeEventStatusCode = "Sent",
IncludeDocuments = "false"
}
}
};
envelopeDefinition.EventNotification = en;
I get the following XML response (I removed the Names and Emails, and changed the Guids):
<?xml version="1.0" encoding="utf-8"?><DocuSignEnvelopeInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.docusign.net/API/3.0"><EnvelopeStatus><RecipientStatuses><RecipientStatus><Type>Signer</Type><Email>someEmail#email.com</Email><UserName>SomeUserName</UserName><RoutingOrder>1</RoutingOrder><Sent>2021-04-28T14:14:41.163</Sent><Delivered>2021-04-28T14:14:54.997</Delivered><Signed>2021-04-28T14:14:59.73</Signed><DeclineReason xsi:nil="true" /><Status>Completed</Status><RecipientIPAddress>IP Address</RecipientIPAddress><ClientUserId>The ClientId</ClientUserId><CustomFields /><TabStatuses><TabStatus><TabType>SignHere</TabType><Status>Signed</Status><XPosition>938</XPosition><YPosition>1169</YPosition><TabLabel>Sign Here</TabLabel><TabName>SignHere</TabName><TabValue /><DocumentID>3</DocumentID><PageNumber>1</PageNumber></TabStatus></TabStatuses><AccountStatus>Active</AccountStatus><RecipientId>f571daaf-cd2c-4fge-a72e-d32277929305</RecipientId></RecipientStatus><RecipientStatus><Type>Signer</Type><Email>anotherEmail.Email.com</Email><UserName>Another Name</UserName><RoutingOrder>1</RoutingOrder><Sent>2021-04-28T14:14:41.503</Sent><DeclineReason xsi:nil="true" /><Status>Sent</Status><RecipientIPAddress /><CustomFields /><TabStatuses><TabStatus><TabType>SignHere</TabType><Status>Active</Status><XPosition>196</XPosition><YPosition>1169</YPosition><TabLabel>Sign Here</TabLabel><TabName>SignHere</TabName><TabValue /><DocumentID>3</DocumentID><PageNumber>1</PageNumber></TabStatus></TabStatuses><AccountStatus>Active</AccountStatus><RecipientId>1eb9d346-33ae-4444-b5f1-be30f8bcf041</RecipientId></RecipientStatus></RecipientStatuses><TimeGenerated>2021-04-28T14:15:03.3011225</TimeGenerated><EnvelopeID>3c9281c7-3345-44ac-9c4f-3d39274c49f4</EnvelopeID><Subject>Please sign this document</Subject><UserName>User Name</UserName><Email>Users Email Address Here</Email><Status>Sent</Status><Created>2021-04-28T14:14:40.41</Created><Sent>2021-04-28T14:14:41.557</Sent><ACStatus>Original</ACStatus><ACStatusDate>2021-04-28T14:14:40.41</ACStatusDate><ACHolder>Account Holders name</ACHolder><ACHolderEmail>Account Holders Email</ACHolderEmail><ACHolderLocation>DocuSign</ACHolderLocation><SigningLocation>Online</SigningLocation><SenderIPAddress>Senders IP Address</SenderIPAddress><EnvelopePDFHash /><CustomFields /><AutoNavigation>true</AutoNavigation><EnvelopeIdStamping>true</EnvelopeIdStamping><AuthoritativeCopy>false</AuthoritativeCopy><DocumentStatuses><DocumentStatus><ID>3</ID><Name>PG Document</Name><TemplateName /><Sequence>1</Sequence></DocumentStatus></DocumentStatuses></EnvelopeStatus></DocuSignEnvelopeInformation>
I was having issues parsing the response, so I created a console application to parse the xml string, and using the response xml shown above. The following is the code that I used to parse.
static void Main(string[] args)
{
string strXML = GetXML();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(strXML);
string xpath = "DocuSignEnvelopeInformation/EnvelopeStatus";
var nodes = xmlDoc.SelectNodes(xpath);
foreach (XmlNode childrenNode in nodes)
{
Console.WriteLine(childrenNode.SelectSingleNode("//status").Value);
}
Console.Read();
}
nodes is always empty.
What am I missing here?
Thank you in advance.
I was able to get it to work by using the namespace it was using.
var ns = new XmlNamespaceManager(xmlDoc.NameTable);
ns.AddNamespace("docusign", "http://www.docusign.net/API/3.0");
var envelopeId = xmlDoc.SelectSingleNode("//docusign:EnvelopeID", ns);
var status = xmlDoc.SelectSingleNode("//docusign:Status", ns);
I changed the method and I am able to get the values:
Request.InputStream.Position = 0;
var xmlDoc = new XmlDocument();
xmlDoc.Load(Request.InputStream);
var ns = new XmlNamespaceManager(xmlDoc.NameTable);
ns.AddNamespace("docusign", "http://www.docusign.net/API/3.0");
var envelopeId = xmlDoc.SelectSingleNode("//docusign:EnvelopeID", ns);
var status = xmlDoc.SelectSingleNode("//docusign:EnvelopeStatus/docusign:Status", ns);
if (envelopeId == null || String.IsNullOrEmpty(envelopeId.InnerText) || status == null || string.IsNullOrEmpty(status.InnerText)) return;
if (status.InnerText.ToLower() == "completed")
{
// Update the Document Status
var extra = _uow.JobExtraRepository.GetByEnvelopeId(envelopeId.InnerText);
extra.StatusId = (int)ExtraJobStatus.Completed;
Save();
var docBytes = xmlDoc.SelectSingleNode("//docusign:docBytes", ns);
}
I have researched a lot but I cannot find solution to my particular problem. I have to read an external xml file in C# and read the values in an Object. Here is the snapshot of my xml file:
<DatabaseList>
<DatabaseDetails>
<ConnectionId>1</ConnectionId>
<ConnectionName>MyConn1</ConnectionName>
<ServerConnection xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CobConnection>
<CobConnection />
<ConnectionType>MSSQL</ConnectionType>
<Database />
<Server />
</CobConnection>
<ConnectionType>MSSQL</ConnectionType>
<Database>MyDB1</Database>
<Port>2431</Port>
<Server>MyServerName1</Server>
</ServerConnection>
</DatabaseDetails>
<DatabaseDetails>
<ConnectionId>2</ConnectionId>
<ConnectionName>MyConn2</ConnectionName>
<ServerConnection xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CobConnection>
<CobConnection />
<ConnectionType>MSSQL</ConnectionType>
<Database />
<Server />
</CobConnection>
<ConnectionType>MSSQL</ConnectionType>
<Database>MyDB2</Database>
<Port>2431</Port>
<Server> MyServerName2</Server>
</ServerConnection>
</DatabaseDetails>
</DatabaseList>
For example, ConnectionName = MyConn2 is passed to the procedure below, code should read values for MyConn2. But in my case, I'm selecting the xmlNodesLvl2 correctly, but it starts from the beginning of the file. I need to read the value of node just found in previous step. For that particular Database.ConnectionName, I need to read the node values for eg, Database, ConnectionType, Server, etc. But I’m starting in next step from the beginning. I have put comment in my code //Problem here.
public static void GetInfo(string ConnectionName)
{
XmlDocument xmlDoc = new XmlDocument();
bool bfound = false;
xmlDoc.Load(#"C:\path..\Database.xml");
XmlNodeList xmlNodesLvl1 = xmlDoc.SelectNodes("DatabaseList/DatabaseDetails");
foreach (XmlNode xmlNode in xmlNodesLvl1)
{
if (xmlNode.HasChildNodes)
{
foreach (XmlNode item in xmlNode.ChildNodes)
{
string tagName = item.Name;
if (tagName == "ConnectionId")
{
Database.ConnectionId = item.InnerText;
}
if (tagName == "ConnectionName")
{
if (item.InnerText == ConnectionName)
{
Database.ConnectionName = item.InnerText;
bfound = true;
XmlNodeList xmlNodesLvl2 = null;
//Problem here
if (Enviroment == "COB")
{
xmlNodesLvl2 = xmlDoc.SelectNodes("DatabaseList/DatabaseDetails/ServerConnection/CobConnection");
}
else
{
xmlNodesLvl2 = xmlDoc.SelectNodes("DatabaseList/DatabaseDetails/ServerConnection");
}
foreach (XmlNode xmlNodeLvl2 in xmlNodesLvl2)
{
if (xmlNodeLvl2.HasChildNodes)
{
foreach (XmlNode itemLvl2 in xmlNodeLvl2.ChildNodes)
{
if (itemLvl2.Name == "CobConnection")
{
Database.CobConnection = itemLvl2.InnerText;
}
if (itemLvl2.Name == "Database")
{
Database.Name = itemLvl2.InnerText;
}
if (itemLvl2.Name == "ConnectionType")
{
Database.ConnectionType = itemLvl2.InnerText;
}
if (itemLvl2.Name == "Server")
{
Database.Server = itemLvl2.InnerText;
}
}
if (bfound == true)
{
break;
}
}
}
if (bfound == true)
{
break;
}
}
}
}
if (bfound == true)
{
break;
}
}
}
}
Please advise!
Try putting in DataTable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
DataTable dt = new DataTable();
dt.Columns.Add("ConnectionId",typeof(string));
dt.Columns.Add("ConnectionName",typeof(string));
dt.Columns.Add("CobConnection",typeof(string));
dt.Columns.Add("CobConnectionType",typeof(string));
dt.Columns.Add("CobDatabase",typeof(string));
dt.Columns.Add("CobServer",typeof(string));
dt.Columns.Add("ConnectionType",typeof(string));
dt.Columns.Add("Database",typeof(string));
dt.Columns.Add("Port",typeof(string));
dt.Columns.Add("Server", typeof(string));
List<XElement> details = doc.Descendants("DatabaseDetails").ToList();
foreach (XElement detail in details)
{
string id = (string)detail.Element("ConnectionId");
string name = (string)detail.Element("ConnectionName");
XElement xCobConnection = detail.Descendants("CobConnection").FirstOrDefault();
string cobConnection = (string)xCobConnection.Element("CobConnection");
string cobType = (string)xCobConnection.Element("ConnectionType");
string cobDatabase = (string)xCobConnection.Element("Database");
string cobServer = (string)xCobConnection.Element("Server");
XElement serverConnection = detail.Element("ServerConnection");
string connectionType = (string)serverConnection.Element("ConnectionType");
string database = (string)serverConnection.Element("Database");
string port = (string)serverConnection.Element("Port");
string server = (string)serverConnection.Element("Server");
dt.Rows.Add(new object[] {
id,
name,
cobConnection,
cobType,
cobDatabase,
cobServer,
connectionType,
database,
port,
server
});
}
}
}
}
I have a xml file as:-
<Data>
<Caption>
</Caption>
</Data>
I added a new child CData in the the following code
foreach (XmlNode item in childNode.ChildNodes)
{
if (item.Name == "Data")
{
XmlCDataSection CData;
CData = xml2.CreateCDataSection("All Jane Austen novels 25% off starting 3/23!");
item.InsertBefore(CData, item.FirstChild);
foreach (XmlNode itemC in item.ChildNodes)
{
if (itemC.Name == "Caption")
{
XmlElement getTemplateID = xml2.CreateElement("TempalteID");
getTemplateID.InnerText = "10010";
itemC.AppendChild(getTemplateID);
//if (OptionsData[0].Key == "NoChilds")
//{
// XmlElement Getnochild = itemDoc.CreateElement("CaptionOptions");
// Getnochild.InnerText = "";
// itemC.AppendChild(Getnochild);
//}
//else
//{
XmlNode elemCap = xml2.CreateNode(XmlNodeType.Element, "CaptionOptions", null);
itemC.AppendChild(elemCap);
XmlElement Getelem1 = xml2.CreateElement("CaptionField");
elemCap.AppendChild(Getelem1);
XmlElement elem2 = xml2.CreateElement("FieldID");
XmlElement elem3 = xml2.CreateElement("FieldID");
elem2.InnerText = "#FieldId1";
elem3.InnerText = "#FieldId2";
XmlElement elem4 = xml2.CreateElement("TextString");
XmlElement elem5 = xml2.CreateElement("TextString");
elem4.InnerText = "#TextString1";
elem5.InnerText = "#TextString2";
Getelem1.AppendChild(elem2);
Getelem1.AppendChild(elem4);
Getelem1.AppendChild(elem3);
Getelem1.AppendChild(elem5);
//}
}
}
}
}
Now my final xml is coming as
<Data>
<![CDATA[All Jane Austen novels 25% off starting 3/23!]]>
<Caption>
<TempalteID>10010</TempalteID>
<CaptionOptions><CaptionField>
<FieldID>#FieldId1</FieldID>
<TextString>#TextString1</TextString>
<FieldID>#FieldId2</FieldID>
<TextString>#TextString2</TextString>
</CaptionField></CaptionOptions>
</Caption>
</Data>
But I want to make it as the following way....
<Data><![CDATA[<Caption xmlns="http://www.iin.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.happy.xsd">
<TemplateID>T000114-NOW</TemplateID>
<CaptionOptions>
<CaptionField>
<FieldID>NOW1</FieldID>
<TextString>"Ep 01"</TextString>
</CaptionField>
<CaptionField>
<FieldID>NOW2</FieldID>
<TextString>""</TextString>
</CaptionField>
</CaptionOptions>
</Caption>]]>
</Data>
So as you can see I basically wanted my newly added child CData to make <Caption> as it's child. So basically I want to create a child and make an existing child as it's child.(But I don't think I would still get the same format?")
How to do it?
Using xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Runtime.InteropServices;
namespace ConsoleApplication23
{
class Program
{
static void Main(string[] args)
{
string xml = "<Data><Caption xmlns=\"http://www.iin.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.happy.xsd\"/></Data>";
XDocument doc = XDocument.Parse(xml);
XElement caption = doc.Descendants("Data").FirstOrDefault();
caption.Add(new XElement("TemplateID","T000114-NOW"));
XElement options = new XElement("CaptionOptions");
caption.Add(options);
foreach (Field field in Field.fields)
{
XElement newField = new XElement("CaptionField", new object[] { new XElement("FieldID", field.ID), new XElement("TextString", field.text)});
options.Add(newField);
}
}
}
public class Field
{
public static List<Field> fields = new List<Field>() {
new Field() { ID = "NOW1", text = "Ep 01"},
new Field() { ID = "Ep 01", text = ""}
};
public string ID { get; set; }
public string text { get; set; }
}
}
If I understand right, what you want to do is storing XML data in CDATA element. I want to remind you, that this is not what CDATA was intended to be used for, but here is example how to do that:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<book genre='novel' ISBN='1-861001-57-5'>" +
"<title>Pride And Prejudice</title>" +
"</book>");
//Add the new node to the document.
XmlElement root = doc.DocumentElement;
XmlCDataSection CData;
CData = doc.CreateCDataSection(root.InnerXml);
root.RemoveAll();
root.AppendChild(CData);
doc.Save(Console.Out);
I have that XML file which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<backupatmail>
<backup id="0">
<foldername>TestFolder</foldername>
<backupdate>09/10/2015</backupdate>
<comment>Sample comment text is here</comment>
<numberofparts>7</numberofparts>
<lastsucceed>Test.007</lastsucceed>
</backup>
<backup id="1">
<foldername>TestFolder2</foldername>
<backupdate>09/10/2015</backupdate>
<comment>Sample comment text is here</comment>
<numberofparts>15</numberofparts>
<lastsucceed>Test.015</lastsucceed>
</backup>
</backupatmail>
Now, I want to append new node(?):
<backup id="999">
<foldername>testing1</foldername>
<backupdate>99/99/9999</backupdate>
</backup>
I wrote following code:
public static void AddBackupToXML()
{
XmlDocument doc = new XmlDocument();
doc.Load(GlobalSettings.appDefaultFolder + "backups.xml");
XmlElement backupNodeNew = doc.CreateElement("backup");
XmlAttribute backupId = doc.CreateAttribute("id");
backupId.Value = "999";
backupNodeNew.Attributes.Append(backupId);
XmlNode nodeTitle = doc.CreateElement("foldername");
nodeTitle.InnerText = "testing1";
XmlNode nodeUrl = doc.CreateElement("backupdate");
nodeUrl.InnerText = "99/99/9999";
backupNodeNew.AppendChild(nodeTitle);
backupNodeNew.AppendChild(nodeUrl);
doc.DocumentElement.AppendChild(backupNodeNew);
doc.Save(GlobalSettings.appDefaultFolder + "backups.xml");
}
Is there any shorten way to do that and also keep simplicity at beginners level?
I will recommend you to use LINQ to XML. It has more simple API for working with XML and your code will look like
var file_name = GlobalSettings.appDefaultFolder + "backups.xml";
XDocument xdoc = XDocument.Load(file_name);
var backup999 = new XElement("backup",
new XAttribute("id", 999),
new XElement("foldername", "testing1"),
new XElement("backupdate", "99/99/9999")
);
xdoc.Root.Add(backup999);
xdoc.Save(file_name);
How I did it plenty of times, using copy special feature of visual studio http://blog.codeinside.eu/2014/09/08/Visual-Studio-2013-Paste-Special-JSON-And-Xml/ I generated the classed describing the xml structure, handle it really clean and easy from code and transfomed when required with System.Xml.Serialization https://support.microsoft.com/en-us/kb/815813 in xml doc or whatever was the need.
The same way from xml to c# object https://msdn.microsoft.com/en-us/library/fa420a9y(v=vs.110).aspx.
My personal preference is to not use the xml api directly. Rather, use the model object then serialize and de-serialize it. It's much cleaner in my opinion and the code to do what you actually need is only 3 lines once your have the generic serializer in place.
What you can do is de-serialize your object into an actual "backupatmail" object and then call backupatmail.BackUpItems.Add(your new item here) and then deserialize it back into a string.
This approach is slower than using LinqToXml during runtime but most of the time a extra millisecond or more isn't a big deal.
Here's the serialization/ deserialization code.
using System.Xml;
using System.Xml.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
public class SerializationUtils
{
public static T Deserialize<T>(string data)
{
XmlSerializer objSerializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(data))
{
return (T)objSerializer.Deserialize(reader);
}
}
public static string Serialize<T>(T obj)
{
XmlSerializer objSerializer = new XmlSerializer(typeof(T));
XmlSerializerNamespaces emptyNamespaces = new XmlSerializerNamespaces(new [] { XmlQualifiedName.Empty });
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Auto;
#if DEBUG
settings.Indent = true;
#else
settings.Indent = false;
#endif
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
objSerializer.Serialize(writer, obj, emptyNamespaces);
return stream.ToString();
}
}
}
and for your use.
string mailItems = GetXmlStringFromSomewhere();
var objMail = SerializationUtils.Deserialize<BackUpMail>(mailItems);
var newItem = new BackUp() { FolderName = "testing1", BackupDate = DateTime.Now};
objMail.BackUpItems.Add(newItem);
var strMailWAddedItem = SerializationUtils.Serialize(objMail);
Here are your entity classes.
public class BackUpMail
{
public List<BackUp> BackUpItems {get;set;}
}
public class BackUp
{
[XmlAttribute("id")]
public string ID {get;set}
[XmlElement("foldername")]
public string FolderName {get;set;}
[XmlElement("backupdate")]
public DateTime BackupDate {get;set;}
[XmlElement("comment")]
public string Comment {get;set}
[XmlElement("numberofparts")]
public string NumberOfParts {get;set}
[XmlElement("lastsucceed")]
public string LastSucceed {get;set}
}
Since you have the code, just parameterize it.
public static void someOtherMethod(){
XmlDocument doc = new XmlDocument();
doc.Load(GlobalSettings.appDefaultFolder + "backups.xml");
// some loop..
doc.DocumentElement.AppendChild(createNode(id[i], foldername[i], backupdate[i]));
doc.Save(GlobalSettings.appDefaultFolder + "backups.xml");
}
public static void createNode(string id, string foldername, string backupdate)
{
XmlElement backupNodeNew = doc.CreateElement("backup");
XmlAttribute backupId = doc.CreateAttribute("id");
backupId.Value = id;
backupNodeNew.Attributes.Append(backupId);
XmlNode nodeTitle = doc.CreateElement("foldername");
nodeTitle.InnerText = foldername;
XmlNode nodeUrl = doc.CreateElement("backupdate");
nodeUrl.InnerText = backupdate;
backupNodeNew.AppendChild(nodeTitle);
backupNodeNew.AppendChild(nodeUrl);
return backupNodeNew;
}
I played a little with Bond using this code:
using System;
using System.IO;
using System.Text;
using System.Xml;
using Bond;
using Bond.Protocols;
using NUnit.Framework;
public class Sandbox
{
[Test]
public void RoundtripWithSchema()
{
var sb = new StringBuilder();
var source = new WithSchema { Value = 1 };
using (XmlWriter xmlWriter = XmlWriter.Create(sb))
{
var writer = new SimpleXmlWriter(xmlWriter);
Serialize.To(writer, source);
}
var xml = sb.ToString();
Console.Write(xml);
Console.WriteLine();
using (var xmlReader = XmlReader.Create(new StringReader(xml)))
{
var reader = new SimpleXmlReader(xmlReader);
var roundtripped = Deserialize<WithSchema>.From(reader); // System.IO.InvalidDataException : Unexpected node type
Assert.AreEqual(source.Value, roundtripped.Value);
}
}
[Test]
public void RoundtripUsingSerializerWithSchema()
{
var sb = new StringBuilder();
var source = new WithSchema { Value = 1 };
using (XmlWriter xmlWriter = XmlWriter.Create(sb))
{
var writer = new SimpleXmlWriter(xmlWriter);
var serializer = new Serializer<SimpleXmlWriter>(typeof(WithSchema));
serializer.Serialize(source, writer);
}
var xml = sb.ToString();
Console.Write(xml);
Console.WriteLine();
using (var xmlReader = XmlReader.Create(new StringReader(xml)))
{
var reader = new SimpleXmlReader(xmlReader);
var serializer = new Deserializer<SimpleXmlReader>(typeof(WithSchema));
var roundtripped = serializer.Deserialize<WithSchema>(reader); // System.IO.InvalidDataException : Unexpected node type
Assert.AreEqual(source.Value, roundtripped.Value);
}
}
}
[Schema]
public class WithSchema
{
[Id(0)]
public int Value { get; set; }
}
Both samples output the expected xml:
<?xml version="1.0" encoding="utf-16"?>
<WithSchema>
<Value>1</Value>
</WithSchema>
Both fail when deserializing throwing System.IO.InvalidDataException : Unexpected node type
Don't know where to look for the bug really, suggestions?
The Bond SimpleXmlReader is having trouble with the <?xml version="1.0" encoding="utf-16"?> line. If you leave this out when serializing, you can deserialize without a problem.
Try something like this
using (XmlWriter xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
var writer = new SimpleXmlWriter(xmlWriter);
Serialize.To(writer, source);
}
My guess is that XmlNodeType.XmlDeclaration probably needs to be added to the IgnoredTokens set in Bond's SimpleXmlParser.
Bond versions later than v4.0.1 will have this issue (Bond issue #112 on GitHub) fixed.
Inspiration for this answer came from the Bond simple_xml sample.