C# Read XML files in the Resources folder - c#

I'm trying to read some xml files which I have included in the Resources folder under my project. Below is my code:
public void ReadXMLFile(int TFType)
{
XmlTextReader reader = null;
if (TFType == 1)
reader = new XmlTextReader(MyProject.Properties.Resources.ID01);
else if (TFType == 2)
reader = new XmlTextReader(MyProject.Properties.Resources.ID02);
while (reader.Read())
{
if (reader.IsStartElement())
{
switch (reader.Name)
{
case "Number":
// more coding on the cases.
}
But when I compile, there's an error on "QP2020E.Properties.Resources.ID01" saying: 'Illegal characters in path.' Do you guys know what's wrong?

The XmlTextReader constructor requires either a stream or a string. The one that requires a string is expecting a url (or path). You are passing it the value of your resource. You'll need to convert the string value into a stream.
To do this Wrap it in a StringReader(...)
reader = new XmlTextReader(new StringReader(MyProject.Properties.Resources.ID02));

You should provide the XMLTextReader with the file path not the file content. For instance, change
reader = new XmlTextReader(MyProject.Properties.Resources.ID01);
To:
StringReader s = new StringReader(MyProject.Properties.Resources.XmlFile);
XmlTextReader r = new XmlTextReader(s);

To read an XML file from a resource, use XDocument.Parse as described in this answer
I think you need to modify your code to be like this:
public void ReadXMLFile(int TFType)
{
XDocument doc = null;
if (TFType == 1)
doc = XDocument.Parse(MyProject.Properties.Resources.ID01);
else if (TFType == 2)
doc = XDocument.Parse(MyProject.Properties.Resources.ID02);
// Now use 'doc' as an XDocument object
}
More info on XDocument is here.

Related

C# Parse XML file into object from given tag

I have an xml file and the dataset that I want to make into an object is encapsulated by another tag, so when I try and parse it, of course it throws an InvalidOperationException, due to the unexpected member.
I've tried reading various MS Docs about xml, as well as googling my problem, but I couldn't find how could I solve it without too much hussle.
My code:
public static ClassToDeserialize GetObjectFromXml (string path)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ClassToDeserialize));
System.IO.FileStream file = System.IO.File.OpenRead(path);
ClassToDeserialize loadedObjectXml = xmlSerializer.Deserialize(file) as ClassToDeserialize;
return loadedLicenseXml;
}
So how could I tell this program to start deserializing only from a specific tag, as that contains the object's related xml data?
You might try read Xml up the point you find your node and then retrieve it's outer xml and put that into XmlSerializer. Let's say you have a simple XML file like this one:
<rootnode>
<!-- some nodes inside -->
<uselessNode>
<thatsWhatIWant>
<!-- some fields inside -->
<uselessNodeInside/>
<usefullNodeInside/>
</thatsWhatIWant>
</uselessNode>
</rootnode>
What you could do is open up XmlReader:
XmlReader reader = XmlReader.Create("path/to/myfile.xml");
Then read contents up to your POI and store that in some variable:
string wantedNodeContents = string.Empty;
while (reader.Read())
{
if(reader.NodeType == XmlNodeType.Element && reader.Name == "thatsWhatIWant")
{
wantedNodeContents = reader.ReadOuterXml();
break;
}
}
Having this you should be able to use XmlSerializer like so:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ClassToDeserialize));
System.IO.TextReader textReader = System.IO.StringReader(wantedNodeContents);
ClassToDeserialize loadedObjectXml = xmlSerializer.Deserialize(textReader) as ClassToDeserialize;
You can alternatively (or in addition to that) try to add some handlers for UnknownNode and UnknownAttribute:
xmlSerializer.UnknownNode+= new XmlNodeEventHandler(UnknownNode);
xmlSerializer.UnknownAttribute+= new XmlAttributeEventHandler(UnknownAttribute);
void UnknownNode(object sender, XmlNodeEventArgs e) { }
void UnknownAttribute(object sender, XmlAttributeEventArgs e) { }

