How can i update xml file in c# - c#

I write console application program
this is my xml file:
<?xml version="1.0" encoding="utf-8" ?>
<Settings>
<AsteriskHost type="string">172.16.18.14</AsteriskHost>
</Settings>
I run this code
public void Set(List<AcmSettings> acmSettings)
{
XElement xelement = XElement.Load("Settings.xml");
IEnumerable<XElement> settings = xelement.Elements();
foreach (var item in acmSettings)
{
settings.FirstOrDefault(x => x.Name == item.Name).SetValue("treeee");
}
xelement.Save("Settings.xml");
}
this my test:
[Test]
public void SetShouldUpdateValue()
{
var settingsManager = new SettingsManager();
const string newIp = "165.166.167.167";
const string elemntName = "AsteriskHost";
var acmSetting = new List<AcmSettings> { new AcmSettings { Name = elemntName, Value = newIp } };
settingsManager.Set(acmSetting);
var setting = settingsManager.Get(x => x.Name == elemntName).FirstOrDefault();
Assert.IsTrue(setting != null);
Assert.IsTrue(setting.Value== newIp);
}
I don't have any error but my new value not save in file.
How can I update xml node in c#

I tried your Set method, and it runs ok for me. I did have to tweak your current implementation by changing just one line:
// settings.FirstOrDefault(x => x.Name == item.Name).SetValue("treeee");
settings.FirstOrDefault(x => x.Name == item.Name).SetValue(item.Value);
Perhaps the problem is with your Get method. Here is a quick (not production quality) Get implementation. Using this implementation, your unit test runs successfully.
// note - just a string (name) passed in
public XElement Get(string name)
{
XElement xelement = XElement.Load("Settings.xml");
IEnumerable<XElement> settings = xelement.Elements();
return settings.FirstOrDefault(x => x.Name == name);
}
The other possibility is that, as suggested in the comments above, is that you are looking at your project XML file, and not looking at the output XML file.

Try like this
XmlDocument xmlDom = new XmlDocument();
xmlDom.Load("YourXMLFILEPATH.xml");
XmlNode newXMLNode = xmlDom.SelectSingleNode("/Settings/AsteriskHost");
newXMLNode.InnerText = YourValue;
xmlDom.Save("YourXMLFILEPATH.xml");
Console.WriteLine(xmlDom);
Have you tried this ?

You can modify your set method like this.
public void Set(List<AcmSettings> acmSettings)
{
XElement xelement = XElement.Load("Settings.xml");
IEnumerable<XElement> settings = xelement.Elements();
foreach (var item in acmSettings)
{
xelement.Descendants(item.Name).FirstOrDefault().Value = item.Value;
}
xelement.Save("Settings.xml");
}

Related

How to get separate values from Xlement

