How to use XmlDocument object instead of reading XML file from drive? - c#

I didn't know that I can use XSD schema to serialize received XML file. I used xsd.exe to generate cs class from XSD file and now I need to use that class to get data in class properties but I miss one thing and I need help.
This is the code:
private void ParseDataFromXmlDocument_UsingSerializerClass(XmlDocument doc)
{
XmlSerializer ser = new XmlSerializer(typeof(ClassFromXsd));
string filename = Path.Combine("C:\\myxmls\\test", "xmlname.xml");
ClassFromXsdmyClass = ser.Deserialize(new FileStream(filename, FileMode.Open)) as ClassFromXsd;
if (myClass != null)
{
// to do
}
...
Here I use XML file from drive. And I want to use this XmlDocument from parameter that I passed in. So how to adapt this code to use doc instead XML from drive?

You could write the XmlDocument to a MemoryStream, and then Deserialize it like you already did.
XmlDocument doc = new XmlDocument();
ClassFromXsd obj = null;
using (var s = new MemoryStream())
{
doc.Save(s);
var ser = new XmlSerializer(typeof (ClassFromXsd));
s.Seek(0, SeekOrigin.Begin);
obj = (ClassFromXsd)ser.Deserialize(s);
}

Related

Append XML to file without writing it from scratch? [duplicate]

This question already has answers here:
Fastest way to add new node to end of an xml?
(10 answers)
Closed 5 years ago.
The standard way to append an XML file in LINQ-to-XML is to read it in, modify the in-memory document, and write the whole file out from scratch. For example:
XDocument doc = XDocument.Load("pathToDoc.xml");
doc.Root.Add(new XElement(namespace + "anotherChild", new XAttribute("child-id", childId)));
doc.Save("pathToDoc.xml");
Or, with a FileStream:
using (FileStream fs = new FileStream("pathToDoc.xml", FileMode.Open, FileAccess.ReadWrite)) {
XDocument doc = XDocument.Load(fs);
doc.Root.Add(new XElement(namespace + "anotherChild", new XAttribute("child-id", childId)));
fs.SetLength(0);
using (var writer = new StreamWriter(fs, new UTF8Encoding(false))) {
doc.Save(writer);
}
}
However, in both cases, the existing XML document is being loaded into memory, modified in memory, and then written from scratch to the XML file. For small XML files this is OK, but for large files with hundreds or thousands of nodes this seems like a very inefficient process. Is there any way to make XDocument (or perhaps something like an XmlWriter) just append the necessary additional nodes to the existing XML document rather than blanking it out and starting from scratch?
This totally depends on the position where you need to add the additional elements. Of course you can implement something that removes the closing "</root>" tag, writes additional elements and then adds the "</root>" again. However, such code is highly optimized for your purpose and you'll probably not find a library for it.
Your code could look like this (quick and dirty, without input checking, assuming that <root/> cannot exist):
using System.IO;
using System.Xml.Linq;
namespace XmlAddElementWithoutLoading
{
class Program
{
static void Main()
{
var rootelement = "root";
var doc = GetDocumentWithNewNodes(rootelement);
var newNodes = GetXmlOfNewNodes(doc);
using (var fs = new FileStream("pathToDoc.xml", FileMode.Open, FileAccess.ReadWrite))
{
using (var writer = new StreamWriter(fs))
{
RemoveClosingRootNode(fs, rootelement);
writer.Write(newNodes);
writer.Write("</"+rootelement+">");
}
}
}
private static void RemoveClosingRootNode(FileStream fs, string rootelement)
{
fs.SetLength(fs.Length - ("</" + rootelement + ">").Length);
fs.Seek(0, SeekOrigin.End);
}
private static string GetXmlOfNewNodes(XDocument doc)
{
var reader = doc.Root.CreateReader();
reader.MoveToContent();
return reader.ReadInnerXml();
}
private static XDocument GetDocumentWithNewNodes(string rootelement)
{
var doc = XDocument.Parse("<" + rootelement + "/>");
var childId = "2";
XNamespace ns = "namespace";
doc.Root.Add(new XElement(ns + "anotherChild", new XAttribute("child-id", childId)));
return doc;
}
}
}

Assembly load XML document from memorystream C#

I have a database and I convert it to XML document like this:
XmlDocument _XMLDoc = new XmlDocument();
_XMLDoc.LoadXml(dataset.GetXml());
XML document is in memory and I need to read the assembly. So far I can only read the assembly if the file is saved to disk like this:
using (var stream= Assembly.GetExecutingAssembly().GetManifestResourceStream("_XMLDoc.xml"))
{
...
}
How can I modify my code so I can read the assembly from memorystream?
Try the following:
var _XMLDoc = new XmlDocument();
_XMLDoc.LoadXml(dataset.GetXml());
var byteArray = Encoding.ASCII.GetBytes(_XMLDoc.OuterXml);
using (var stream = new MemoryStream(byteArray))
{
// ProcessStream(stream);
}

getting "Stream Was Not Writable" while saving an XML document that I read via a stream from a zip file

I have a zip file that contains an xml file,
I'm Loading this xml file to an xml document without having to extract the file.
this is done via a stream.
after doing so, I'm modifying the inner text of some nodes.
The Problem is that I'm getting the previous mentioned exception after trying to save the stream, here's the code:
(I'm using DotNetZip here)
ZipFile zipFile = ZipFile.Read(zipPath); // the path is my desktop
foreach (ZipEntry entry in zipFile)
{
if (entry.FileName == "myXML.xml")
{
//creating the stream and loading the xml doc from the zip file:
Stream stream = zipFile[entry.FileName].OpenReader();
XmlReader xReader = XmlReader.Create(stream);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xReader);
//changing the inner text of the doc nodes:
xDoc.DocumentElement.SelectSingleNode("Account/Name").InnerText = "VeXe";
xDoc.DocumentElement.SelectSingleNode("Account/Money").InnerText = "Million$";
xDoc.Save(stream); // here's where I got the exception.
break;
}
}
I'm not a pro coder, but instead of xDoc.Save(stream); I noticed that it could also take a XmlWriter as a parameter, so I tried making an instance of the XmlWriter immediately after instantiating the XmlReader ..
I tried doing this: xDoc.Save(XmlWriter)
I got an exception saying something like: "Cannot Write After Reading"
how can I successfully save the xDoc ?
ADDED:
I had an idea of saving the xml file in some other place, like a temp folder or something
then adding that saved file in the zip overwriting the old one, then deleting the xml file in the temp ..
but that's not what i want, I want to deal directly with the zip file, in and out, no third parties.
You're attempting to write to the same Stream you've opened it with. You cannot do that.
Perhaps try something like this:
ZipFile zipFile = ZipFile.Read(zipPath); // the path is my desktop
foreach (ZipEntry entry in zipFile)
{
if (entry.FileName == "myXML.xml")
{
//creating the stream and loading the xml doc from the zip file:
using (Stream stream = zipFile[entry.FileName].OpenReader()) {
XmlReader xReader = XmlReader.Create(stream);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xReader);
}
//changing the inner text of the doc nodes:
xDoc.DocumentElement.SelectSingleNode("Account/Name").InnerText = "VeXe";
xDoc.DocumentElement.SelectSingleNode("Account/Money").InnerText = "Million$";
using (StreamWriter streamWriter = new StreamWriter(pathToSaveTo)) {
xDoc.Save(streamWriter);
break;
}
}
}
A quick look at the docs leads me to believe that you should do it something like this:
using(ZipFile zipFile = ZipFile.Read(zipPath))
foreach (ZipEntry entry in zipFile)
{
if (entry.FileName == "myXML.xml")
{
XmlDocument xDoc = new XmlDocument();
//creating the stream and loading the xml doc from the zip file:
using(Stream stream = zipFile[entry.FileName].OpenReader())
using(XmlReader xReader = XmlReader.Create(stream))
{
xDoc.Load(xReader);
}
//changing the inner text of the doc nodes:
xDoc.DocumentElement.SelectSingleNode("Account/Name").InnerText = "VeXe";
xDoc.DocumentElement.SelectSingleNode("Account/Money").InnerText = "Million$";
using(var ms=new MemoryStream())
using(var sw=new StreamWriter(ms))
{
xDoc.Save(sw);
sw.Flush();
ms.Position=0;
zipFile.UpdateEntry(entry.FileName,ms);
}
break;
}
}