Xml gets corrupted each time I append a node

I have an Xml file as:
<?xml version="1.0"?>
<hashnotes>
<hashtags>
<hashtag>#birthday</hashtag>
<hashtag>#meeting</hashtag>
<hashtag>#anniversary</hashtag>
</hashtags>
<lastid>0</lastid>
<Settings>
<Font>Arial</Font>
<HashtagColor>red</HashtagColor>
<passwordset>0</passwordset>
<password></password>
</Settings>
</hashnotes>
I then call a function to add a node in the xml,
The function is :
public static void CreateNoteNodeInXDocument(XDocument argXmlDoc, string argNoteText)
{
string lastId=((Convert.ToInt32(argXmlDoc.Root.Element("lastid").Value)) +1).ToString();
string date = DateTime.Now.ToString("MM/dd/yyyy");
argXmlDoc.Element("hashnotes").Add(new XElement("Note", new XAttribute("ID", lastId), new XAttribute("Date",date),new XElement("Text", argNoteText)));
//argXmlDoc.Root.Note.Add new XElement("Text", argNoteText)
List<string> hashtagList = Utilities.GetHashtagsFromText(argNoteText);
XElement reqNoteElement = (from xml2 in argXmlDoc.Descendants("Note")
where xml2.Attribute("ID").Value == lastId
select xml2).FirstOrDefault();
if (reqNoteElement != null)
{
foreach (string hashTag in hashtagList)
{
reqNoteElement.Add(new XElement("hashtag", hashTag));
}
}
argXmlDoc.Root.Element("lastid").Value = lastId;
}
After this I save the xml.
Next time when I try to load the Xml, it fails with an exception:
System.Xml.XmlException: Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it.
Here is the code to load the XML:
private static XDocument hashNotesXDocument;
private static Stream hashNotesStream;
StorageFile hashNoteXml = await InstallationFolder.GetFileAsync("hashnotes.xml");
hashNotesStream = await hashNoteXml.OpenStreamForWriteAsync();
hashNotesXDocument = XDocument.Load(hashNotesStream);
and I save it using:
hashNotesXDocument.Save(hashNotesStream);
You don't show all of your code, but it looks like you open the XML file, read the XML from it into an XDocument, edit the XDocument in memory, then write back to the opened stream. Since the stream is still open it will be positioned at the end of the file and thus the new XML will be appended to the file.
Suggest eliminating hashNotesXDocument and hashNotesStream as static variables, and instead open and read the file, modify the XDocument, then open and write the file using the pattern shown here.
I'm working only on desktop code (using an older version of .Net) so I can't test this, but something like the following should work:
static async Task LoadUpdateAndSaveXml(Action<XDocument> editor)
{
XDocument doc;
var xmlFile = await InstallationFolder.GetFileAsync("hashnotes.xml");
using (var reader = new StreamReader(await xmlFile.OpenStreamForReadAsync()))
{
doc = XDocument.Load(reader);
}
if (doc != null)
{
editor(doc);
using (var writer = new StreamWriter(await xmlFile.OpenStreamForWriteAsync()))
{
// Truncate - https://stackoverflow.com/questions/13454584/writing-a-shorter-stream-to-a-storagefile
if (writer.CanSeek && writer.Length > 0)
writer.SetLength(0);
doc.Save(writer);
}
}
}
Also, be sure to create the file before using it.

How to Json To Xml

