Can't read xml nodes - c#

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();

Related

Append List to XML

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>

Serialize/deserialize XML with multiple elements with same name and incrementing number using XmlSerializer

I need to serialize an class related to this:
public class Root {
public string[] Elements {get;set;}
}
to an XML like this:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Element_01>1st element</Element_01>
<Element_02>2nd element</Element_02>
<Element_03>3rd element</Element_03>
<Element_04>4th element</Element_04>
</Root>
when the object is instantiated like so:
var root = new Root {
Elements = new[] {
"1st element", "2nd element", "3rd element"
"4th element"
}
};
using the System.Xml.Serialization.XmlSerializer.
I have to do it the other way round, too.
Is there any way to achieve this?
You may want to explore an alternative way using XLinq, for your particular scenario it would be simpler and easier, take a look to how your Root class may be rewritten:
public class Root
{
public string[] Elements { get; set; }
public string GetXmlString()
{
var rootElement = new XElement("Root");
for (var i = 0; i < Elements.Length; i++)
{
var tag = $"Element_{(i + 1).ToString().PadLeft(2, '0')}";
var xElement = new XElement(tag, Elements[i]);
rootElement.Add(xElement);
}
return rootElement.ToString();
}
public static Root DeserializeXmlString(string xmlString)
{
var rootElement = XElement.Parse(xmlString);
var elementsArray = rootElement
.Elements()
.Select(xElement => xElement.Value)
.ToArray();
return new Root {Elements = elementsArray};
}
}
And testing:
private static void Main()
{
var root = new Root
{
Elements = new[]
{
"1st element", "2nd element", "3rd element", "4th element"
}
};
var xmlString = root.GetXmlString();
Console.WriteLine(xmlString);
var deserializedRoot = Root.DeserializeXmlString(xmlString);
foreach (var element in deserializedRoot.Elements)
Console.WriteLine(element);
Console.ReadLine();
}
Result:
You have only to add error validation code and you are pretty much done. For more info on LINQ to XML check this

String builder to XML traverse through each node

Hi all I am having an XML data which is formed in StringBuilder as follows
StringBuilder sb = new StringBuilder();
sb.Append("<?xml version=\"1.0\" encoding=\"utf-16\"?>");
sb.Append("<TEST>"
+ "<DEMO><CONTENTINFO name=\"Nani\" receiver=\"Lucky\""
+ "/></DEMO></TEST>");
XmlDocument XMLDocument = new XmlDocument();
XMLDocument.LoadXml(sb.ToString());
XmlNodeList nodeList = XMLDocument.FirstChild.ChildNodes;
foreach (XmlNode node in nodeList)
{
}
I tried using XMLDocument to traverse through child nodes to get the data I need to split the data so that it should give name=Nani and receiver=lucky or store the key and value in a dictionary like dic.Add("name","nani") and dic.Add("receiver","lucky") . So can some one help me how to sort it out
If you prefer having a strong set of class instances being formed then use the XmlSerializer and create classes to represent each of the levels of your XML structure.
[XmlRoot("TEST")]
public class Test
{
[XmlElement(Name = "DEMO")]
public Demo Demo
{
get;
set;
}
}
public class Demo
{
[XmlElement("CONTENTINFO")]
public ContentInfo ContentInfo
{
get;
set;
}
}
public class ContentInfo
{
[XmlAttribute(Name = "name")]
public string Name
{
get;
set;
}
[XmlAttribute(Name = "receiver")]
public string Reciever
{
get;
set;
}
}
XmlSerializer serializer = new XmlSerializer(typeof(Test));
serializer.Serialize(....);
Test testInstance = serializer.Deserialize(....);
... etc.
The above code has not been tested but should give you the gist.
Why are you using a StringBuilder to generate your XML? There are much better ways:
var root = new XDocument();
var test = new XElement("TEST");
var demo = new XElement("DEMO");
var contentInfo = new XElement("CONTENTINFO",
new XAttribute("name", "Nani"),
new XAttribute("receiver", "Lucky"));
demo.Add(contentInfo);
test.Add(demo);
root.Add(test);
To pull out the values you need into a dictionary you can use the following LINQ query:
var foo = root.Descendants("DEMO").Elements("CONTENTINFO")
.SelectMany(x => x.Attributes())
.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
This will give you a dictionary looking like this:
Key: name =
Value: Nani,
Key: receiver = Value: Lucky

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>