C# Get Microsoft ReportViewer to load XDocument contents

I have an Xdocument object which is populated with xml (the definition for a report -rdl). I would like to give the contents of this XDocument to the report viewer.
this.reportViewer1.LocalReport.LoadReportDefinition();
LoadReportDefinition only seems to take either TextReader or FileStream arguments....but my report definition is loaded within my XDocument? How can I stream the contents of my XDocument?
You can use the StringReader class like so:
using (var textReader = new StringReader(xDocument.ToString()))
{
this.reportViewer1.LocalReport.LoadReportDefinition(textReader);
}
Or alternatively use a Stream:
using (var stream = new MemoryStream())
{
xDocument.Save(stream);
stream.Position = 0;
this.reportViewer1.LocalReport.LoadReportDefinition(stream);
}

XslCompiledTransform and Serialization

I am trying to implement some functions that will convert one object to another with XslCompiledTransform.
I found some implementations for Serializing an object to XML string and DeSerialize the XML string to an object.
Another function does the XslCompiledTransform from object1 to obejbct2.
To generate the XSLT file i used the Altova MapForce, just loaded the XML of the serialized objects and mapped some attributes.
Now for the problems:
first I noticed that the XslCompiledTransform doesn't work with XSLT version 2.0. is there any newer functions that do work with XSLT 2.0? maybe some settings?
secondly I get an exception when trying to DeSerialize the XML to an object:
"There was an error deserializing the object of type myObject Input string was not in a correct format."
I don't understand where is the problem.
Does anybody have a sample code that does such a thing? all I find in google are Transformations of HTML code and not objects.
Here are the functions:
private static string runXSLT(string xsltFile, string inputXML)
{
XmlDocument XmlDoc = new XmlDocument();
// Load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform(true);
xslt.Load(xsltFile);
StringReader StrReader = new StringReader(inputXML);
XmlTextReader XmlReader = new XmlTextReader(StrReader);
//Create an XmlTextWriter which outputs to memory stream
Stream stream = new MemoryStream();
XmlWriter writer = new XmlTextWriter(stream, Encoding.UTF8);
// Execute the transform and output the results to a file.
xslt.Transform(XmlReader, writer);
stream.Position = 0;
XmlDoc.Load(stream);
return XmlDoc.InnerXml;
}
public static string SerializeAnObject(object AnObject)
{
XmlDocument XmlDoc = new XmlDocument();
DataContractSerializer xmlDataContractSerializer = new DataContractSerializer(AnObject.GetType());
MemoryStream MemStream = new MemoryStream();
try
{
xmlDataContractSerializer.WriteObject(MemStream, AnObject);
MemStream.Position = 0;
XmlDoc.Load(MemStream);
return XmlDoc.InnerXml;
}
finally
{
MemStream.Close();
}
}
public static Object DeSerializeAnObject(string XmlOfAnObject, Type ObjectType)
{
StringReader StrReader = new StringReader(XmlOfAnObject);
DataContractSerializer xmlDataContractSerializer = new DataContractSerializer(ObjectType);
XmlTextReader XmlReader = new XmlTextReader(StrReader);
try
{
Object AnObject = xmlDataContractSerializer.ReadObject(XmlReader);
return AnObject;
}
finally
{
XmlReader.Close();
StrReader.Close();
}
}
Thanks allot,
Omri.
XslCompiledTransform does not support XSLT 2.0. In fact, XSLT 2.0 is not supported within the .NET Framework at all (you could try the Saxon version for .NET, but be aware that this is just the Java version running inside IKVM).
From your description I did not understand why you are taking the detour via XML to convert one object into another. Why don't you simply provide a constructor in your target object that takes your input object as a paramater? Then you can code all the mapping inside that constructor. This is not onlyby far more efficient than serializing, transforming and deserializing your objects you will also get the type safety of C#.

Categories

Resources