How to parse and update xml file using xmltextreader or xmlreader - asp.net

Hi i have the following code to read the xml file and change the value of particular node ,but i want to do the same using xmltextreader or xmlreader, i am trying to avoid the statement doc.Save(System.Web.HttpContext.Current.Server.MapPath("Data/Example.xml")); , which has a direct reference to my physical file.
XmlDocument doc = new XmlDocument();
string xmlFile = System.Web.HttpContext.Current.Server.MapPath("Data/Example.xml");
doc.Load(xmlFile);
XmlNodeList xmlnode = doc.GetElementsByTagName("value");
xmlnode[0].ChildNodes[0].Value = 23;
doc.Save(System.Web.HttpContext.Current.Server.MapPath("Data/Example.xml"));

Well something's going to have to have a reference to the file. However, you could easily change your code to simply accept a Stream (which would have to be readable, writable and seekable):
private static void ChangeDocument(Stream stream)
{
XmlDocument doc = new XmlDocument();
doc.Load(stream);
XmlNodeList xmlnode = doc.GetElementsByTagName("value");
xmlnode[0].ChildNodes[0].Value = 23;
stream.Position = 0;
doc.Save(stream);
stream.SetLength(stream.Position); // Truncate the file if it was longer
}
It's somewhat ugly, admittedly...
Of course you could always pass in the filename itself - your MapPath call would still be in a higher level method, which may be all you're trying to achieve:
private static void ChangeDocument(string filename)
{
XmlDocument doc = new XmlDocument();
doc.Load(filename);
XmlNodeList xmlnode = doc.GetElementsByTagName("value");
xmlnode[0].ChildNodes[0].Value = 23;
doc.Save(filename);
}
One final aside - if you're using .NET 3.5 or higher, I'd strongly recommend using LINQ to XML as a rather nicer XML API.

You can not write or update XML data using XmlTextReader or XmlReader ansectors, use XmlTextWriter or XmlWriter ancestors, ot XmlSerializer.Serialize(..) method as alternative.
You can not avoid the statement and alike,
doc.Save(System.Web.HttpContext.Current.Server.MapPath("Data/Example.xml"));
which has a direct reference to your physical file, because you have to write the changed nodes back to the origin file again, otherwize you have to switch your system from using file-based approach (ASP.NET web site using file-based data storage) to database-driven approach (ASP.NET web site using the database server).
As alternative, use your own XML data in your SQL server, then load and update it using EF of ORM.

Related

Reading posted JSON data in ASP.NET

I subscribe to a mass email service which, when an error occurs at their end, posts to a page on my website as an endpoint to notify me that an email has bounced.
They describe it as follows:
The event data is sent in the POST request body using a JSON object.
What I need to know is how can I capture the info posted to me?
Currently I'm pointing them to a generic handler, a .ashx page, this can be changed to whatever as long as it's in .NET.
In 10 years working with first classic ASP and now .NET I've never done this before and I must admit I don't even know where to start.
This is the code I used to achieve a similar thing - not sure where I got it originally.
C#
var strJSON = String.Empty;
context.Request.InputStream.Position = 0;
using (var inputStream = new StreamReader(context.Request.InputStream))
{
strJSON = inputStream.ReadToEnd();
}
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
object serJsonDetails = javaScriptSerializer.Deserialize(strJSON, typeof(object));
// go and process the serJsonDetails object
or VB
Dim strJSON = [String].Empty
context.Request.InputStream.Position = 0
Using inputStream = New StreamReader(context.Request.InputStream)
strJSON = inputStream.ReadToEnd()
End Using
Dim javaScriptSerializer As New JavaScriptSerializer()
Dim serJsonDetails As Object = javaScriptSerializer.Deserialize(strJSON, GetType(Object))
' go and process the serJsonDetails object
You could just read the Request stream (Request.GetRequestStream) and use Json.NET to deserialize to an object.
You could use MVC4 and the built in object mapping.
There's many options. Perhaps you should read up on them more so that you have an idea of their capabilities and drawbacks.
Probably Request.Form (here) will help you get the JSON, if you know the content of the post, and then you need something like json.net library to get the object, or you can simply search the string using regex or keywords
Or if you can direct the post to a web service(asmx) instead of a web page, those services will parse the json for you
If you need to read raw post data twice or many times, i advice you to use this code.
string postBodyJson = null;
MemoryStream ms = new MemoryStream();
Request.InputStream.Position = 0;
Request.InputStream.Seek(0, SeekOrigin.Begin);
Request.InputStream.CopyTo(ms);
ms.Position = 0;
ms.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(ms))
{
postBodyJson = reader.ReadToEnd();
}

