I am trying to update an existing XML file by adding a new child node using c#.
Everything is OK if I save it by new name but I want to update the same file and while doing it, got the following exception:
System.IO.IOException:Process cannot access the file... because it is
being used by another process
Here is my code: (I am trying to add a new default node)
XmlDocument doc = new XmlDocument();
string path = #"C:\Debug\default.xml";
doc.Load(path);
XmlNode NName = doc.CreateElement("default");
XmlNode SNO = doc.CreateElement("SNo");
SNO.InnerText = "2";
NName.AppendChild(SNO);
doc.DocumentElement.AppendChild(NName);
doc.Save(path);
Also XML file:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<default>
<SNo>1</SNo>
</default>
</NewDataSet>
If you are sure the file is only being used by your process, then simply read it into a byte array, close the file, then save it again:
(I am using .net 4.0 for this sample):
XmlDocument doc = new XmlDocument();
byte[] content = File.ReadAllBytes(path);
using (var memStream = new MemoryStream(content))
{
doc.Load(memStream);
}
XmlNode NName = doc.CreateElement("default");
XmlNode SNO = doc.CreateElement("SNo");
SNO.InnerText = "2";
NName.AppendChild(SNO);
doc.DocumentElement.AppendChild(NName);
doc.Save(path);
Related
I'm trying to load xml file using Xelement.Load() method and in case of some files, I get "ditaarch" is an undeclared prefix exception. The content of such troublesome xml's are similar to this simplified version:
<?xml version="1.0" encoding="UTF-8"?>
<concept ditaarch:DITAArchVersion="1.3">
<title>Test Title</title>
<menucascade>
<uicontrol>text</uicontrol>
<uicontrol/>
</menucascade>
</concept>
I've tried to follow suggestions to manually add or ignore "ditaarch" namespace using xml namespace manager:
using (XmlReader reader = XmlReader.Create(#"C:\test\example.xml"))
{
NameTable nameTable = new NameTable();
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(nameTable);
nameSpaceManager.AddNamespace("ditaarch", "");
XmlParserContext parserContext = new XmlParserContext(null, nameSpaceManager, null, XmlSpace.None);
XElement elem = XElement.Load(reader);
}
But it leads to same exception as before. Most probably the solution is trivial but I just can't see it :(
If anyone would be able to point me in the right direction, I would be most grateful.
The presented markup is not namespace well-formed XML so I don't think XElement or XDocument is an option as it doesn't support colons in names. You can parse it with a legacy new XmlTextReader("foo.xml") { Namespaces = false } however.
And you could use XmlDocument instead of XDocument or XElement and check for any empty elements with e.g.
XmlDocument doc = new XmlDocument();
using (XmlReader xr = new XmlTextReader("example.xml") { Namespaces = false })
{
doc.Load(xr);
}
Console.WriteLine("Number of empty elements: {0}", doc.SelectNodes("//*[not(*)][not(normalize-space())]").Count);
I am using the follwing syntax to add data to already existing xml file in the following way:
XmlTextReader Reader = new XmlTextReader("ServerPaths.xml");
DataSet dsNewList = new DataSet();
dsNewList.ReadXml(Reader);
Reader.Close();
DataTable dt = dsNewList.Tables[0];
dt.Rows.Add(txtNewServerPath.Text);
dt.WriteXml("ServerPaths.xml",false);
But, i was getting error at last line as:
System.IO.IOException was unhandled
Message=The process cannot access the file 'C:\Documents and Settings\590000\my documents\visual studio 2010\Projects\EasyDeployer\EasyDeployer\bin\Debug\ServerPaths.xml' because it is being used by another process
Please help in solving this error. or is there any other way to do this?
My xml file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<ServerList>
<ServerPath>C:\\Avinash\\Dev1</ServerPath>
<ServerPath>C:\\Avinash\\Dev1</ServerPath>
</ServerList>
I just wanted to add new serverpath..
You could also try adding XmlNode's to the xml document like this:
XmlDocument xd = new XmlDocument();
xd.Load("ServerPaths.xml");
XmlNode rootNode = xd.DocumentElement;
XmlNode serverPathNode = xd.CreateElement("ServerPath");
serverPathNode.InnerText = txtNewServerPath.Text; // Your value
rootNode.AppendChild(serverPathNode);
xd.Save("ServerPaths.xml");
In C# am trying to check to see if an XML file is created, if not create the file and then create the xml declaration, a comment and a parent node.
When I try to load it, it gives me this error:
"The process cannot access the file 'C:\FileMoveResults\Applications.xml' because it is being used by another process."
I checked the task manager to ensure it wasn't open and sure enough there were no open applications of it. Any ideas of what's going on?
Here is the code I am using:
//check for the xml file
if (!File.Exists(GlobalVars.strXMLPath))
{
//create the xml file
File.Create(GlobalVars.strXMLPath);
//create the structure
XmlDocument doc = new XmlDocument();
doc.Load(GlobalVars.strXMLPath);
//create the xml declaration
XmlDeclaration xdec = doc.CreateXmlDeclaration("1.0", null, null);
//create the comment
XmlComment xcom = doc.CreateComment("This file contains all the apps, versions, source and destination paths.");
//create the application parent node
XmlNode newApp = doc.CreateElement("applications");
//save
doc.Save(GlobalVars.strXMLPath);
Here is the code I ended up using to fix this issue:
//check for the xml file
if (!File.Exists(GlobalVars.strXMLPath))
{
using (XmlWriter xWriter = XmlWriter.Create(GlobalVars.strXMLPath))
{
xWriter.WriteStartDocument();
xWriter.WriteComment("This file contains all the apps, versions, source and destination paths.");
xWriter.WriteStartElement("application");
xWriter.WriteFullEndElement();
xWriter.WriteEndDocument();
}
File.Create() returns a FileStream that locks the file until it's closed.
You don't need to call File.Create() at all; doc.Save() will create or overwrite the file.
I would suggest something like this:
string filePath = "C:/myFilePath";
XmlDocument doc = new XmlDocument();
if (System.IO.File.Exists(filePath))
{
doc.Load(filePath);
}
else
{
using (XmlWriter xWriter = XmlWriter.Create(filePath))
{
xWriter.WriteStartDocument();
xWriter.WriteStartElement("Element Name");
xWriter.WriteEndElement();
xWriter.WriteEndDocument();
}
//OR
XmlDeclaration xdec = doc.CreateXmlDeclaration("1.0", null, null);
XmlComment xcom = doc.CreateComment("This file contains all the apps, versions, source and destination paths.");
XmlNode newApp = doc.CreateElement("applications");
XmlNode newApp = doc.CreateElement("applications1");
XmlNode newApp = doc.CreateElement("applications2");
doc.Save(filePath); //save a copy
}
The reason your code is currently having problems is because of: File.Create creates the file and opens the stream to the file, and then you never make use of it (never close it) on this line:
//create the xml file
File.Create(GlobalVars.strXMLPath);
if you did something like
//create the xml file
using(Stream fStream = File.Create(GlobalVars.strXMLPath)) { }
Then you would not get that in use exception.
As a side note XmlDocument.Load will not create a file, only work with an already create one
You could create a stream, setting the FileMode to FileMode.Create and then use the stream to save the Xml to the path specified.
using (System.IO.Stream stream = new System.IO.FileStream(GlobalVars.strXMLPath, FileMode.Create))
{
XmlDocument doc = new XmlDocument();
...
doc.Save(stream);
}
I have a simple c# function that creates a basic XML file and saves:
private void CreateXMlFile(string Filename, string Name, string Company)
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode licenseNode = doc.CreateElement("license");
doc.AppendChild(licenseNode);
XmlNode node = doc.CreateElement("Name");
node.AppendChild(doc.CreateTextNode(Name));
licenseNode.AppendChild(node);
node = doc.CreateElement("Company");
node.AppendChild(doc.CreateTextNode(Company));
licenseNode.AppendChild(node);
doc.Save(Filename);
}
When I try to edit or delete the file I always get following error:
The process cannot access the file because it is being used by another
process.
XmlDocument doesnt have any inbuilt dispose or close routines and wondered how I can force the file to close before later editing or deleting it.
I have tried to save the file using StreamWriter:
StreamWriter outStream = System.IO.File.CreateText(outfile);
outStream.Write(data);
outStream.Close();
But this didnt make a difference with the same error.
Your advice is greatly accepted.
Thank you
Send Stream to XmlDocument's Save method instead of file name.
private static void Main(string[] args)
{
CreateXMlFile("c:\\test.xml", "testName", "testCompany");
}
private static void CreateXMlFile(string Filename, string Name, string Company)
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode licenseNode = doc.CreateElement("license");
doc.AppendChild(licenseNode);
XmlNode node = doc.CreateElement("Name");
node.AppendChild(doc.CreateTextNode(Name));
licenseNode.AppendChild(node);
node = doc.CreateElement("Company");
node.AppendChild(doc.CreateTextNode(Company));
licenseNode.AppendChild(node);
StreamWriter outStream = System.IO.File.CreateText(Filename);
doc.Save(outStream);
outStream.Close();
}
I tried executing above code and it is working fine at my end.
Your code is fine. I tested it on my machine and there is no lock left after Save().
Try to use Unlocker (http://www.softpedia.com/get/System/System-Miscellaneous/Unlocker.shtml) to check whether you are really the one who holds the lock.
Which .NET framework do you use? Theres also a report (http://bytes.com/topic/net/answers/467028-xmldocument-save-does-not-close-file-properly) which was not reproducable too.
I wanted to find out if there is a way of getting a parameter or variable value out of an XSL file. For example, if I have the following:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="username" select ="usertest"/>
<xsl:variable name="password" select ="pass"/>
<!-- ... -->
</xsl:stylesheet>
I would like to read the username and password values from the XSL and use them for authentication. I am using ASP.Net and C# to perform the actual transform on an XML file.
Could someone please share code with me that would allow me to read the XSL variables from ASP.NET/C#. Thanks in advance for the help.
This is easy. XSL files are XML themselves, so you can treat them as such.
XmlDocument xslDoc = new XmlDocument();
xslDoc.Load("myfile.xsl");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xslDoc.NameTable);
nsMgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
XmlNode usrNode = xslDoc.SelectSingleNode("/xsl:stylesheet/xsl:variable[#name='username']", nsMgr);
XmlNode pwdNode = xslDoc.SelectSingleNode("/xsl:stylesheet/xsl:variable[#name='password']", nsMgr);
string usr = usrNode.Attributes["select"].Value;
string pwd = pwdNode.Attributes["select"].Value;
Your question is (edit: was) missing the actual code, but from the description it appears what you are looking for is XPath. XSL will transform one XML document into another XML document, you can then use XPath to query the resulting XML to get out the values that you want.
This Microsoft KB article has information about how to use XPath from C#:
http://support.microsoft.com/kb/308333
Thanks Everone. Here is what finally worked:
Client (asp with vbscript) Used for Testing Purposes:
<%
//Create Object
Set xmlhttp = CreateObject("Microsoft.XMLHTTP")
//Set up the object with the URL
'xmlhttp.open "POST" ,"http://localhost/ASP_Test/receiveXML.asp",False
//Create DOM Object
Set xmldom = CreateObject("Microsoft.XMLDOM")
xmldom.async = false
//Load xls to send over for transform
xmldom.load(Server.MapPath("/ASP_Test/masterdata/test.xsl"))
//Send transform file as DOM object
xmlhttp.send xmldom
%>
//////////////////////////////////////////////////////////////////////////
On the Server Side: (aspx with C#) Accepts xslt and process the transform:
//file path for data xml
String xmlFile = ("\\masterdata\\test.xml");
//file path for transformed xml
String xmlFile2 = ("\\masterdata\\out.xml");
XmlTextReader reader = new XmlTextReader(Request.InputStream);
Transform(xmlFile, reader, xmlFile2);
public static string Transform(string sXmlPath, XmlTextReader xslFileReader, string outFile)
{
try
{
//load the Xml doc
XPathDocument myXPathDoc = new XPathDocument(sXmlPath);
XslCompiledTransform myXslTrans = new XslCompiledTransform();
//load the Xsl
myXslTrans.Load(xslFileReader);
//create the output stream
XmlTextWriter myWriter = new XmlTextWriter
(outFile, null);
//do the actual transform of Xml
myXslTrans.Transform(myXPathDoc, null, myWriter);
myWriter.Close();
return "Done";
}
catch (Exception e)
{
return e.Message;
}
}