Append List to XML - c#

I am trying to append my list to an XML file.
I have my c# class PasswordSettings which contains some properties:
public class PasswordSettings {
public string customerRef { get; set; }
public string node { get; set; }
public string name { get; set; }
public string login { get; set; }
public string password { get; set; }
public string fileType { get; set; }
}
I have a list of PasswordSettings like this:
public List<PasswordSettings> Logins = new List<PasswordSettings>();
I now add elements to my object and add the object to my list:
PasswordSettings settings = new PasswordSettings();
settings.customerRef = "abc";
settings.name = "test";
Logins.add(settings);
Now I want to add this list to an XML file so I end up with something like:
<PasswordSettings>
<Logins>
<customerRef>abc</customerRef>
<name>test</name>
</Logins>
</PasswordSettings>
And if I want to add another login, it will append to the XML file, i.e. not replace or overwrite anything, so a new <Logins>
I have tried multiple methods and I either get null pointers or nothings gets written. I suppose the nullpointer could be because the XML file is empty, but I just want it to add this list as an XML structure.

here is a solution to create xml or add a new record, so after you could adapt following what you want:
PasswordSettings settings = new PasswordSettings();
settings.customerRef = "abc";
settings.name = "test";
Logins.Add(settings);
settings = new PasswordSettings();
settings.customerRef = "def";
settings.name = "test1";
Logins.Add(settings);
foreach (var login in Logins)
{
if (!File.Exists(#"e:\Test.xml"))
{
XDocument doc =
new XDocument(
new XElement("PasswordSettings",
new XElement("Logins",
new XElement("customerRef", login.customerRef),
new XElement("name", login.name)
)
)
);
doc.Save(#"e:\Test.xml");
}
else
{
XDocument doc = XDocument.Load(#"e:\Test.xml");
XElement root = doc.Element("PasswordSettings");
IEnumerable<XElement> rows = root.Descendants("Logins");
XElement firstRow = rows.First();
firstRow.AddBeforeSelf(
new XElement("Logins",
new XElement("customerRef", login.customerRef),
new XElement("name", login.name)));
doc.Save(#"e:\Test.xml");
}
}
}
xml output:
<?xml version="1.0" encoding="utf-8"?>
<PasswordSettings>
<Logins>
<customerRef>def</customerRef>
<name>test1</name>
</Logins>
<Logins>
<customerRef>abc</customerRef>
<name>test</name>
</Logins>
</PasswordSettings>
here i add at the beginning of file, if you want to add at the end of file, just do:
XElement firstRow = rows.Last();
firstRow.AddAfterSelf(
new XElement("Logins",
new XElement("customerRef", login.customerRef),
new XElement("name", login.name)));
output:
<?xml version="1.0" encoding="utf-8"?>
<PasswordSettings>
<Logins>
<customerRef>abc</customerRef>
<name>test</name>
</Logins>
<Logins>
<customerRef>def</customerRef>
<name>test1</name>
</Logins>
</PasswordSettings>

Related

How to deserialize this xml doc into list

In app a get a response from vk server with information about user's playlist in xml. App throw InvalidOperationexception here
var result = (PlayList)serializer.Deserialize(reader);
DTOs:
public class PlayList
{
[XmlElement("audio")]
public List<Song> Audio { get; set; }
public PlayList()
{
Audio = new List<Song>();
}
}
public class Song
{
[XmlElement(ElementName ="id")]
public int Id { get; set; }
...
[XmlElement(ElementName ="genre_id")]
public int Genre_id { get; set; }``
}
But my code work when I delete this 3 lines from xmlfile
<response>
<count>156</count>
...
<response>
and <items list="true"> -> <items>
What I must change in my code to make it work?
var serializer = new XmlSerializer(typeof(PlayList), new XmlRootAttribute("items"));
using (var stringReader = new StringReader(xml))
using (var reader = XmlReader.Create(stringReader))
{
var result = (PlayList)serializer.Deserialize(reader);
Console.WriteLine(result.Audio[1].Title);
}
And this is an example of xml.
How do I Deserialize this XML document?
var xml =
#"<?xml version="1.0" encoding="utf-8"?>
<response>
<count>156</count>
<items list="true">
<audio>
<id>456239034</id>
<owner_id>181216176</owner_id>
<artist>Oh Wonder</artist>
<title>Technicolour Beat</title>
<duration>179</duration>
<date>1465249779</date>
<url>http://cs613222.vk.me/u285269348/audios/4ae051b98797.mp3?extra=MS3dvwutPkFx7k8rQdV3Szuh7cSwLkRcS_KpPbO9DXviMFLNNgkDAmZFWdIueioL3dDgdPUc7rch0V81KgOHYaTTSampaRcljxrJcytJYImZssivVP7DigKdcxaLoALeUatAhuHk5gXQ7TY</url>
<lyrics_id>235824304</lyrics_id>
<genre_id>1001</genre_id>
</audio>
<audio>
<id>456239033</id>
<owner_id>181216176</owner_id>
<artist>Mikky Ekko</artist>
<title>We Must Be Killers (Волчонок / Teen Wolf / 2х08) </title>
<duration>195</duration>
<date>1465249755</date>
<url>http://cs521610.vk.me/u14558277/audios/c2daca7b2b6f.mp3?extra=z9VPdKf6v- n7zkIfZ_6ej-RZSjlIjAr_qYmVp4F-zI1Z3ZXgVtOUElovlOiSOgSuKbFC0e0ahac8XU-AxNtfEYYPe5gcejSotr84mHi0LQ2L-b0BPWP2cYn5Yy44YN4FLPNKq0Ow8vMKFn0</url>
<lyrics_id>26311225</lyrics_id>
</audio>
</items>
</response>";
You need to let it know its an array, I think using typeof(PlayList[]) instead of typeof(PlayList)
You can just skip unnecessary nodes with the XmlReader.
using (var reader = XmlReader.Create(stringReader))
{
reader.ReadToFollowing("items");
var result = (PlayList)serializer.Deserialize(reader);

Can't read xml nodes

I've the following XML saved into settings.config:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Settings>
<Type>15</Type>
<Module>True</Module>
<Capacity>10</Capacity>
</Settings>
I've created a class like this:
public class Settings
{
public int Type { get; set; }
public bool Module { get; set; }
public int Capacity { get; set; }
}
and this is my code that deserialize the XML:
XDocument doc = XDocument.Load("settings.config");
var settings = doc.Root
.Elements("Settings")
.Select(x => new Settings
{
Type = (int)x.Attribute("Type"),
Module = (bool)x.Attribute("Module"),
Capacity = (int)x.Attribute("Capacity"),
})
.ToList();
The problem is that the settings variable return Count = 0. What am I doing wrong?
A few issues with your XML
<Settings> is your Root, it is not an element of your root. If you want to have multiple <Settings>, then make a new root element, and put the <Settings> tags inside that.
Type, Module, and Capacity are Elements, not Attributes
If you only have 1 settings note, you can do something like the following:
var settignsNode = doc.Element("Settings");
var settings = new Settings()
{
Type = (int)settignsNode.Element("Type"),
// ...
};
Working example, but answer above is really explain what is going here
XDocument doc = XDocument.Parse("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?><Settings><Type>15</Type><Module>True</Module><Capacity>10</Capacity></Settings>");
var settings = doc
.Elements("Settings")
.Select(x => new Settings
{
Type = (int.Parse(x.Elements("Type").First().Value)),
Module = bool.Parse(x.Elements("Module").First().Value),
Capacity = (int.Parse(x.Elements("Capacity").First().Value)),
})
.ToList();
Working code
XDocument doc = XDocument.Parse("<Settings><Type>15</Type><Module>True</Module><Capacity>10</Capacity></Settings>");
var settings = doc
.Elements("Settings")
.Select(x => new Settings
{
Type = (int)x.Element("Type"),
Module = (bool)x.Element("Module"),
Capacity = (int)x.Element("Capacity"),
})
.ToList();

Construction xml file: This document already has a ' DocumentElement ' node

I am trying to construct a .xml file of the form
<Orders>
<Id type="System.Int32">1</Id>
<OrderItems>
<OrderItem>
<Id type="System.Int32">321</Id>
<Product type="System.String">Coffee</Product>
</OrderItem>
</OrderItems>
<Client type="System.String">Johnny</Client>
<Orders>
For Order model:
public class Order
{
public int Id { get; set; }
public List<OrderItem> Products { get; set; }
public string Client { get; set; }
}
Here, I create the Order element
public void SaveToFile(IEnumerable<Order> elementsList)
{
XmlDocument xmlDoc = new XmlDocument();
XmlDeclaration xmlDec = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
xmlDoc.PrependChild(xmlDec);
XmlElement elemRoot = xmlDoc.CreateElement("Orders");
xmlDoc.AppendChild(elemRoot);
XmlHelper<Order> xmlHelper = new XmlHelper<Order>();
foreach (var order in _orders)
{
xmlHelper.AddNodeToXmlDocument(xmlDoc, elemRoot, order);
}
xmlDoc.PreserveWhitespace = true;
xmlDoc.Save(_filePath);
}
And here, I am trying to construct the sub-elements. It works fine for Id and Client, but when I try to create the order items, I get this error at line document.AppendChild(elemRoot);
public void AddNodeToXmlDocument(XmlDocument document, XmlElement rootElement, object myObject)
{
XmlElement myObjectElement = document.CreateElement(EntityFormatter.GetObjectName(myObject));
foreach (var objectProperty in EntityFormatter.GetPropertiesAndValues(myObject))
{
if ((objectProperty.Value.GetType().FullName).ToString().Contains("System.Collections.Generic.List"))
{
Regex regex = new Regex(#"Models[.][A-Za-z]+");
Match match = regex.Match(objectProperty.Value.ToString());
var elemRoot = document.CreateElement(match.Value.Substring(7));
document.AppendChild(elemRoot);
foreach (var obj in objectProperty.Value.ToString())
{
AddNodeToXmlDocument(document, elemRoot, obj);
}
}
else
{
var elem = document.CreateElement(objectProperty.Key);
elem.SetAttribute("type", objectProperty.Value.GetType().FullName);
elem.InnerText = objectProperty.Value.ToString();
myObjectElement.AppendChild(elem);
}
}
rootElement.AppendChild(myObjectElement);
}
XML specification only allows single root element in a document. document.AppendChild(elemRoot) line in your AddNodeToXmlDocument() method throws exception because root element has been created before in the SaveToFile() method :
.....
XmlElement elemRoot = xmlDoc.CreateElement("Orders");
xmlDoc.AppendChild(elemRoot);
.....
It isn't clear what you're trying to do with the erroneous line, maybe you want to append elemRoot to the previously created root element instead :
.....
var elemRoot = document.CreateElement(match.Value.Substring(7));
document.DocumentElement.AppendChild(elemRoot);
.....

XML Serialize Example, first steps

I have following exercise to do ...
I shall get following xml-file ...
<?xml version="1.0" encoding="UTF-8"?>
<Mitarbeiterstatistik xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Mitarbeiter>
<Vorname>Horst</Vorname>
<Nachname>Schneider</Nachname>
<Id>1</Id>
</Mitarbeiter>
<Mitarbeiter>
<Vorname>Tanja</Vorname>
<Nachname>Lindner</Nachname>
<Id>2</Id>
</Mitarbeiter>
</Mitarbeiterstatistik>
Now I tried following steps ...
I made a class Mitarbeiter!
public class Mitarbeiter
{
private string vorname;
private string nachname;
private int id;
public Mitarbeiter()
{
}
public Mitarbeiter(string vorname, string nachname, int id)
{
this.vorname = vorname;
this.nachname = nachname;
this.id = id;
}
public string Vorname
{
get { return vorname; }
set { vorname = value; }
}
public string Nachname
{
get { return nachname; }
set { nachname = value; }
}
public int Id
{
get { return id; }
set { id = value; }
}
}
Then I made a class Mitarbeiterstatistik with a list for Mitarbeiter objects ...
[XmlRoot("Mitarbeiterstatistik")]
public class Mitarbeiterstatistik
{
private List<Mitarbeiter> list = new List<Mitarbeiter>();
[XmlArray("List")]
public List<Mitarbeiter> List
{
get { return list; }
set { list = value; }
}
}
My Main-Class looks like ...
class Program
{
static void Main(string[] args)
{
Mitarbeiterstatistik maStatistik = new Mitarbeiterstatistik();
Mitarbeiter ma1 = new Mitarbeiter("Horst", "Schneider", 1);
Mitarbeiter ma2 = new Mitarbeiter("Tanja", "Lindner", 2);
maStatistik.List.Add(ma1);
maStatistik.List.Add(ma2);
XmlSerializer serializer = new XmlSerializer(typeof(Mitarbeiterstatistik));
XmlWriter writer = XmlWriter.Create(#"D:\test.xml");
serializer.Serialize(writer, maStatistik);
writer.Close();
}
}
Now I got following result ...
<?xml version="1.0" encoding="UTF-8"?>
<Mitarbeiterstatistik xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
**<List>**
<Mitarbeiter>
<Vorname>Horst</Vorname>
<Nachname>Schneider</Nachname>
<Id>1</Id>
</Mitarbeiter>
<Mitarbeiter>
<Vorname>Tanja</Vorname>
<Nachname>Schneider</Nachname>
<Id>2</Id>
</Mitarbeiter>
**</List>**
</Mitarbeiterstatistik>
No I have an Element "List" in my Xml-file ... :-)
What can I do against my problem ...
Is there only the possibility to define only a Mitarbeiter class and NO Mitarbeiterstatistik-Class?
Maybe as following?
List<Mitarbeiter> list = new List<Mitarbeiter>();
Mitarbeiter ma1 = new Mitarbeiter("Horst", "Schneider", 1);
Mitarbeiter ma2 = new Mitarbeiter("Tanja", "Lindner", 2);
list.Add(ma1);
list.Add(ma2);
XmlSerializer serializer = new XmlSerializer(typeof(List<Mitarbeiter>), new XmlRootAttribute("Mitarbeiterstatistik"));
XmlWriter writer = XmlWriter.Create(#"D:\test.xml");
serializer.Serialize(writer, list);
writer.Close();
Or is there a chance to keep my Mitarbeiterstatistik-Class??? And disable my List-Element???
If you want to try Linq To Xml:
XDocument xDoc = new XDocument(new XElement("Mitarbeiterstatistik"));
foreach (var mitarbeiter in list)
{
xDoc.Root.Add(
new XElement("Mitarbeiter",
new XElement("Vorname" ,mitarbeiter.Vorname ),
new XElement("Nachname" ,mitarbeiter.Nachname ),
new XElement("Id" ,mitarbeiter.Id )));
}
xDoc.Save(#"d:\test.xml");
You can get out of attribute "List" (as i undestand your question correctly) using [XmlElement] with name of element you want to get instead of [XmlArray]:
[XmlRoot("Mitarbeiterstatistik")]
public class Mitarbeiterstatistik
{
private List<Mitarbeiter> list = new List<Mitarbeiter>();
[XmlElement("Mitarbeiter")]
public List<Mitarbeiter> List {get; set;}
}

removing namespace tag (xmlns:) from XMLSerializer

I want to generate following xml output in my C# code :
<?xml version="1.0" encoding="utf-16"?>
<CallConnectReq Xmlns="urn:interno-com:ns:a9c" reqId="9" msgNb="2">
<LocalCallId>0</LocalCallId>
</CallConnectReq>
right now I am achieving this as follows:
var xnameSpace = new XmlSerializerNamespaces();
xnameSpace.Add("Xmlns", Constants.XmlNameSpaceValue);
var xmlSerializer = new XmlSerializer(objToSerialize.GetType());
var stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, objToSerialize, xnameSpace);
return stringWriter.ToString().**Replace("xmlns:","");**
But I want to remove "xmlns:" tag without using Replace() method.
Is there any way to do it?
To add just the default namespace:
var xnameSpace = new XmlSerializerNamespaces();
xnameSpace.Add("", "urn:interno-com:ns:a9c");
var ser = new XmlSerializer(typeof (CallConnectRequest));
ser.Serialize(destination, new CallConnectRequest(), xnameSpace);
with:
[XmlRoot("CallConnectReq", Namespace = "urn:interno-com:ns:a9c")]
public class CallConnectRequest {}
If you genuinely want Xmlns (which, to restate, I strongly believe is a typo of xmlns, and if not: is a bad choice in that it adds confusion), then:
var xnameSpace = new XmlSerializerNamespaces();
xnameSpace.Add("", "");
var ser = new XmlSerializer(typeof (CallConnectRequest));
ser.Serialize(destination, new CallConnectRequest {
RequestId = 9,
MessageNumber = 2,
LocalCallId = 0
}, xnameSpace);
using:
[XmlRoot("CallConnectReq")]
public class CallConnectRequest {
[XmlAttribute("Xmlns"), Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public string XmlNamespace {
get { return "urn:interno-com:ns:a9c";} set { }
}
[XmlAttribute("reqId")]
public int RequestId { get; set; }
[XmlAttribute("msbNb")]
public int MessageNumber { get; set; }
[XmlElement("LocalCallId")]
public int LocalCallId { get; set; }
}
which writes:
<?xml version="1.0" encoding="ibm850"?>
<CallConnectReq Xmlns="urn:interno-com:ns:a9c" reqId="9" msbNb="2">
<LocalCallId>0</LocalCallId>
</CallConnectReq>

Categories

Resources