How to call a node from a xml file within asp.net web page

I am trying to use the value of <Directory> in my following piece of code:
Public Function GetFile() As String
Dim di As New DirectoryInfo(< Directory >)
Dim files As FileSystemInfo() = di.GetFileSystemInfos()
Dim newestFile = files.OrderByDescending(Function(f) f.CreationTime).First
Return newestFile.FullName
End Function
Is there any way i can call the value stored in the xml file in my code?
Andy's answer is good, but in VB it's even easier.
Dim xmlDoc As XDocument
Dim dir as String
xmlDoc = XDocument.Load("XMLFile1.xml")
dir = xmlDoc.<ServerList>.<Server>.<Directory>.First().Value;
Or even easier if the XML file will never have more than one <Directory> element that you care about:
dir = xmlDoc...<Directory>.First().Value;
To answer your comment on Andy's answer:
dir = (From server as XElement in xmlDoc...<Server>
Where server.<ServerName>.First().Value = requiredServer
Select server.<Directory>.First().Value)(0);
As you are clearly familiar with Linq, you can operate on the Xml using System.Xml.Linq.
Apologies, this is in c#.
var xDoc = XDocument.Load("XMLFile1.xml");
var dir = xDoc.Element("ServerList").Elements("Server").Elements("Directory").First().Value;
If you have the Xml stored in a string replace XDocument.Load with XDocument.Parse.
Obviously you'll have to defend against parse errors, file missing and schema inconsistencies in your production code.
You can use this http://support.microsoft.com/kb/301225

Programmatic update of InfoPath form XML is stripping off tags

I have a C# program that is looping through all of the forms (browser enabled) in my forms library and injecting an XML node into each of them (for a newly promoted field). For some reason, when the XML is saved back to the form, the first few tags are being stripped off. Specifically, these tags are:
<?xml version="1.0"?>
<?mso-infoPathSolution name="urn:schemas-microsoft-com:office:infopath:Contractor-DB-Form:-myXSD-2009-09-10T18-19-55" solutionVersion="1.0.1.1100" productVersion="12.0.0.0" PIVersion="1.0.0.0" href="http://echouat.rbs.us/npe/FormServerTemplates/Contractor_DB_Form.xsn"?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<?mso-infoPath-file-attachment-present?>"
My code to update the XML is as follows:
private static SPListItem InsertXmlNode(SPListItem infoPathForm, string nodeToUpdateStr, string nodeToInsertStr,
string nodeInnerXmlStr, string firstNode)
{
//load form into xml document
byte[] fileBytes = infoPathForm.File.OpenBinary();
MemoryStream itemStream = new MemoryStream(fileBytes);
//Stream itemStream = infoPathForm.File.OpenBinary();
XmlDocument xmlDoc = new XmlDocument();
XmlNamespaceManager xmlNameSpaceMgr = new XmlNamespaceManager(xmlDoc.NameTable);
xmlNameSpaceMgr.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-09-10T18:19:55");
xmlDoc.Load(itemStream);
itemStream.Close();
//inject xml
XmlNode nodeToUpdate = xmlDoc.SelectSingleNode(firstNode + nodeToUpdateStr, xmlNameSpaceMgr);
//only insert if doesn't already exist
if (xmlDoc.SelectSingleNode(firstNode + nodeToUpdateStr + "/" + nodeToInsertStr, xmlNameSpaceMgr) == null)
{
updateCounter++;
XmlNode nodeToInsert = xmlDoc.CreateNode(XmlNodeType.Element, nodeToInsertStr, "http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-09-10T18:19:55");
nodeToInsert.InnerText = nodeInnerXmlStr;
nodeToUpdate.AppendChild(nodeToInsert);
//get binary data for updated xml
byte[] newXmlData = Encoding.UTF8.GetBytes(xmlDoc.DocumentElement.OuterXml);
MemoryStream newMemStream = new MemoryStream(newXmlData);
//write updated binary data to the form
infoPathForm.File.SaveBinary(newMemStream);
newMemStream.Close();
infoPathForm.File.Update();
}
return infoPathForm;
}
The addition of the new node is working properly; I can see that the new XML is properly formed. It's just that the tags get stripped off once the file is loaded from the MemoryStream into the XmlDocument object. And once these tags are missing, the forms won't open anymore in IP.
PLEASE HELP!
Thank you!
Change the line which reads:
byte[] newXmlData = Encoding.UTF8.GetBytes(xmlDoc.DocumentElement.OuterXml);
to read:
byte[] newXmlData = Encoding.UTF8.GetBytes(xmlDoc.OuterXml);

