Write XML with XDocument doesn't add XElements probably - c#

I am new to C# and Linq. I am trying to write my Dictionary to file as XML. Therefore I use a foreach loop add all XElements to a root XElement. This is added to the document. But it does only add the last iteration of my loop to the document. What am I doing wrong?
Here is the code
public void ToXml(string xmlFile)
{
//Dictionary used: Values
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null));
XElement xRoot = new XElement("RootElement");
doc.Add(xRoot);
Dictionary<double, double[]>.KeyCollection keys = Values.Keys;
foreach(double key in keys)
{
XElement inner = new XElement("InnerElement",
new XAttribute("value", key),
new XElement("TestValue1", Values[key][0]),
new XElement("Testvalue2", Values[key][1]),
new XElement("TestValue3", Values[key][2]),
new XElement("TestValue4", Values[key][3]),
new XElement("TestValue5", Values[key][4]),
new XElement("TestValue6", Values[key][5]));
xRoot.Add(inner);
}
doc.Save(xmlFile);
}
This is the output:
<?xml version="1.0" encoding="utf-8"?>
<RootElement>
<InnerElement value="400">
<TestValue1>0</TestValue1>
<Testvalue2>0</Testvalue2>
<TestValue3>200</TestValue3>
<TestValue4>0</TestValue4>
<TestValue5>100</TestValue5>
<TestValue6>491</TestValue6>
</InnerElement>
</RootElement>

Related

How to read an argument value from xml file?

I have the code in an .xml file, I would like to assign to the field the value of the attribute from the .xml file.
.csharp
private static string camera_model_c1_set = xml_read_set_cip_c1.Descendants("root").ElementAt("camera_model_c1_set").Att
.csharp
Parameter name: value '
XDocument name_of_file_xml = new XDocument(
new XComment("document"),
new XElement("root",
new XElement("name", new XAttribute ("name2", myvalue ))
)
);
.xml
<?xml version="1.0" encoding="utf-8"?>
<!--document-->
<root>
<name name2="myvalue" />
</root>
and I want to get this "myvalue" to .cs code to:
static string new_my_var = ... (?)
I have
XDocument xml_doc = XDocument.Load(path);
I care about using XDocument in this code. (instead of XmlDocument)
Try this for reading the attribute from an xml file :
XmlDocument doc = new XmlDocument();
doc.Load("Path/document.xml");
XmlNodeList elem = doc.GetElementsByTagName("name");
static string new_my_var = elem.Attributes["name2"].Value;

Iteration over XML returns Same Node Over & Over

The following is supposed to generate a list of all messages.
In practice I get a list of the rought length, but with the same element over and over.
Message is a class that get populated from the XmlNode sent to the constructor.
_messages = new List<Message>();
/*This does it*/
foreach (XmlNode n in thread.SelectNodes("//messages/message"))
{
_messages.Add(new Message(n));
}
/*So does this*/
XmlNode msgItr = thread.SelectSingleNode("//messages").FirstChild;
while (msgItr != null)
{
_messages.Add(new Message(msgItr));
msgItr = msgItr.NextSibling;
}
You are pathing to the wrong location, just use //message.
Here is two ways of enumerating the nodes, I am using LinqPad which Dump() shows one the current state.
XDocument xd = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Messages",
new XElement("Message", "Alpha"),
new XElement("Message", "Beta"),
new XElement("Message", "Omega")
));
xd.Descendants("Message").Dump("XDocument");
XmlDocument xmd = new XmlDocument();
xmd.LoadXml(xd.ToString());
xmd.SelectNodes("//Message")
.Dump("XmlDocument");
Here is the results for the first and second dumps

Save listbox items as child items in xml file using linq and c#