This is a portion of XML I'm trying to parse
<BRTHDATES>
<BRTHDATE value="5/1/1963" code="B"/>
</BRTHDATES>
var birthdates = xmlDoc.XPathSelectElements("/INDV/PERSON/BRTHDATES").Elements().Where(e => e.Name == "BRTHDATE");
xe = birthdates.Elements().Where(e => e.Name == "BRTHDATE");
bbs = from b in birthdates
select new
{
Birthdays = b.FirstAttribute.Value,
Code = b?.Value
};
var status = birthdates.Elements().Where(e => e.Name.LocalName == "BRTHDATE").Single().Value;
When I try to get "Value" from the Element I get an empty string. I can't get anything for the "code" attribute.
It sure seems like this should be a lot easier...
You can try below code. I've already tested through a test project and got the require value.
string personBirthday = string.Empty;
string soapResult = #"<?xml version=""1.0"" encoding=""utf - 8"" ?><INDV> <PERSON> <BRTHDATES><BRTHDATE value = ""5/1/1963"" code = ""B"" /> </BRTHDATES></PERSON></INDV> ";
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(soapResult));
XmlNodeList person = doc.GetElementsByTagName("BRTHDATES");
if (person[0].ChildNodes.Count > 0)
{
foreach (XmlNode item in person[0].ChildNodes)
{
if (item.Name.Trim().Equals("BRTHDATE"))
{
personBirthday = !string.IsNullOrEmpty(item.Attributes[0].Value) ? item.Attributes[0].Value.Trim() : string.Empty;
}
}
}
Here is the solution
You can select specific Element from a Xml. Just try below sample code
XmlNodeList generalTabNodeList = xmlDocument.SelectNodes("/INDV/PERSON/BRTHDATES");
foreach (XmlNode node in generalTabNodeList)
{
if (node.ChildNodes.Count > 0)
{
string birthdate = !string.IsNullOrEmpty(node.ChildNodes[0].ToString()) ? node.ChildNodes[2].InnerText.ToString() : string.Empty;
}
}
I can't quite follow what you are trying to do, but, this should get you going:
For an XML file that looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<INDV>
<PERSON>
<BRTHDATES>
<BRTHDATE value="5/1/1963" code="B"/>
</BRTHDATES>
</PERSON>
</INDV>
(Note, this is an entire XML document - one that matches your code, not just the snippet you provided (that doesn't match your code))
This code will pick out the value and code attributes:
using (var xmlStream = new FileStream("Test.xml", FileMode.Open))
{
XDocument xmlDocument = XDocument.Load(xmlStream);
var birthDateElements = xmlDocument.XPathSelectElements("/INDV/PERSON/BRTHDATES/BRTHDATE");
var birthDateElement = birthDateElements.FirstOrDefault();
if (birthDateElement != null)
{
var attributes = birthDateElement.Attributes();
var valueAttribute = attributes.Where(a => a.Name == "value");
var codeAttribute = attributes.Where(a => a.Name == "code");
}
}
You can play around with this code to figure out what you want to do. Whatever you do, don't pick out attributes by position, pick them out by name.

Edit existing XML file tree

I have problem with an editting existing xml file. I was looking for a solution but I can not find solution which I need. Can someone help me please?
Here is my code:
private void referenceToXML(string path)
{
var filePath = path;
var xmlDoc = XDocument.Load(filePath);
var parentElement = new XElement("Items");
var firstNameElement = new XElement("Item");
firstNameElement.SetAttributeValue("name", question.text);
var lastNameElement = new XElement("Cathegory", SM.text);
parentElement.Add(firstNameElement);
firstNameElement.Add(lastNameElement);
var rootElement = xmlDoc.Element("ItemCollection");
rootElement.Add(parentElement);
xmlDoc.Save(path);
}
And here is result of the code:
https://pastebin.com/LKGJER38
But I need this:
https://pastebin.com/RRC75pR8
I will appreciate every help.
Add to the Items Element instead :
private void referenceToXML(string path)
{
var xmlDoc = XDocument.Load(path);
xmlDoc.Element("ItemCollection").Element("Items").Add(
new XElement("Item", new XAttribute("name", question.text), SM.text));
xmlDoc.Save(path);
}
Your problem is that you are unconditionally adding an <Items> element every time you add an <Item> element. Instead, you need to check whether such an element exists, and if so, use it. The following extension method makes that easy:
public static partial class XNodeExtensions
{
public static XElement GetOrAddElement(this XContainer container, XName name)
{
if (container == null || name == null)
throw new ArgumentNullException();
var element = container.Element(name);
if (element == null)
container.Add(element = new XElement(name));
return element;
}
}
Now you can modify your referenceToXML method to use it as follows:
private static void referenceToXML(string path, string questionText, string smText)
{
AddItem(XDocument.Load(path), questionText, smText).Save(path);
}
static XDocument AddItem(XDocument doc, string questionText, string smText)
{
var firstNameElement = new XElement("Item");
firstNameElement.SetAttributeValue("name", questionText);
var lastNameElement = new XElement("Cathegory", smText);
firstNameElement.Add(lastNameElement);
// Get or create the root element ItemCollection
var root = doc.GetOrAddElement("ItemCollection");
// Get or create the Items list
var items = root.GetOrAddElement("Items");
// Add the item
items.Add(firstNameElement);
return doc;
}
Demo fiddle here.
Note I modified your code to make question.text and SM.text arguments instead of class members for clarity and testing purposes.

Get data from XML in simple way

I am using the following code to get data from the OData XML and its works ,
but I am not sure that I fully understand it so maybe there is a way to write it in simple way?
what i need is to get the property value which is in the first loop value = 0001 and text = approve and in the
second value = 0002 text = reject
The code
XNamespace dns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
if (response.StatusCode == HttpStatusCode.OK)
{
string decisionOptions = ReadResponse(response);
XDocument document = XDocument.Parse(decisionOptions);
foreach (XElement element in document.Element(dns + "DecisionOptions").Elements(dns + "element"))
{
PropertyKeyRef decisionOption = new PropertyKeyRef();
decisionOption.PropertyValue = element.Element(dns + "DecisionKey").Value;
decisionOption.PropertyName = element.Element(dns + "DecisionText").Value;
dat.Add(decisionOption);
}
}
the XML
<?xml version="1.0" encoding="utf-8" ?>
- <d:DecisionOptions xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
- <d:element m:type="TAS.DecisionOption">
<d:InstanceID>007</d:InstanceID>
<d:DecisionKey>0001</d:DecisionKey>
<d:DecisionText>Approve</d:DecisionText>
<d:CommentMandatory>false</d:CommentMandatory>
<d:Nature>POSITIVE</d:Nature>
</d:element>
- <d:element m:type="TAS.DecisionOption">
<d:InstanceID>007</d:InstanceID>
<d:DecisionKey>0002</d:DecisionKey>
<d:DecisionText>Reject</d:DecisionText>
<d:CommentMandatory>true</d:CommentMandatory>
<d:Nature>NEGATIVE</d:Nature>
</d:element>
</d:DecisionOptions>
here how can do it in simple way using LINQ
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
XDocument xdoc = XDocument.Load("test.xml");
XNamespace dns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
//in xml every element should have it's namespace for this reason I have to concatenate namespace with the name of element
var elementsRes = xdoc.Root.Elements(dns+"element").Select((elt) => new PropertyKeyRef { PropertyName = elt.Element(dns+"DecisionKey").Value.ToString(),PropertyValue = elt.Element(dns+"DecisionText").Value.ToString() }).ToList();
foreach (var item in elementsRes)
{
//your code for the result
}
}
}
public class PropertyKeyRef
{
public string PropertyName
{ get; set; }
public string PropertyValue
{ get; set; }
}
}
You have already achieved it in simplest way. Little bit of LINQ might improve readability (get away with foreach loop) but it's just syntactic sugar of what you have written.
XNamespace dns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
XDocument document = XDocument.Load("database.xml");
PropertyKeyRef decisionOption = new PropertyKeyRef();
decisionOption.PropertyValue = document.Descendants(dns + "DecisionKey")
.Select(node => node.Value).First();
decisionOption.PropertyName = document.Descendants(dns + "DecisionText")
.Select(node => node.Value).First();
dat.Add(decisionOption);