XPath with string or XmlDocument

I'm having trouble parsing the xml returned from a web service because it's really just a string. The web service doesn't contain any method to submit the request, nor an object to handle the response, so I'm just getting the xml as a string and trying to parse it to properties in an object I've created.
I was messing around with XPath, but I'm unable to figure out how to use a string, or an XmlDocument object with Xpath. I don't have an actual xml file, just a string that I've used to create an XmlDocument object.
private void SetProperties(string _xml)
{
XmlDocument _doc = new XmlDocument();
_doc.LoadXml(_xml);
}
Any ideas as to how I can query that XmlDocument object with XPath?
SelectNodes or SelectSingleNode is a good place to start. There are examples on those pages of selecting/querying node lists from an XmlDocument.
Have you tried calling the various methods on the XmlDocument object? For example, the SelectSingleNode method takes an xpath string and returns an xmlNode.
Also, check this site for additional information: http://www.w3schools.com/
You can create a new XPathExpression object which you then do a select against the XDoc with it. Adding onto the XDocument load code you started with:
XmlDocument _doc = new XmlDocument();
_doc.LoadXml(_xml);
XPathNavigator navigator = _doc.CreateNavigator();
XPathExpression expression = navigator.Compile("/foo/bar");
XPathNodeIterator iterator = navigator.Select(expression);
while (iterator.HasNext()) {
//Do Something With iterator.Current.Value;
}

.NET StreamReader Won't Close

I'm using a RTF file as a template for an ASP.NET web application. My VB.NET code reads the file using a StreamReader, replaces some strings, and creates a new Word document with data from the database. My code closes and disposes of the StreamReader. However, when I attempt to upload a revised RTF file to the web server I get an error, "Cannot open the file for writing". So obviously the file remains open long after the ASP.NET page has run.
How can I force the StreamReader to close? Even editing the web.config file to force the web application to restart isn't enough to kill the lock on this file.
consider using the "using" idiom, also available in VB.net
using(StreamReader reader = new StreamReader(...)) {
}
the stream will get closed, even if exception is thrown
Consider closing all IDisposable implementations like this
It seems odd if it's hanging on even after a close/dispose. Are you using a FileStream along with the StreamReader? Generally, I use a FileStream to control access to the file and feed that to the StreamReader, a la:
FileStream fsIn = new FileStream("path",FileMode.Open, FileAccess.Read, FileShare.None);
StreamReader srIn = new StreamReader(fsIn, System.Text.Encoding.Default);
//...do stuff....
srIn.close();
srIn.Dispose();
fsIn.close();
fsIn.Dispose();
Better yet, if you're limiting the use of your StreamReader to one method, stick the Close/Dispose in a Finally.
Make sure the stream is closed in finally.
FileStream fsIn = null;
StreamReader srIn = null;
try
{
fsIn = new FileStream("path",FileMode.Open, FileAccess.Read, FileShare.None);
srIn = new StreamReader(fsIn, System.Text.Encoding.Default);
//...do stuff....
}
catch (Exception ex)
{
}
finally
{
srIn.close();
srIn.Dispose();
fsIn.close();
fsIn.Dispose();
}

Resources