Add node in XML file crashes - c#

I created a ping application with a service that pings to URLs. The list of the URLs is stored in an XML file.
My application crashes when I'm trying to add a new site to my XML while the service is running.
VS2010 says my file is being used by some other process but I'm sure that everything is fine. My service isn't using the XML while I'm adding to it.
BUT I guess using an XmlReader & XmlWriter at the same time is where it crashes.
I'll rewrite my code with LINQ to XML but I was wondering if it's possible to use XmlReader & XmlWriter at the same time?
private void saveSites(Site newSite)
{
XmlDocument XDoc = new XmlDocument();
bool fileExists = true;
if (File.Exists("c:\\temp\\sites.xml") == false)
{
createXML();
fileExists = false;
}
using (XmlReader XReader = XmlReader.Create("c:\\temp\\sites.xml"))
{
XDoc.Load(XReader);
if (fileExists == true)
{
XmlNode SiteNode = XDoc.CreateNode(XmlNodeType.Element, "site", "");
XmlNode URLNode = XDoc.CreateNode(XmlNodeType.Element, "url", "");
URLNode.InnerText = newSite.URL;
XmlNode EmailNode = XDoc.CreateNode(XmlNodeType.Element, "email", "");
EmailNode.InnerText = newSite.Email;
SiteNode.AppendChild(URLNode);
SiteNode.AppendChild(EmailNode);
XDoc.DocumentElement.AppendChild(SiteNode);
}
else
{
foreach (Site site in sites)
{
XmlNode SiteNode = XDoc.CreateNode(XmlNodeType.Element, "site", "");
XmlNode URLNode = XDoc.CreateNode(XmlNodeType.Element, "url", "");
URLNode.InnerText= site.URL;
XmlNode EmailNode = XDoc.CreateNode(XmlNodeType.Element, "email", "");
EmailNode.InnerText = site.Email;
SiteNode.AppendChild(URLNode);
SiteNode.AppendChild(EmailNode);
XDoc.DocumentElement.AppendChild(SiteNode);
}
}
XDoc.Save("c:\\temp\\sites.xml");
}
}

Your reader is blocking the writing because it is in the using block. I'd suggest using the Load method the XmlDocument object with a uri instead of creating your own reader. Then also you can separate the initilisation from the writing operation.

Close your XMLReader explicitly.
using (XmlReader reader = XmlReader.Create("file.xml"))
{
while (reader.Read())
{
...
}
reader.Close();
}

Related

How to fetch file names inside a folder of a Sharepoint Document Library in C#?

I have a document Library - "Artifacts" on my sharepoint server. And inside the library , I have a few folders. I want to fetch the names of all the files residing inside a folder. I am using Lists.asmx webservice for getting this info. But I have only been able to get the names of the folders but not the names of the file inside each folder. Below is the code for getting names of the folders. If there is a better approach to getting file names instead of Lists.asmx then please suggest it with some sample code. Otherwise please let me know how to fetch file names inside a folder using Lists.asmx webservice.
public Collection<string> GetFileNamesFromList(string sitePath, string folderName)
{
Collection<string> artifactsList = new Collection<string>();
string innerhtml = string.Empty;
string listServiceURL = string.Format("{0}{1}", sitePath, this.spserviceInfo.ListserviceUri);
Lists listWS = new Lists(listServiceURL);
listWS.UseDefaultCredentials = true;
listWS.Url = listServiceURL;
XmlDocument xmlDoc = new XmlDocument();
XmlNode artifactQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
XmlNode artifactViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
XmlNode artifactQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
artifactQueryOptions.InnerXml = "<IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls>";
artifactViewFields.InnerXml = "";
artifactQuery.InnerXml = "";
XmlNode ndListItems = listWS.GetListItems("Artifacts", null, artifactQuery, artifactViewFields, null, artifactQueryOptions, null);
XmlNodeList oNodes = ndListItems.ChildNodes;
foreach (XmlNode node in oNodes)
{
XmlNodeReader objReader = new XmlNodeReader(node);
while (objReader.Read())
{
if (objReader["ows_LinkFilename"] != null)
{
var folder = objReader["ows_LinkFilename"].ToString();
artifactsList.Add(folder);
}
}
}
return artifactsList;
}
Try the following code to get the items based on the folder
using(SPSite site = new SPSite("site url"))
{
using(SPWeb web = site.OpenWeb())
{
SPFolder folder = web.GetFolder("/Docs/folder1");
if(folder.ItemCount > 0)
{
SPList list = web.Lists.TryGetList("ListName");
SPQuery query = new SPQuery();
query.Folder = folder;
SPListItemCollection = list.GetItems(query);
}
}
}