C# Foreach XML Node

I'm saving 2-dimensional coordinates on an XML file with a structure similar to:
<?xml version="1.0" encoding="utf-8" ?>
<grid>
<coordinate time="78">
<initial>540:672</initial>
<final>540:672</final>
</coordinate>
</grid>
I can open the XML file and read it via the XmlTextReader, but how do I loop through the coordinates specifically to retrieve both the time attribute and data between the initial and final nodes in some format similar to:
string initial = "540:672";
string final = "540:672";
int time = 78;
New Code:
My New Code:
//Read the XML file.
XDocument xmlDoc = XDocument.Load("C:\\test.xml");
foreach (var coordinate in xmlDoc.Descendants("coordinate"))
{
this.coordinates[this.counter][0] = coordinate.Attribute("time").Value;
this.coordinates[this.counter][1] = coordinate.Element("initial").Value;
this.coordinates[this.counter][2] = coordinate.Element("final").Value;
this.counter++;
};
but now I get this error:
"Object reference not set to an instance of an object."
XML
<?xml version="1.0" encoding="utf-8"?>
<grid>
<coordinate time="62">
<initial>540:672</initial>
<final>540:672</final>
</coordinate>
...
<coordinate time="46">
<initial>176:605</initial>
<final>181:617</final>
</coordinate>
</grid>
Skipped a few coordinate tags to fit, but they all had the time attribute and initial/final subtags.
Globals
uint counter = 0;
// Coordinates to be retrieved from the XML file.
string[][] coordinates;
You might want to check into something like Linq-to-XML:
XDocument coordinates = XDocument.Load("yourfilename.xml");
foreach(var coordinate in coordinates.Descendants("coordinate"))
{
string time = coordinate.Attribute("time").Value;
string initial = coordinate.Element("initial").Value;
string final = coordinate.Element("final").Value;
// do whatever you want to do with those items of information now
}
That should be a lot easier than using straight low-level XmlTextReader....
See here or here (or a great many other places) for introductions to Linq-to-XML.
UPDATE:
please try this code - if it works, and you get all the coordinates in that resulting list, then the Linq-to-XML code is fine:
Define a new helper class:
public class Coordinate
{
public string Time { get; set; }
public string Initial { get; set; }
public string Final { get; set; }
}
and in your main code:
XDocument xdoc = XDocument.Load("C:\\test.xml");
IEnumerable<XElement> cords= xdoc.Descendants("coordinate");
var coordinates = cords
.Select(x => new Coordinate()
{
Time = x.Attribute("time").Value,
Initial = x.Element("initial").Value,
Final = x.Element("final").Value
});
How does this list and its contents look like?? Do you get all the coordinates you're expecting??
You could have used XmlSerialization to make the XML into a simple list of coordinate classes with a small amount of work, e.g.
public class coordinate
{
[XmlAttribute]
public int time;
[XmlElement(ElementName="initial")]
public string initial;
[XmlElement(ElementName = "final")]
public string final;
public coordinate()
{
time = 0;
initial = "";
final = "";
}
}
public class grid
{
[XmlElement(ElementName="coordinate", Type = typeof(coordinate))]
public coordinate[] list;
public grid()
{
list = new coordinate[0];
}
}
Then in your code:
XmlReader r = new XmlReader.Create(...);
grid g = (grid) new XmlSerializer(typeof(grid)).Deserialize(r);

Categories

Resources