Update element value in xml file - c#

I'm updating an xml file by this code,
public static void UpdateDesignCfg(string ChildName, string[,] AttribWithValue)
{
try
{
XmlDocument doc = new XmlDocument();
doc.Load("DesignCfg.xml");
XmlElement formData = (XmlElement)doc.SelectSingleNode("//" + ChildName);
if (formData != null)
{
for (int i = 0; i < AttribWithValue.GetLength(0); i++)
{
formData.SetAttribute(AttribWithValue[i, 0], AttribWithValue[i, 1]);
}
}
doc.Save("DesignCfg.xml");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
but I've often get this error ( not every time)
the process cannot access the file because it is being used by another process
so, Is there any way to " Release " the file after every change ?

UPDATE
The file is accessed from another place and is not closed. Use the same Load method in the other place.

I solved my problem, thanks so much #Ulugbek Umirov for help, the problem was on my ReadXmlFile Method, it was like this :
public static Color GetColor(string ChildName, string Attribute)
{
Color clr = new Color(); string v = "";
XmlTextReader reader = new XmlTextReader("DesignCfg.xml");
XmlDocument doc = new XmlDocument();
XmlNode node = doc.ReadNode(reader);
foreach (XmlNode chldNode in node.ChildNodes)
{
if (chldNode.Name == ChildName)
v = chldNode.Attributes["" + Attribute + ""].Value;
}
clr = System.Drawing.ColorTranslator.FromHtml(v);
return clr;
}
and the new one is :
public static Color GetColor(string ChildName, string Attribute)
{
Color clr = new Color();
string v = "";
XmlDocument doc = new XmlDocument();
doc.Load("DesignCfg.xml");
XmlElement formData = (XmlElement)doc.SelectSingleNode("//" + ChildName);
if (formData != null)
v = formData.GetAttribute(Attribute);
clr = System.Drawing.ColorTranslator.FromHtml(v);
return clr;
}
Thanks all for help :)

Related

A fast way to compare two XML files and create another one with differences

My friend wants to upload only product differences to his web shop. So my idea is to compare XML files and extract only changes. Thus I've created this:
Part of XML file (note that this XML have more elements, but I've excluded them):
<?xml version="1.0" encoding="UTF-8"?>
<artikli>
<artikal>
<id>1039282</id>
<sifra>42640</sifra>
<naziv><![CDATA[Bluetooth zvucnik za tablet IYIGLE X7 crni]]></naziv>
</artikal>
<artikal>
<id>1048331</id>
<sifra>48888</sifra>
<naziv><![CDATA[Bluetooth zvucnik REMAX RB-M15 crni]]></naziv>
</artikal>
</artikli>
C# script
static IEnumerable<XElement> StreamRootChildDoc(string uri)
{
using (XmlReader reader = XmlReader.Create(uri))
{
reader.MoveToContent();
while (!reader.EOF)
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "artikal")
{
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
}
else
{
reader.Read();
}
}
}
}
void ProcessFiles()
{
try
{
IEnumerable<XElement> posle = from el in StreamRootChildDoc(#"lisic2.xml")
select el;
IEnumerable<XElement> pre = from el in StreamRootChildDoc(#"lisic1.xml")
select el;
XmlDocument doc = new XmlDocument();
//(1) the xml declaration is recommended, but not mandatory
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
//(2) string.Empty makes cleaner code
XmlElement element1 = doc.CreateElement(string.Empty, "artikli", string.Empty);
doc.AppendChild(element1);
int count_files = 0;
foreach (XElement node_posle in posle)
{
count_files++;
var node_pre = pre.First(child => child.Element("id").Value == node_posle.Element("id").Value);
if (node_pre != null)
{
string pre_Value = node_pre.Value.Replace("\t", ""); ;
string posle_Value = node_posle.Value.Replace("\t", ""); ;
if (pre_Value != posle_Value)
{
var reader = node_posle.CreateReader();
reader.MoveToContent();
XmlElement element2 = doc.CreateElement(string.Empty, "artikal", reader.ReadInnerXml());
element1.AppendChild(element2);
}
}
}
doc.Save("document.xml");
}
finally
{
}
}
This works but after 10000 passed records the speed is 18 records per second, after 14000 - 12 records/sec. Is there any other approach to speed this up?
UPDATE
Now, I will try to move faster to the corresponding ID of checked XML.
One way to do it is with XmlDocument, just because the XML is small (22000 products) it is possible to use it.
void ProcessXMLDocument()
{
SetControlEnabled(btStart, false);
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
XmlDocument sada = new XmlDocument();
sada.Load(tbPathSada.Text);
XmlDocument pre = new XmlDocument();
pre.Load(tbPathOdPre.Text);
XmlDocument doc = new XmlDocument();
//(1) the xml declaration is recommended, but not mandatory
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
//(2) string.Empty makes cleaner code
XmlElement element1 = doc.CreateElement(string.Empty, "artikli", string.Empty);
doc.AppendChild(element1);
root = sada.DocumentElement;
XmlNodeList nodes = root.SelectNodes("artikal");
int count_files = 0;
foreach (XmlNode nodeSada in nodes)
{
count_files++;
try
{
SetControlText(lbBlokova, count_files.ToString());
TimeSpan elapsed = sw.Elapsed;
var files_per_sec = Math.Floor((double)count_files / (double)elapsed.TotalSeconds);
SetControlText(lbPerSecond, files_per_sec.ToString());
SetControlText(lbTime, elapsed.ToString(#"hh\:mm\:ss"));
}
catch (Exception ex2)
{
}
var idSada = nodeSada.SelectSingleNode("id").InnerText.Trim();
var nodePre = pre.DocumentElement.SelectSingleNode("artikal[id='" + idSada + "']");
if (nodePre != null)
{
string pre_Value = nodePre.InnerXml.Replace("\t", ""); ;
string posle_Value = nodeSada.InnerXml.Replace("\t", ""); ;
if (pre_Value != posle_Value)
{
XmlNode importNode = doc.ImportNode(nodeSada, true);
element1.AppendChild(importNode);
}
}
else
{
XmlNode importNode = doc.ImportNode(nodeSada, true);
element1.AppendChild(importNode);
}
}
doc.Save("razlika.xml");
}
finally
{
sw.Stop();
SetControlEnabled(btStart, true);
}
}
This way I've managed to improve #10000 records => 140 rec/sec and #14000 => 104 rec/sec

Issue with reading multiple xml nodes instead of one

The XML bills usually have one Node that is returned and parsed. We have come across an issue where an XML bill had multiple Nodes. Since the code is not set up to handle that, the customer ended up with an incorrect bill.
This is the code I have that goes through the bill list. If it comes back with a node then it parses the information from the xml.
var response = new List<CustomerBill>();
try
{
foreach (GetBillForCAResponse eBillResponse in eBillResponseList)
{
var statementDetailsResponse = GetStatementDetails(
new GetStatementDetailsRequest
{
BatchId = eBillResponse.BatchId,
CustomerAccountId = eBillResponse.CA.ToString("000000000"),
StatementId = eBillResponse.CAS_NUM.ToString("0000")
});
string xmlBill = statementDetailsResponse.StatementAsXML.ToString();
var document = new XmlDocument();
document.LoadXml(xmlBill);
var saDetailedPageNode = XmlBillParser.GetDetailPageSectionBySa(requestSa, xmlBill);
if (saDetailedPageNode == null) continue;
var customerBill = new CustomerBill();
customerBill.IsSurepay = XmlBillParser.GetSurepayFlagFromBill(document);
customerBill.ServiceAddress = XmlBillParser.GetServiceAddress(requestSa, document);
customerBill.monthName = XmlBillParser.GetnillStatementDate(requestSa, xmlBill);
customerBill.EqCurlPlanBal = XmlBillParser.getEqualizerCurrentPlanBalance(document);
customerBill.EqPymntDue = XmlBillParser.getEqualizerPaymentDue(document);
customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSa, xmlBill, saDetailedPageNode);
response.Add(customerBill);
}
}
catch (Exception ex)
{
trace.Write(new InvalidOperationException(requestSa, ex));
}
return response;
}
Here is the method that checks if there is a node in the XML. I have changed the code so that is returns all the nodes. I had to change the type xmlNode to xmlNodeList because now its returning a collection of nodes. ****This is whats causing all the problems in my code in other places.***
public static xmlNode GetDetailPageSectionBySa(string sa, string statementXml)
{
XmlDocument document = new XmlDocument();
document.LoadXml(statementXml);
string requestSa = sa.PadLeft(9, '0');
string xpath = String.Format("//Para[IRBILGP_SA_SAA_ID_PRINT.SERVICE.ACCOUNT.STATMENT='{0}S{1}']/..", requestSa.Substring(0, 4), requestSa.Substring(4));
return document.SelectNodes(xpath);
//var nodes = document.SelectNodes(xpath);
// if(nodes.Count > 0) return nodes[nodes.Count - 1];
//if(!SaExistInBill(requestSa, statementXml)) return null;
//var node = GetDetailPageSectionByBillPrisminfoIndex(sa, statementXml);
//if (node != null) return node;
//return null;
}
So returning back to where it is called.. im getting an invalid arguement here
customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSA, xmlBill, saDetailedPageNode); because the parameter saDetailedPageNode is xmlNodeList now when it is expecting of type xmlNode. if i go to the method private static ServiceAddressBillDetail GetServiceAccountUsageAndBillingDetail(string requestSA, string xmlBill, XmlNode detailPageNode) which i added at the end of this code so you could see. If I change the parameter XmlNode detailPageNode to XmlNodeList detailPageNode which I have to do to fix the invalid arguement above, I get that detailPageNode.SelectNodes becomes invalid because xmlNodeList does not have SelectNodes as an extension method. I use this extention method a lot through this method. So I am getting a lot of errors.
var saDetailedPageNode = XmlBillParser.GetDetailPageSectionBySa(requestSa, xmlBill);
if (saDetailedPageNode == null) continue;
var customerBill = new CustomerBill();
customerBill.IsSurepay = XmlBillParser.GetSurepayFlagFromBill(document);
customerBill.ServiceAddress = XmlBillParser.GetServiceAddress(requestSa, document);
customerBill.monthName = XmlBillParser.GetnillStatementDate(requestSa, xmlBill);
customerBill.EqCurlPlanBal = XmlBillParser.getEqualizerCurrentPlanBalance(document);
customerBill.EqPymntDue = XmlBillParser.getEqualizerPaymentDue(document);
customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSa, xmlBill, saDetailedPageNode);
response.Add(customerBill);
}
}
catch (Exception ex)
{
trace.Write(new InvalidOperationException(requestSa, ex));
}
return response;
}
private static ServiceAddressBillDetail GetServiceAccountUsageAndBillingDetail(string requestSA, string xmlBill, XmlNode detailPageNode)
{
var saBillDetail = new ServiceAddressBillDetail();
saBillDetail.UsageServiceName = requestSA;
var meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_b");
if (meterReadEndXMLNodes.Count == 0)
{
meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_a");
}
if (meterReadEndXMLNodes.Count == 0)
{
meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_b");
}
if (meterReadEndXMLNodes.Count == 0)
{
meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_a");
}
var demandXMLNodes = detailPageNode.SelectNodes("Usage_kW_Total_Bold");
How can i fix my invalid arguments so that I can use xmlNodeList instead of xmlNode? is there a way to convert or cast? or is there another xml object I can use?
Since I am now returning multiple nodes. I know that I will need to loop through the customerBill portion. How can I do that without creating a new bill for every node? All the nodes in one xml need to be included in one bill.
From the code you've provided, the only part that needs to account for your refactor to XmlNodeList is GetServiceAccountUsageAndBillingDetail(), so you have two options:
Update GetServiceAccountUsageAndBillingDetail() to take in an XmlNodeList parameter instead and aggregate values inside that method to come up with your final ServiceAddressBillDetail object.
Loop through your XmlNode objects in the XmlNodeList and reconcile the different ServiceAddressBillDetail objects yourself.
Without details on what ServiceAddressBillDetail, I can only guess as to which is better, but I'd suggest using the first option.
private static ServiceAddressBillDetail GetServiceAccountUsageAndBillingDetail(
string requestSA,
string xmlBill,
XmlNodeList detailPageNodes)
{
var saBillDetail = new ServiceAddressBillDetail();
saBillDetail.UsageServiceName = requestSA;
foreach(XmlNode detailPageNode in detailPageNodes)
{
var meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_b");
if (meterReadEndXMLNodes.Count == 0)
{
meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_a");
}
if (meterReadEndXMLNodes.Count == 0)
{
meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_b");
}
if (meterReadEndXMLNodes.Count == 0)
{
meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_a");
}
var demandXMLNodes = detailPageNode.SelectNodes("Usage_kW_Total_Bold");
//Whatever comes next
}
}
Assuming ServiceAddressBillDetail has properties for "usage" you could simply add the appropriate values from each detailPageNode to the saBillDetail object.
It's hard to see what is going on but this may be the problem;
string xpath = String.Format("//Para..
The "//" will search in the entire document, but you probably want to search for descendent elements.
Here's some code to deal with a similar problem;
XmlNodeList staffNodes = resultXML.SelectNodes("//staff");
List<TempStaff> tempStaffs = staffNodes
.Cast<XmlNode>()
.Select(
i =>
new TempStaff()
{
StaffId = i.SelectSingleNode("id").InnerText,
Forename = i.SelectSingleNode("forename").InnerText,
Surname = i.SelectSingleNode("surname").InnerText,
}
).ToList();
My XML looks like
<staff><forename>asdf</forename><surname>ddsf</surname><id>123</id>... </staff>
<staff><forename>asdfas</forename><surname>asffdf</surname><id>456</id>...</staff>

How can I avoid NullReferenceExceptions when nodes don't exist in my XML files?

I have the following code:
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.Load(#"C:\MR.xml");
XmlNodeList stations = xml.SelectNodes("//FileDump/Message/Attachment");
var Message_ID = xml.SelectSingleNode("//FileDump/Message/MsgID").InnerXml;
Console.WriteLine("Message ID is :{0}", Message_ID);
foreach (XmlNode station in stations)
{
var File_Name = station.SelectSingleNode("FileName").InnerXml;
var File_ID = station.SelectSingleNode("FileID").InnerXml;
}
}
FileID and FileName do not always exist in some files. How can I avoid NullReferenceExceptions in this case?
I would try to something like this if that check has to happen in lot of places and to keep the code simple and clear
public static class Helpers
{
public static string GetInnerXml(this XmlNode node, string innerNodeName)
{
string innerXml = "";
XmlNode innerNode = node.SelectSingleNode(innerNodeName);
if (innerNode != null)
{
innerXml = innerNode.InnerXml;
}
return innerXml;
}
}
and use it like this
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.Load(#"C:\MR.xml");
XmlNodeList stations = xml.SelectNodes("//FileDump/Message/Attachment");
var Message_ID = xml.GetInnerXml("//FileDump/Message/MsgID");
Console.WriteLine("Message ID is :{0}", Message_ID);
foreach (XmlNode station in stations)
{
var File_Name = station.GetInnerXml("FileName");
var File_ID = station.GetInnerXml("FileID");
}
}
You could do something like:
string FileName= "";
string File_ID = "";
if (station.SelectSingleNode("FileName") != null)
File_Name = station.SelectSingleNode("FileName").InnerXml;
if (station.SelectSingleNode("FileID") != null)
File_ID = station.SelectSingleNode("FileID").InnerXml;
And continue processing if the vars are not the empty string ... ("") ...
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.Load(#"C:\MR.xml");
XmlNodeList stations = xml.SelectNodes("//FileDump/Message/Attachment");
var Message_ID = xml.SelectSingleNode("//FileDump/Message/MsgID").InnerXml;
Console.WriteLine("Message ID is :{0}", Message_ID);
foreach (XmlNode station in stations)
{
var fileNameNode = station.SelectSingleNode("FileName");
var fileIdNode = station.SelectSingleNode("FileID");
var File_Name = fileNameNode == null ? (string)null : fileNameNode.InnerXml;
var File_ID = fileIdNode == null ? (string)null : fileIdNode.InnerXml;;
}
}
I usually use extension methods for handling unexpected nulls.
public static string GetValueIfNotNull(this XmlAttribute xmlAttribute)
{
if (xmlAttribute == null)
{
return null;
}
return xmlAttribute.Value;
}
Then I can do myElement.Attribute("someAttribute").GetValueIfNotNull();

Finding inner text value from XML file

When I write this code, I get only the parent tag value. I want to get their childnodes value also, please tell me about this.
XmlDocument DOC = new XmlDocument();
DOC.RemoveAll();
DOC.Load("C:\\Users\\DIGITEL EYE SYSTEM\\Desktop\\response.xml");
foreach (XmlNode AllNodes in ParentNode)
{
Project.Name = AllNodes["Name"].InnerText;
if (AllNodes.ChildNodes == DOC.GetElementsByTagName("AppBuilderForms"))
{
// Project.Forms = DOC.GetElementsByTagName("");
// String sb = AllNodes["Forms"].InnerText;
}
else if (AllNodes.ChildNodes==DOC.GetElementsByTagName("CheckMarkObject"))
{
checkmark.Name = AllNodes["Name"].InnerText;
checkmark.Label = AllNodes["Label"].InnerText;
// checkmark.IsChecked = AllNodes["IsChecked"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("DateTimeObject"))
{
DateTime.Name = AllNodes["Name"].InnerText;
DateTime.Label = AllNodes["Label"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("LocationObject"))
{
Location.Name = AllNodes["Name"].InnerText;
Location.Label = AllNodes["Label"].InnerText;
Location.Longitude = AllNodes["Longitude"].InnerText;
Location.Latitude = AllNodes["Latitude"].InnerText;
}
else if (ParentNode==DOC.GetElementsByTagName("SwitchObject"))
{
Switch.Name = AllNodes["Name"].InnerText;
Switch.Label = AllNodes["Label"].InnerText;
// Switch.IsChecked =AllNodes["IsChecked"].InnerText;
}
else if(ParentNode==DOC.GetElementsByTagName("TextViewObject"))
{
TextView.Name = AllNodes["Name"].InnerText;
TextView.Value = AllNodes["Value"].InnerText;
}
else if (ParentNode ==DOC.GetElementsByTagName("TextFieldObject"))
{
TextField.Name = AllNodes["Name"].InnerText;
TextField.Value = AllNodes["Value"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("PhotoPickerObject"))
{
PhotoPicker.Name = AllNodes["Name"].InnerText;
PhotoPicker.Label = AllNodes["Label"].InnerText;
}
else if (ParentNode == DOC.GetElementsByTagName("SpinWheelPickerObject"))
{
SpinWheelPicker.Name = AllNodes["Name"].InnerText;
SpinWheelPicker.Label = AllNodes["Label"].InnerText;
// SpinWheelPicker.Columns = AllNodes["Columns"].InnerText;
}
}
var xdoc = XDocument.Load(#"C:\Users\DIGITEL EYE SYSTEM\Desktop\response.xml");
var allElements = xdoc.Root.Elements();
foreach (string element in allElements)
{
//TODO add logic
}
First we'll load up the xml into a XDocument (needs .Net 3.5),
nothing odd going on here.
Second we'll select the root node and ALL
the elements under the root into a IEnumrable. You can add a filter here in the Elements() method.
Third we'll start iterating over the elements in our IEnumerable and implicitly
cast them to a string, this is a operator in the LINQ to XML lib
that just returns the XElement.Value (so if you think that's more
readable or need the whole Element for some other reason write
that! I.E XElement element in allElements)
Don't know how to do it in XmlDocument, I've totally forgotten, hopefully this might help you in case you'll go down that path (pun intended).

What's wrong in my dynamical ToolStripMenu script?

Why duplicate code?
I read on a rampage in the xml data! and installing a toolstripmenu! but for some reason every so often put into the xml amennyi item is in! Why?
here is the code:
try
{
XmlDocument xml = new XmlDocument();
xml.Load("allomasok.xml");
XmlNodeList xnList = xml.SelectNodes("/radiok/allomas");
mennyi =int.Parse(xnList.Count.ToString());
foreach (XmlNode xn in xnList)
{
string radioNEV = xn["neve"].InnerText;
string radioURL = xn["url"].InnerText;
//int i = mennyi;
ToolStripMenuItem[] items = new ToolStripMenuItem[mennyi];
for (int i = 0; i < items.Length; i++)
{
items[i] = new ToolStripMenuItem();
items[i].Name = "mentett" + i.ToString();
items[i].Tag = radioURL;
items[i].Text = radioNEV;
items[i].Click += new EventHandler(MenuItemClickHandler);
}
sajátokToolStripMenuItem.DropDownItems.AddRange(items);
}
}
catch
{
MessageBox.Show("Hiba", "NetRadioPlayer");
}
finally
{
MessageBox.Show("Ennyi mentett állomás van: " + mennyi);
}
Thanks.
You have too many loops, I think. Try this:
try
{
XmlDocument xml = new XmlDocument();
xml.Load("allomasok.xml");
XmlNodeList xnList = xml.SelectNodes("/radiok/allomas");
ToolStripMenuItem mi;
int i;
foreach (XmlNode xn in xnList)
{
string radioNEV = xn["neve"].InnerText;
string radioURL = xn["url"].InnerText;
mi = new ToolStripMenuItem();
mi.Name = "mentett" + i++.ToString();
mi.Tag = radioURL;
mi.Text = radioNEV;
mi.Click += new EventHandler(MenuItemClickHandler);
sajátokToolStripMenuItem.DropDownItems.Add(mi);
}
}
catch
{
MessageBox.Show("Hiba", "NetRadioPlayer");
}
finally
{
MessageBox.Show("Ennyi mentett állomás van: " + mennyi);
}
If that doesn't help I'm sorry, I don't understand the question.

Categories

Resources