I am new for Json and I have a simple problem.
I am trying to convert json file to xml file with c#. But it throw an exception.
The Code is ;
private void TakeXML()
{
string json = ReadText();
XmlDocument doc = (XmlDocument)Newtonsoft.Json.JsonConvert.DeserializeXmlNode(json);
XmlTextWriter writer = new XmlTextWriter("json.xml", null);
writer.Formatting = Formatting.Indented;
doc.Save(writer);
}
The ReadText function is;
private string ReadText()
{
FileStream fs = new FileStream(#"C:\Users\Sinan\Desktop\bina.json", FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
string json;
try
{
json = sr.ReadToEnd();
return json;
}
catch (Exception)
{
return null;
}
finally
{
sr.Close();
fs.Dispose();
}
}
for XmlDocument doc = (XmlDocument)Newtonsoft.Json.JsonConvert.DeserializeXmlNode(json); line, it said that;
"JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName."
I am searching to solve this problem but ı haven't found it. İf you help me in this regard, I will be glad. Thank you.
In method DeserializeXmlNode specify the root node name in second parameter as shown in below code:
XmlDocument doc =
(XmlDocument)
Newtonsoft.Json.JsonConvert.DeserializeXmlNode(json, "rootNodeName");
// second parameter
Although if you can give json string then it would be easy to give exact answer.
Reference link: Converting JSON to XML

Get file name from Xdocument after Linq query

I'm querying a bunch of SGML documents for specific Element and Attributes. This works ok and will display a message box when it finds the file which contains the specified items. However, what i need it to do is also give me the name of the file it's found them in, otherwise it's next to useless. I can't seem to find a way to get the filename of the file. I have:
XDocument doc = XDocument.Load(sgmlReader);
IEnumerable<XElement> selectedElement =
from el in doc.Descendants(Element_textBox.Text)
where (string)el.Attribute(Attribute_textBox.Text) == Value_textBox.Text
select el;
//need to select the DMC and title and put in a variable, and list them
foreach (XElement elem in selectedElement)
//Console.WriteLine(elem);
MessageBox.Show("Data Module Found: " + elem);
As I say, I need to somehow identify the file from which the query finds a match. Any ideas?
You can specify that the document's base URI must be set on load:
var doc = XDocument.Load(#"file.xml", LoadOptions.SetBaseUri);
Then you can get the document URI from any element:
var someElement = doc.Root;
var uri = element.Document.BaseUri;
Console.WriteLine(uri); // Prints: file:///C:/file.xml
If you are using a Stream or TextReader, you have to get the filename from somewhere else and store it yourself. Otherwise there is no way to get the filename.
Imagine I passed a MemoryStream or NetworkStream to XDocument.Load(), then there is no filename. In general, when working with streams or readers, you don't have a file name.
However there is one exception: if you can get the base stream of the reader and cast it to a FileStream, then you can get the filename:
var fs = File.OpenRead(#"C:\myxml.xml");
var reader = new StreamReader(fs);
DoSomething(reader);
static void DoSomething(TextReader reader)
{
var streamReader = reader as StreamReader;
if (streamReader != null)
{
var fileStream = streamReader.BaseStream as FileStream;
if (fileStream != null)
Console.WriteLine(fileStream.Name);
else { /* No filename */ }
}
else { /* No filename */ }
// ...
}

Manipulating Word 2007 Document XML in C#

I am trying to manipulate the XML of a Word 2007 document in C#. I have managed to find and manipulate the node that I want but now I can't seem to figure out how to save it back. Here is what I am trying:
// Open the document from memoryStream
Package pkgFile = Package.Open(memoryStream, FileMode.Open, FileAccess.ReadWrite);
PackageRelationshipCollection pkgrcOfficeDocument = pkgFile.GetRelationshipsByType(strRelRoot);
foreach (PackageRelationship pkgr in pkgrcOfficeDocument)
{
if (pkgr.SourceUri.OriginalString == "/")
{
Uri uriData = new Uri("/word/document.xml", UriKind.Relative);
PackagePart pkgprtData = pkgFile.GetPart(uriData);
XmlDocument doc = new XmlDocument();
doc.Load(pkgprtData.GetStream());
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", nsUri);
XmlNodeList nodes = doc.SelectNodes("//w:body/w:p/w:r/w:t", nsManager);
foreach (XmlNode node in nodes)
{
if (node.InnerText == "{{TextToChange}}")
{
node.InnerText = "success";
}
}
if (pkgFile.PartExists(uriData))
{
// Delete template "/customXML/item1.xml" part
pkgFile.DeletePart(uriData);
}
PackagePart newPkgprtData = pkgFile.CreatePart(uriData, "application/xml");
StreamWriter partWrtr = new StreamWriter(newPkgprtData.GetStream(FileMode.Create, FileAccess.Write));
doc.Save(partWrtr);
partWrtr.Close();
}
}
pkgFile.Close();
I get the error 'Memory stream is not expandable'. Any ideas?
I would recommend that you use Open XML SDK instead of hacking the format by yourself.
Using OpenXML SDK 2.0, I do this:
public void SearchAndReplace(Dictionary<string, string> tokens)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(_filename, true))
ProcessDocument(doc, tokens);
}
private string GetPartAsString(OpenXmlPart part)
{
string text = String.Empty;
using (StreamReader sr = new StreamReader(part.GetStream()))
{
text = sr.ReadToEnd();
}
return text;
}
private void SavePart(OpenXmlPart part, string text)
{
using (StreamWriter sw = new StreamWriter(part.GetStream(FileMode.Create)))
{
sw.Write(text);
}
}
private void ProcessDocument(WordprocessingDocument doc, Dictionary<string, string> tokenDict)
{
ProcessPart(doc.MainDocumentPart, tokenDict);
foreach (var part in doc.MainDocumentPart.HeaderParts)
{
ProcessPart(part, tokenDict);
}
foreach (var part in doc.MainDocumentPart.FooterParts)
{
ProcessPart(part, tokenDict);
}
}
private void ProcessPart(OpenXmlPart part, Dictionary<string, string> tokenDict)
{
string docText = GetPartAsString(part);
foreach (var keyval in tokenDict)
{
Regex expr = new Regex(_starttag + keyval.Key + _endtag);
docText = expr.Replace(docText, keyval.Value);
}
SavePart(part, docText);
}
From this you could write a GetPartAsXmlDocument, do what you want with it, and then stream it back with SavePart(part, xmlString).
Hope this helps!
You should use the OpenXML SDK to work on docx files and not write your own wrapper.
Getting Started with the Open XML SDK 2.0 for Microsoft Office
Introducing the Office (2007) Open XML File Formats
How to: Manipulate Office Open XML Formats Documents
Manipulate Docx with C# without Microsoft Word installed with OpenXML SDK
The problem appears to be doc.Save(partWrtr), which is built using newPkgprtData, which is built using pkgFile, which loads from a memory stream... Because you loaded from a memory stream it's trying to save the document back to that same memory stream. This leads to the error you are seeing.
Instead of saving it to the memory stream try saving it to a new file or to a new memory stream.
The short and simple answer to the issue with getting 'Memory stream is not expandable' is:
Do not open the document from memoryStream.
So in that respect the earlier answer is correct, simply open a file instead.
Opening from MemoryStream editing the document (in my experience) easy lead to 'Memory stream is not expandable'.
I suppose the message appears when one do edits that requires the memory stream to expand.
I have found that I can do some edits but not anything that add to the size.
So, f.ex deleting a custom xml part is ok but adding one and some data is not.
So if you actually need to open a memory stream you must figure out how to open an expandable MemoryStream if you want to add to it.
I have a need for this and hope to find a solution.
Stein-Tore Erdal
PS: just noticed the answer from "Jan 26 '11 at 15:18".
Don't think that is the answer in all situations.
I get the error when trying this:
var ms = new MemoryStream(bytes);
using (WordprocessingDocument wd = WordprocessingDocument.Open(ms, true))
{
...
using (MemoryStream msData = new MemoryStream())
{
xdoc.Save(msData);
msData.Position = 0;
ourCxp.FeedData(msData); // Memory stream is not expandable.

Categories