I have a relatively simple Winforms application and am using C#. I have been using LINQ (system.xml.linq) ... I have successfully been saving textbox items (single items) to my xml file.
I have a listBox of items and would like that list to be saved as child nodes in the xml file. So my xml final output would look something like this:
<items>
<centerName>My Center</centerName>
<poc>Mr. Jones</poc>
<servicedUnits>
<state>Texas</state>
<state>Iowa</state>
<state>Hawaii</state>
</servicedUnits>
</items>
I have this code that I have been using to write to XML:
private void writeFCATSettings()
{
XDocument doc = new XDocument
(
new XElement
("Items",
new XElement("textBoxCenterName", textBoxCenterName.Text),
new XElement("textBoxContactFirstName", textBoxContactFirstName.Text),
new XElement("servicedUnits", "<listBoxServicedUnits.Items>")
)
);
doc.Save(#"Settings.xml");
}
I am pretty sure I need to put code to iterate through the listbox between the brackets .
And lastly..I found this code that does iterate through my list...but if I just paste it into the space ... it doesn't work.
XElement servicedUnits = new XElement("ServicedUnits");
foreach (var item in listBoxServicedUnits.Items)
{
servicedUnits.Add(new XElement("unit", item));
}
XDocument document = new XDocument();
document.Add(servicedUnits);
Thank you for any ideas...
ER
Assuming your listbox's items are strings you could do this:
private void writeFCATSettings()
{
XDocument doc = new XDocument(
new XElement("Items",
new XElement("textBoxCenterName", textBoxCenterName.Text),
new XElement("textBoxContactFirstName", textBoxContactFirstName.Text),
new XElement("servicedUnits",
listBoxServicedUnits
.Items
.OfType<string>()
.Select(item => new XElement("unit", item)))));
doc.Save(#"Settings.xml");
}
Or, if they are not strings or they are mixed types you could do this:
private void writeFCATSettings()
{
XDocument doc = new XDocument(
new XElement("Items",
new XElement("textBoxCenterName", textBoxCenterName.Text),
new XElement("textBoxContactFirstName", textBoxContactFirstName.Text),
new XElement("servicedUnits",
listBoxServicedUnits
.Items
.OfType<Object>()
.Select(x => TransformYouObjectToAStringHere)
.Select(item => new XElement("unit", item)))));
doc.Save(#"Settings.xml");
}

Issue creating XML doc from Dictionary

My intention is to iterate through my lovely dictionary (both key and value are strings) and create an xml file from it.
I get the error on the last line (saving the xml).
"InvalidOperationException was unhandled
Token EndDocument in state Document would result in an invalid XML document."
Looking through this using breakpoints it would seem that at reaching the end of this, only the initial bit (outside the for each loop) has been done..
I'm half asking what silly mistake I've made, I'm partly asking if there's a more eloquent way of doing this.
Sorry if I've missed anything, let me know if i have, will add.
XDocument xData = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"));
foreach (KeyValuePair<string, string> kvp in inputDictionary)
{
xData.Element(valuesName).Add(
new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)));
}
xData.Save("C:\\xData.xml");
Currently you're adding multiple elements directly to the document - so you'd end up with either no root elements (if the dictionary is empty) or potentially multiple root elements (if there's more than one entry in the dictionary). You want a root element, and then your dictionary elements under that. Additionally, you're trying to find an element called valuesName without ever adding anything, so you'll actually get a NullReferenceException if there are any dictionary entries.
Fortunately, it's even easier than you've made it, because you can just use LINQ to transform your dictionary into a sequence of elements and put that in the doc.
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root",
inputDictionary.Select(kvp => new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)))));
doc.Save(#"c:\data.xml");
Complete sample app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
XName valuesName = "entry";
var dictionary = new Dictionary<string, string>
{
{ "A", "B" },
{ "Foo", "Bar" }
};
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root",
dictionary.Select(kvp => new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)))));
doc.Save("test.xml");
}
}
Output (order of entries is not guaranteed):
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
<entry key="A" value="B" />
<entry key="Foo" value="Bar" />
</root>
An alternative breakdown for this would be:
var elements = inputDictionary.Select(kvp => new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)));
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root", elements));
You may find this simpler to read.
try the following
XDocument xData = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"));
XElement myXml = new XElement("paramList");// make sure your root and your descendents do not shre same name
foreach (var entry in MyList)
{
myXml.Add(new XElement(valuesName,
new XElement("key", entry.key),
new XElement("value", entry.Value)
));
xData.Add(myXml);

Customizing an XML element using LINQ To XML

I have the following code:
XNamespace testNM = "urn:lst-emp:emp";
XDocument xDoc;
string path = "project_data.xml";
if (!File.Exists(path))
{
xDoc = new XDocument(
new XDeclaration("1.0", "UTF-16", null),
new XElement(testNM + "Test")
);
}
else
{
xDoc = XDocument.Load(path);
}
var element = new XElement("key",
new XElement("Type", type),
new XElement("Value", value));
xDoc.Element(testNM + "Test").Add(element);
// Save to Disk
xDoc.Save(path);
which produces an output in the XML file like this:
<?xml version="1.0" encoding="utf-16"?>
<Test xmlns="urn:lst-emp:emp">
<key xmlns="">
<Type>String</Type>
<Value>somestring</Value>
</key>
</Test>
How can I get an output like this in the XML file instead?
<?xml version="1.0" encoding="utf-16"?>
<Tests xmlns="urn:lst-emp:emp">
<key name="someString">
<Type>String</Type>
<Value>somestring</Value>
</key >
</Tests>
Note its only the 3rd line that has changed in the XML file.
You can do it this way:
var element = new XElement("key",
new XAttribute("name", "someString"),
new XElement("Type", "type"),
new XElement("Value", "value"));
To provide a complete version of Bilyukov's answer, this should produce the output expected. Obviously substitute the "someString" static string with a variable populated as you wish. Changes include using XName.Get(string, string) to create the appropriate XName objects for the XElement constructors.
XNamespace testNM = "urn:lst-emp:emp";
XDocument xDoc;
string path = "project_data.xml";
if (!File.Exists(path))
{
xDoc = new XDocument(
new XDeclaration("1.0", "UTF-16", null),
new XElement(XName.Get("Tests", testNM.NamespaceName))
);
}
else
{
xDoc = XDocument.Load(path);
}
var element = new XElement(XName.Get("key", testNM.NamespaceName),
new XAttribute("name", "someString"),
new XElement("Type", type),
new XElement("Value", value));
xDoc.Element(XName.Get("Tests", testNM.NamespaceName)).Add(element);
// Save to Disk
xDoc.Save(path);
Your XML has default namespace. Descendants of the element where default namespace declared is considered in the same default namespace, unless it is explicitly declared with different namespace. That's why you need to use the same XNamespace for <key> element. :
var element = new XElement(testNM +"key",
new XAttribute("name", "someString"),
new XElement(testNM +"Type", type),
new XElement(testNM +"Value", value));

Categories

Resources