Find all the child node of specific value in C#

<main>
<myself>
<pid>1</pid>
<name>abc</name>
</myself>
<myself>
<pid>2</pid>
<name>efg</name>
</myself>
</main>
that is my XML file named simpan. I have two button. next and previous. What i want to do is, all the info will shows off on the TextBox when the user click the button. The searching node will be based on the pid.
Next button will adding 1 value of pid (let's say pid=2) and it will search on the node that have the same value of pid=2. it also will show the name for the pid=2. (showing name=abc)
Same goes to the previous button where it will reduce 1value of pid (pid=1).
Does anybody knows how to do this?
//-------------EDIT------------------
thanks to L.B, im trying to use his code. however i got an error.
is my implementation of code correct?
private void previousList_Click(object sender, EventArgs e)
{
pid = 14;
XDocument xDoc = XDocument.Parse("C:\\Users\\HDAdmin\\Documents\\Fatty\\SliceEngine\\SliceEngine\\bin\\Debug\\simpan.xml");
var name = xDoc.Descendants("myself")
.First(m => (int)m.Element("PatientID") == pid)
.Value;
textETA.Text = name;
////////////////////
}
int pid = 2;
XDocument xDoc = XDocument.Parse(xml); //Load
var name = xDoc.Descendants("myself")
.First(m => (int)m.Element("pid") == pid)
.Element("name")
.Value;
You can use the following XPath to list all Myself tags, then look for what you want using a simple Linq command:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "file1.xml");
var resNodes = xmlDoc.SelectNodes("//myself");
XmlNode res = null;
var val = textBox1.Text;
var item = from XmlNode x in resNodes
select x;
foreach (var nodP in item) {
foreach (XmlNode nod in nodP.ChildNodes) {
if (nod.InnerText == val) {
res = nodP;
}
}
}
if (res == null)
// not found!
;
else
// show the result
;
Call me old fashioned but you could use an XPath, for example:
string xml =
#"<main>
<myself>
<pid>1</pid>
<name>abc</name>
</myself>
<myself>
<pid>2</pid>
<name>efg</name>
</myself>
</main>";
using System.Xml;
....
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
// Replace "2" in the string below with the desired pid
XmlNode xmlNode =
xmlDocument.DocumentElement.SelectSingleNode("myself/name[../pid=2]");
// xmlNode contains the <name>efg</name> XmlElement. For example:
string name = xmlNode.Value;
If it can match multiple nodes, for example there could be multiple <myself> elements with a child element <pid> set to 2, use the following instead:
foreach(XmlNode xmlNode in
xmlDocument.DocumentElement.SelectNodes("myself/name[../pid=2]"))
{
// xmlNode contains the matching <name> element
}
In both cases, the value can be extracted from the XmlNode using the Value property.
public class simpman
{
private static XElement root = XElement.Load("Simpman.xml");
public static string GetItem(int index)
{
XElement item =
(from element in root.Elements("myself")
where (int)element.Element("pid") == index
select element.Element("name")).SingleOrDefault();
return item != null ? item.Value : "Please check the Index";
}
}
Initialize a static itemIndex to 1 and use it further like itemIndex++ (for Next) and itemIndex-- (for Prev).
private void previousList_Click(object sender, EventArgs e)
{
pid = 14;
XDocument xDoc = XDocument.Load(#"C:\Users\HDAdmin\Documents\Fatty\SliceEngine\SliceEngine\bin\Debug\simpan.xml");
var name = xDoc.Root
.Descendants("myself")
.FirstOrDefault(e => e.Element("pid")
.Value
.Equals(pid.ToString(CultureInfo.InvariantCulture)))
.Element("name")
.Value;
textETA.Text = name;
}
XmlDocument doc = new XmlDocument();
FileStream fs = new FileStream(rootXMLPath, FileMode.Open, FileAccess.Read);
doc.Load(fs);
XmlNode node = doc.DocumentElement;
nodeName = "/main/myself";
var child1 = node.SelectSingleNode(nodeName).ChildNodes[0].FirstChild.InnerXml;
var child2 = node.SelectSingleNode(nodeName).ChildNodes[0].LastChild.InnerXml;
var child3 = node.SelectSingleNode(nodeName).ChildNodes[1].FirstChild.InnerXml;
var child4 = node.SelectSingleNode(nodeName).ChildNodes[1].LastChild.InnerXml;

XmlDocument query taking two values

How I can make following query
If I have XmlDocument and it may have following xml
<EquipmentParameterModified dateTime="2011-04-06T12:03:10.00+01:00" parameter="ExtApp">
<Extensions ParameterId="External App Interface" FromParameterValue="" ToParameterValue="DISABLED"/>
</EquipmentParameterModified>
How I can check that I have EquipmentParameterModified and take values of ParameterId and ToParameterValue
Thanks for help.
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(new StringReader(xmlstr));
XmlNode node = xmldoc.GetElementsByTagName("Extensions").Item(0);
string id = node.Attributes["ParameterId"].Value;
string val = node.Attributes["ToParameterValue"].Value;
Are you trying to find the element given the 2 input search values? What do you want your output to be? If you just want to see that you have a matching element, this code should do the trick:
If yes, try something like this:
public static void Main()
{
var paramId = "External App Interface";
var toParameterValue = "DISABLED";
var xdoc = XDocument.Parse(#"
<EquipmentParameterModified dateTime='2011-04-06T12:03:10.00+01:00' parameter='ExtApp'>
<Extensions ParameterId='External App Interface' FromParameterValue='' ToParameterValue='DISABLED'/>
</EquipmentParameterModified>");
var ret = xdoc.Root
.Elements("Extensions")
.Where(e => e.Attribute("ParameterId").Value == paramId &&
e.Attribute("ToParameterValue").Value == toParameterValue)
.FirstOrDefault();
if (ret != null)
Console.WriteLine(ret.Name);
}
Update for .NET 2.0 & XmlDocument:
public static void Main()
{
var paramId = "External App Interface";
var toParameterValue = "DISABLED";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(#"
<EquipmentParameterModified dateTime='2011-04-06T12:03:10.00+01:00' parameter='ExtApp'>
<Extensions ParameterId='External App Interface' FromParameterValue='' ToParameterValue='DISABLED'/>
</EquipmentParameterModified>");
XmlNode node = xmlDoc.GetElementsByTagName("Extensions")[0];
if (node.Attributes["ParameterId"].Value == paramId &&
node.Attributes["ToParameterValue"].Value == toParameterValue)
{
Console.WriteLine("Found matching node:" + node.Name);
return;
}
}
I recommend using XPath to get the element you're aiming for, do a null check, then get specific attributes of that element, doing a null check on the attribute value before calling the .Value property.

Categories

Resources