Incorrect parsing of Textbox in docx by OpenXML

I am reading a .docx file using OpenXML in C#. It reads everything correctly but strangely, the content of textbox is being read thrice. What could be wrong? Here is the code to read .docx:
public static string TextFromWord(String file)
{
const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
StringBuilder textBuilder = new StringBuilder();
using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(file, false))
{
// Manage namespaces to perform XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", wordmlNamespace);
// Get the document part from the package.
// Load the XML in the document part into an XmlDocument instance.
XmlDocument xdoc = new XmlDocument(nt);
xdoc.Load(wdDoc.MainDocumentPart.GetStream());
XmlNodeList paragraphNodes = xdoc.SelectNodes("//w:p", nsManager);
foreach (XmlNode paragraphNode in paragraphNodes)
{
XmlNodeList textNodes = paragraphNode.SelectNodes(".//w:t", nsManager);
foreach (System.Xml.XmlNode textNode in textNodes)
{
textBuilder.Append(textNode.InnerText);
}
textBuilder.Append(Environment.NewLine);
}
}
return textBuilder.ToString();
}
The part of file I am talking about is:
The result is: I read it in a test application like this:
What's wrong here?

How keep carriage return from parsing XML

I am looking on Internet how keep the carriage return from XML data but I could not find the answer, so I'm here :)
The objective is to write in a file the content of a XML data. So, if the value of the node contains some "\r\n" data, the soft need to write them in file in order to create new line, but it doesn't write, even with space:preserve.
Here is my test class:
XElement xRootNode = new XElement("DOCS");
XElement xData = null;
//XNamespace ns = XNamespace.Xml;
//XAttribute spacePreserve = new XAttribute(ns+"space", "preserve");
//xRootNode.Add(spacePreserve);
xData = new XElement("DOC");
xData.Add(new XAttribute("FILENAME", "c:\\titi\\prout.txt"));
xData.Add(new XAttribute("MODE", "APPEND"));
xData.Add("Hi my name is Baptiste\r\nI'm a lazy boy");
xRootNode.Add(xData);
bool result = Tools.writeToFile(xRootNode.ToString());
And here is my process class:
try
{
XElement xRootNode = XElement.Parse(xmlInputFiles);
String filename = xRootNode.Element(xNodeDoc).Attribute(xAttributeFilename).Value.ToString();
Boolean mode = false;
try
{
mode = xRootNode.Element(xNodeDoc).Attribute(xWriteMode).Value.ToString().ToUpper().Equals(xWriteModeAppend);
}
catch (Exception e)
{
mode = false;
}
String value = xRootNode.Element(xNodeDoc).Value;
StreamWriter destFile = new StreamWriter(filename, mode, System.Text.Encoding.Unicode);
destFile.Write(value);
destFile.Close();
return true;
}
catch (Exception e)
{
return false;
}
Does anybody have an idea?
If you want to preserve cr lf in element or attribute content when saving a XDocument or XElement you can do that by using certain XmlWriterSettings, namely NewLineHandling to Entitize:
string fileName = "XmlOuputTest1.xml";
string attValue = "Line1.\r\nLine2.";
string elementValue = "Line1.\r\nLine2.\r\nLine3.";
XmlWriterSettings xws = new XmlWriterSettings();
xws.NewLineHandling = NewLineHandling.Entitize;
XDocument doc = new XDocument(new XElement("root",
new XAttribute("test", attValue),
elementValue));
using (XmlWriter xw = XmlWriter.Create(fileName, xws))
{
doc.Save(xw);
}
doc = XDocument.Load(fileName);
Console.WriteLine("att value: {0}; element value: {1}.",
attValue == doc.Root.Attribute("test").Value,
elementValue == doc.Root.Value);
In that example the value are preserved in the round trip of saving and loading as the output of the sample is "att value: True; element value: True."
Heres a useful link I found for parsing an Xml string with carraige returns, line feeds in it.
howto-correctly-parse-using-xelementparse-for-strings-that-contain-newline-character-in
It may help those who are parsing an Xml string.
For those who can't be bothered to click it says use an XmlTextReader instead
XmlTextReader xtr = new XmlTextReader(new StringReader(xml));
XElement items = XElement.Load(xtr);
foreach (string desc in items.Elements("Item").Select(i => (string)i.Attribute("Description")))
{
Console.WriteLine("|{0}|", desc);
}

Reading XML comments in C#

I have got some XML files that contain comments above the nodes. When I am reading the file in, as part of the process I would like to get the comment out as well. I know you can write a comment to the file using XmlComment, but not sure how to read them back out.
My XML looks similar to this:
<Objects>
<!--Comment about node-->
<GUID-bf2401c0-ef5e-4d20-9d20-a2451a199362>
<info job="SAVE" person="Joe" />
<info job="SAVE" person="Sally" />
</GUID-bf2401c0-ef5e-4d20-9d20-a2451a199362>
<!--Another Comment about node-->
<GUID-bf2401c0-ef5e-4d20-9d20-a5844113284112>
<info job="SAVE" person="John" />
<info job="SAVE" person="Julie" />
</GUID-bf2401c0-ef5e-4d20-9d20-a5844113284112>
Try this:
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreComments = false;
using (XmlReader reader = XmlReader.Create("input.xml", readerSettings))
{
XmlDocument myData = new XmlDocument();
myData.Load(reader);
// etc...
}
To read comments:
XmlReader xmlRdr = XmlReader.Create("Test.XML");
// Parse the file
while (xmlRdr.Read())
{
switch (xmlRdr.NodeType)
{
case XmlNodeType.Element:
// You may need to capture the last element to provide a context
// for any comments you come across... so copy xmlRdr.Name, etc.
break;
case XmlNodeType.Comment:
// Do something with xmlRdr.value
Using System.Xml.Linq:
var doc = XElement.Load(fileName);
var comments = doc.DescendantNodes().OfType<XComment>();
foreach (XComment comment in comments)
...
They are a part of the child nodes of the containing node as all other nodes: http://msdn.microsoft.com/en-us/library/system.xml.xmlcomment.aspx
I know the question is very old, but yesterday I had the same problem. So here is my solution:
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreWhitespace = false;
settings.IgnoreComments = false;
XmlReaderSettings settings2 = new XmlReaderSettings();
settings2.IgnoreWhitespace = false;
settings2.IgnoreComments = false;
XmlReader xmlreaderOriginalCfg = XmlReader.Create(#"C:\...xml", settings);
XmlReader xmlreaderVerificationCfg = XmlReader.Create(#"C:\....xml", settings);
XmlDocument myData = new XmlDocument();
myData.Load(xmlreaderOriginalCfg);
XmlDocument myData2 = new XmlDocument();
myData2.Load(xmlreaderVerificationCfg);
XmlNode parentNode = myData.SelectSingleNode("/configuration/appSettings");
foreach (XmlComment comment in myData2.SelectNodes("//comment()"))
{
XmlComment importedCom = myData.CreateComment(comment.Value);
parentNode.AppendChild(importedCom);
foreach (XmlNode node in myData2.DocumentElement.SelectNodes("/configuration/appSettings/add"))
{
XmlNode imported = myData.ImportNode(node, true);
parentNode.AppendChild(imported);
}
}
myData.Save(this.pathNew);
Maybe it helps somebody
I stored your XML into a file, here is the code sample.
XmlDocument document = new XmlDocument();
document.Load("test.xml");
foreach (XmlComment comment in document.SelectNodes("//comment()"))
{
Console.WriteLine("Comment: \"{0}\".", comment.Value);
}
Some sample code on how to access comments hope this helps
using System;
using System.IO;
using System.Xml;
public class Sample {
public static void Main() {
XmlDocument doc = new XmlDocument();
doc.LoadXml(#"<Objects><!--Comment about node--><othernode/><!--Some more comment--></Objects>");
XmlNode root = doc.FirstChild;
if (root.HasChildNodes)
{
for (int i=0; i<root.ChildNodes.Count; i++)
{
if( root.ChildNodes[i] is XmlComment)
Console.WriteLine(root.ChildNodes[i].InnerText);
}
}
}
}

Sharepoint via web service : checking if item exists in list

Because Microsoft did not include a way to have unique constraints in sharepoint, this has to be done manually.
I am inserting items into a sharepoint list via a web service method.
How can I check if an existing list item already exists with the same field ID value?
I've learnt I should be using wsLists.getListitems web service method, but its not exactly "user friendly". MSDN documentation is again not really great at explaining what should be an easy thing to do.
private bool itemDoesntExist()
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<Document><Query><Where><Contains><FieldRef Name=\"ID\" /><Value Type=\"Text\">" + this.ID + "</Value></Contains></Where></Query><ViewFields /><QueryOptions /></Document>");
XmlNode listQuery = doc.SelectSingleNode("//Query");
XmlNode listViewFields = doc.SelectSingleNode("//ViewFields");
XmlNode listQueryOptions = doc.SelectSingleNode("//QueryOptions");
XmlNode items = this.wsLists.GetListItems(this.ListName , string.Empty, listQuery, listViewFields, string.Empty, listQueryOptions, null);
if (items.ChildNodes[1].Attributes["ItemCount"].Value == "0")
{
return true;
}
else
{
return false;
}
}
Here's a procedure I wrote 2 years ago that pulls the ID of a document with a given filename... I think you could easily revise it to return true/false if a given ID exists in a list.
protected string GetDocumentID(Lists.Lists ls, string ListGUID, string FileName)
{
string strDocumentID = "-1";
string strViewGUID = "";
string strRowLimit = "50000";
XmlDocument xmlDoc = new XmlDocument();
XmlNode query = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
XmlNode viewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
XmlNode queryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
query.InnerXml = "";
viewFields.InnerXml = "";
queryOptions.InnerXml = "<IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls>";
System.Xml.XmlNode nodeListItems = ls.GetListItems(ListGUID, strViewGUID, query, viewFields, strRowLimit, queryOptions, null);
XmlDocument doc = new XmlDocument();
doc.LoadXml(nodeListItems.InnerXml);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("z", "#RowsetSchema");
nsmgr.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
foreach (XmlNode node in doc.SelectNodes("/rs:data/z:row", nsmgr))
{
if (node.Attributes["ows_LinkFilename"].Value == FileName)
{
strDocumentID = node.Attributes["ows_ID"].Value;
break;
}
}
return strDocumentID;
}
Here's the code that calls it...
Lists.Lists ls = new Lists.Lists();
ls.PreAuthenticate = true;
ls.Credentials = System.Net.CredentialCache.DefaultCredentials;
ls.Url = SharePointSiteURL + #"/_vti_bin/lists.asmx";
string DocID = GetDocumentID(ls, ListGUID, FileName);

Categories