Convert Multiple XML files into single CSV using XSLT and C# - c#

I'm trying to convert XML file to CSV using XSLT. It works. I was able to convert XML and get the output I want using XSLT.
The challenge I'm facing right now is that I have many many XML files in a single location. I want to get ALL the data from all XMLs and put them into a single CSV file. I have a for loop that goes through the folder and gets the XML files and then exports it to CSV. However, every time it converts new XML it overrides the data in the current CSV file. So the end result is I only get one row in the CSV file instead of 500 (if there's 500 xml files).
Here's the C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.IO;
using System.Diagnostics;
namespace XSL
{
class Program
{
public static void Main(string[] args)
{
try
{
//declaring xmlFile
string xmlfile ;
//Loading the XSLT template
String xsltfile = "C:\\Win\\XMLReader\\XSL\\csv.xsl";
//get folder location
string d = DateTime.Now.ToString("yyyyMMdd");
//Console.WriteLine(d.ToString());
//first part of the location path
String firstPath = #"\\tripx-exportm\\output\\Skill 53115;1_";
//full path
string fullPath = firstPath + d.ToString() + "_000000" + #"\\IDX";
//Get files from a folder
string[] filePath = Directory.GetFiles(fullPath, "*.xml");
//get each file in the folder
foreach (string file in filePath)
{
Console.WriteLine(file);
xmlfile = file;
Transform(xmlfile, xsltfile);
}
//Get the count of XML files in the current folder
DirectoryInfo dir = new DirectoryInfo(fullPath);
int count = dir.GetFiles().Length;
Console.WriteLine("Count of XML files: " + count);
//Transform(xmlfile, xsltfile);
Console.WriteLine("press any key");
Console.ReadKey();
}
catch(Exception e){
Console.WriteLine(e.ToString());
}
}
public static void Transform(string xml, string xslt)
{
try
{
//load the xml doc
XPathDocument myDoc = new XPathDocument(xml);
XslCompiledTransform myXL = new XslCompiledTransform();
//load the xslt doc
myXL.Load(xslt);
//create the output
XmlTextWriter myWriter = new XmlTextWriter("result.csv", null);
myXL.Transform(myDoc, null, myWriter);
myWriter.Close();
}
catch (Exception e)
{
Console.WriteLine("exception : {0}", e.ToString());
};
}
}
}
XSLT file
Any suggestions on how I can put the data from multiple XMLs into a single CSV?
Thank you

You need to use the right constructor overload for the XmTextWriter to take a stream, rather than a file name.
The help on MSDN says this about the file name overload:
The filename to write to. If the file exists, it truncates it and
overwrites it with the new content.
So you should to do this to Transform to make it work:
public static void Transform(Stream stream, string xml, string xslt)
{
var myDoc = new XPathDocument(xml);
var myXL = new XslCompiledTransform();
myXL.Load(xslt);
using(var myWriter = new XmlTextWriter(stream, Encoding.Default))
{
myXL.Transform(myDoc, null, myWriter);
myWriter.Flush();
myWriter.Close();
}
}
Then the calling code should look like this:
using (var fs = new FileStream("result.csv", FileMode.Create))
{
foreach (string file in filePath)
{
Transform(fs, file, xsltfile);
}
fs.Flush();
fs.Close();
}
I've taken out the (bad) exception handling, and comments, etc.

I have come up with a different approach. It may not be the best possible solution, but it works for me.
In my code, I added a counter to count the number of XMLs that were processed. It increments.
In my Transform procedure instead of hard coding the name "result.csv", I generate the name:
string Result = "result" + count.ToString() + ".csv";
And I use that name in the XMLWriter
XmlTextWriter myWriter = new XmlTextWriter(Result, null);
This way it generates a single CSV for every XML and it will not override the existing one.
Then I wrote another procedure that combines all the CVSs into one:
private static void JoinCsvFiles(string[] csvFileNames, string outputDestinationPath)
{
StringBuilder sb = new StringBuilder();
bool columnHeadersRead = false;
foreach (string csvFileName in csvFileNames)
{
TextReader tr = new StreamReader(csvFileName);
string columnHeaders = tr.ReadLine();
// Skip appending column headers if already appended
if (!columnHeadersRead)
{
sb.AppendLine(columnHeaders);
columnHeadersRead = true;
}
sb.AppendLine(tr.ReadToEnd());
}
File.WriteAllText(outputDestinationPath, sb.ToString());
}
And in the main, I just call
string[] csvFileNames = Directory.GetFiles(".", "result*.csv");
JoinCsvFiles(csvFileNames, "CsvOutput.csv");
Hope this helps somebody.

Related

Unable to move a file once I have read and appended data to a new file c#

I have a foreach loop that is appending data from 1 file (source) to another (destination).
Once the file has been appended with all data I want to move the original source file. When debugging im getting the error "Exception thrown: 'System.IO.IOException' in System.IO.FileSystem.dll"
Im assuming this is because the file is locked. How can I dispose this so I can move the file.
var stringwrite = new[] { prefix, prefix2 };
foreach (string line in File.ReadLines(currentFile))
{
var lastOne = line.Split(';').Last();
if (!stringwrite.Any(stringwrite => lastOne.Contains(stringwrite)))
continue;
//write lines found to new file
File.AppendAllText(todestination, line + Environment.NewLine);
}
//move original file to new directory
try
{
File.Move(currentFile, completeddestination);
break;
}
catch (Exception ex)
{
MessageBox.Show("Issue Moving File");
}
As you are reading the source file to the end and writing to the destination depending on a condition, it would make sense to keep both input and output streams open until the end of read/write operations. Note, that File.ReadLines will open the source file, read the contents, and then close it. Also, File.AppendAllText will open the destination file, append the contents, and then close the file. Such an approach is inefficient. I think, your task could be properly implemented using file streams. Please find the example below:
static void Main()
{
var sourcePath = "C:\\PathToSource";
var destinationPath = "C:\\PathToDestination";
var completedDestinationPath = "C:\\PathToCompletedDestination";
var prefixes = new[] { "some-prefix", "some-other-prefix" };
foreach (var source in EnumerateDataFiles(sourcePath))
{
// This assumes that files in source and destination and completed
// dectination directories have the same file name but different paths.
// If you use another convention for your data, please adjust it here
var destination = GetDestinationFilePath(source, destinationPath);
var completedDestination = GetDestinationFilePath(source, completedDestinationPath);
try
{
AppendData(
source,
destination,
line =>
{
var lastEntry = line.Split(';').Last();
return prefixes.Any(prefix => lastEntry.Contains(prefix));
});
File.Move(source, completedDestination);
}
catch (Exception ex)
{
Console.WriteLine($"Issue Moving File: {ex.Message}");
}
}
}
static IEnumerable<string> EnumerateDataFiles(string path)
{
// Change *.dat to the extension (e.g., *.txt) you use for your data files,
// or to *.* to include all files from the directory
return Directory.EnumerateFiles(path, "*.dat", SearchOption.AllDirectories);
}
static string GetDestinationFilePath(string sourceFileName, string destinationPath)
{
// This will return a file path to the file with the same name as the source
// but located in the destination directory
return Path.Combine(destinationPath, Path.GetFileName(sourceFileName));
}
static void AppendData(string source, string destination, Func<string, bool> linePredicate)
{
using (var inputStream = new FileStream(source, FileMode.Open, FileAccess.Read))
using (var inputReader = new StreamReader(inputStream))
using (var outputStream = new FileStream(destination, FileMode.OpenOrCreate, FileAccess.Write))
using (var outputWriter = new StreamWriter(outputStream))
{
while (inputReader.ReadLine() is string inputLine)
{
if (!linePredicate(inputLine))
continue;
outputWriter.WriteLine(inputLine);
}
}
}
In the example provided, I assumed that you have the same file name but different paths for source, destination, and completed destination file paths. If you use a different naming mechanism, please follow comments to adjust it accordingly.

How to create and save an XML file containing complete hierarchy of files and folders for a specified folder?

this is my first post here on the site :)
So basically I need a gui application that can create and save XML file containing complete hierarchy of files and folders for a specified folder.
1.Each folder should be qualified with: Folder name, Folder size (bytes) and Number of files.
2.Each file should be qualified with: File name, File size (bytes), File creation, File last access time, File last modified time.
After the XML file is created the application needs to display the entire folder hierarchy tree (by using the TreeView class).
Can anyone provide help and answer? Thanks!
Try following code. Fully tested. Start with small Directory. Very large folders may take time. I updated code to speed up loading the treeview.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace WindowsFormsApplication29
{
public partial class Form1 : Form
{
XDocument doc = null;
public Form1()
{
InitializeComponent();
folderBrowserDialog1.SelectedPath = #"c:\temp";
}
private void buttonBrowseForFolder_Click(object sender, EventArgs e)
{
folderBrowserDialog1.ShowDialog();
textBoxFolderName.Text = folderBrowserDialog1.SelectedPath;
}
private void buttonCreateXml_Click(object sender, EventArgs e)
{
if(Directory.Exists(textBoxFolderName.Text))
{
string header = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Directory></Directory> ";
doc = XDocument.Parse(header);
XElement root = doc.Root;
CreateXmlRecursive(textBoxFolderName.Text, root);
}
}
private float CreateXmlRecursive(string folder, XElement folderElement)
{
folderElement.SetValue(folder);
DirectoryInfo dInfo = new DirectoryInfo(folder);
int numberOfFiles = 0;
float size = 0.0f;
foreach(FileInfo fInfo in dInfo.GetFiles())
{
try
{
float fSize = fInfo.Length;
size += fSize;
folderElement.Add(new XElement("File", new object[] {
new XAttribute("size",fSize),
new XAttribute("creationDate", fInfo.CreationTime.ToShortDateString()),
new XAttribute("lastAccessDate", fInfo.LastAccessTime.ToShortDateString()),
new XAttribute("lastModifiedDate", fInfo.LastWriteTime.ToShortDateString()),
fInfo.Name
}));
numberOfFiles += 1;
}
catch(Exception e)
{
Console.WriteLine("Error : CAnnot Access File '{0}'", fInfo.Name);
}
}
foreach(string subFolder in Directory.GetDirectories(folder))
{
XElement childDirectory = new XElement("Directory");
folderElement.Add(childDirectory);
float dSize = CreateXmlRecursive(subFolder, childDirectory);
size += dSize;
}
folderElement.Add(new XAttribute[] {
new XAttribute("size", size),
new XAttribute("numberOfFiles", numberOfFiles)
});
return size;
}
private void buttonCreateTree_Click(object sender, EventArgs e)
{
if (doc != null)
{
TreeNode rootNode = new TreeNode(doc.Root.FirstNode.ToString());
AddNode(doc.Root, rootNode);
treeView1.Nodes.Add(rootNode);
treeView1.ExpandAll();
}
}
private void AddNode(XElement xElement, TreeNode inTreeNode)
{
// An element. Display element name + attribute names & values.
foreach (var att in xElement.Attributes())
{
inTreeNode.Text = inTreeNode.Text + " " + att.Name.LocalName + ": " + att.Value;
}
// Add children
foreach (XElement childElement in xElement.Elements())
{
TreeNode tNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(childElement.Value))];
AddNode(childElement, tNode);
}
}
}
}
Your question is - can u do my application for me - but anyway.
I will give you some hints to get started with your Project.
First of all - Check out MVVM here. This will help you - to handle WPF.
1. Pick the starting folder
Then you will need a FolderPicker to start your Search
public static string PickFolder()
{
var dialog = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
string folder = string.Empty;
switch (result)
{
case System.Windows.Forms.DialogResult.OK: return dialog.SelectedPath;
case System.Windows.Forms.DialogResult.Cancel: return string.Empty;
default: return string.Empty;
}
}
U will need the System.Windows.Forms Assembly for this. (Project -> Add reference -> Assembly)
2. folders and files
Then you want to itterate through all folders.
Check out System.IO.Directory here
3. file information
Check out System.IO.File here - this will give you some file data and to get the file size check this out

File Still Locked Despite putting StreamReader in Using

My program goes through all files in a folder, reads them, and without altering their information moves them to another location under a different name. However I cannot use the File.Move method because I get the following IOException:
The process cannot access the file because it is being used by another
process.
This is how I am reading the file and adding all its lines to a List<string>:
List<string> lines = null;
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sr = new StreamReader(fs, Encoding.Default))
{
lines = new List<string>();
while (!sr.EndOfStream)
lines.Add(sr.ReadLine());
}
And this is the function with which I move the file:
public static bool ArchiveFile(string filePath, string archiveFolderLocation)
{
if (!Directory.Exists(archiveFolderLocation))
Directory.CreateDirectory(archiveFolderLocation);
try
{
string timestamp = string.Format("{0:yyyy-MM-dd HHmmss}", DateTime.Now);
string newFileName = Path.GetFileNameWithoutExtension(filePath) + " " + timestamp;
string destination = string.Format("{0}\\{1}{2}", archiveFolderLocation, newFileName, Path.GetExtension(filePath));
File.Move(filePath, destination);
return true;
}
catch (Exception ex)
{
return false;
}
}
I thought using the using statement is supposed to garbage-collect and release the file after being used. How can I release the file so I can move it and why my file stays locked?
Solved:
Got it. Somewhere between these two calls I was opening a TextReaderobject without disposing it.
I thought using the using statement is supposed to garbage-collect and
release the file after being used. How can I release the file so I can
move it and why my file stays locked?
Not really. Using statement is nothing but :
try { var resource = new SomeResource(); }
finally { resource.Dispose(); // which is not GC.Collect(); }
It works fine so it looks like your file is opened from some other place in your code...
P.S.
By the way you can just do:
List<string> lines = File.ReadAllLines().ToList();
You could use:
string dpath = "D:\\Destination\\";
string spath = "D:\\Source";
string[] flist = Directory.GetFiles(spath);
foreach (string item in flist)
{
File.Move(item, dpath + new FileInfo(item).Name);
}
Replace D:\\Source & D:\\Destination\\ with the required source and destination paths, respectively.

Data from newly created .text file is not readable to third party application

I have developed a windows application, which will read updated data from .jrn files(In an ATM Machine) and will be copy the text to a temporary text file "tempfile.txt".
There is another third party application called "POS Text Sender", which reads "tempfile.txt" and display the contents of it in a CCTV Camera.
The problem is that if I type directly something in the tempfile, the POS application will read it, but if my application writes text to "tempfile", I can see the same content as in the .jrn file in tempfile, but it is not reflected in the POS application when ever data is copied from newly generated file to tempfile.if restart the POS Text Sender after the first data copied to tempfile from newly generated file,POS Text sender will display the content til content from newly created file is written to tempfile
My application code is reading .jrn file using StreamReader and assigning it to a string variable and then writing it to a tempfile using StreamWriter. What is the difference between manually typing text on a file and .NET StreamWriter writing text to a file?
CODE:
DateTime LastChecked = DateTime.Now;
try
{
string[] files = System.IO.Directory.GetFiles(#"C:\Test", "*.jrn", System.IO.SearchOption.AllDirectories);
foreach (string file in files)
{
if (!fileList.Contains(file))
{
currentfilename = file;
fileList.Add(file);
copywarehouse(file);
//do_some_processing();
try
{
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(file))
{
currentcontent=sr.ReadToEnd();
// Read and display lines from the file until the end of
//// the file is reached.
//while ((currentcontent = sr.ReadLine()) != null)
//{
//}
sr.Close();
//sr.Dispose();
}
}
catch (Exception)
{
// Let the user know what went wrong.
}
}
}
//checking
try
{
using (StreamReader sr = new StreamReader(currentfilename))
{
string currentfilecontent = sr.ReadToEnd();
sr.Close();
//sr.Dispose();
if (currentfilecontent!=currentcontent)
{
if (currentfilecontent.Contains(currentcontent))
{
string originalcontent = currentfilecontent.Substring(currentcontent.Length);
System.IO.StreamWriter filenew = new System.IO.StreamWriter(#"C:\Test\tempfile.txt");
filenew.WriteLine(originalcontent);
filenew.Close();
currentcontent = currentfilecontent;
}
}
}
}
catch (Exception)
{
// Let the user know what went wrong.
}
copywarehouse method:
private void copywarehouse(string filename)
{
string sourcePath = #"C:\Test";
string targetPath = #"C:\Test";
try
{
string sourceFile = System.IO.Path.Combine(sourcePath, filename);
string destFile = System.IO.Path.Combine(targetPath, "tempfile.txt");
System.IO.File.Copy(sourceFile, destFile, true);
}
catch (Exception)
{
}
}
Can you check the following:
Is the generated file encoding same as the manually created file? (i.e. UTF-8/ANSI).
Are your constantly flushing the streamWriter's buffer? Or set the StreamWriter's AutoFlush property to true.
Is the StreamWriter opened with a WriteLock with no read allowed? In this case the other application may not be able to open your tempfile for read access.
EDIT:
Also, in the code you posted, you are comparing the tempFile data to current data, and if tempFile data is newer than current data, you are appending the temp file, which I think should be vice versa.
Main change:
using (StreamWriter filenew = new StreamWriter(fileDetail.TempFileName, true, Encoding.ASCII))
{
filenew.WriteLine(newContent);
}
To know the correct encoding, just create a new tempFile, write something in the editor and save it. Open the file in notepad and do a "save as". This will display the current encoding in the bottom. Set that encoding in .NET code.
If this does not work try (As recommended by shr):
using (StreamWriter filenew = new StreamWriter(fileDetail.TempFileName, true, Encoding.ASCII))
{
filenew.Write(newContent + "\r\n");
}
Long Version: (It may be a bit different than your code):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DateTime LastChecked = DateTime.Now;
IDictionary<string, FileDetails> fileDetails = new Dictionary<string, FileDetails>(StringComparer.OrdinalIgnoreCase);
IList<string> tempFileList = new List<string>();
try
{
string[] files = System.IO.Directory.GetFiles(#"C:\Test", "*.jrn", System.IO.SearchOption.AllDirectories);
foreach (string file in files)
{
string currentfilename = file;
string currentcontent = string.Empty;
if (!fileDetails.Keys.Contains(file))
{
fileDetails[file] = new FileDetails(copywarehouse(file));
//do_some_processing();
}
try
{
using (StreamReader sr = new StreamReader(file))
{
currentcontent = sr.ReadToEnd();
}
}
catch (Exception)
{
// Let the user know what went wrong.
}
fileDetails[file].AddContent(currentcontent);
}
//TODO: Check using the file modified time. Avoids unnecessary reading of file.
foreach (var fileDetail in fileDetails.Values)
{
//checking
try
{
string tempFileContent = string.Empty;
string currentcontent = fileDetail.GetContent();
using (StreamReader sr = new StreamReader(fileDetail.TempFileName))
{
tempFileContent = sr.ReadToEnd();
sr.Close();
}
if (!(0 == string.Compare(tempFileContent, currentcontent)))
{
if (currentcontent.Contains(tempFileContent))
{
string newContent = tempFileContent.Substring(currentcontent.Length);
using (StreamWriter filenew = new StreamWriter(fileDetail.TempFileName, true, Encoding.ASCII))
{
filenew.WriteLine(newContent);
}
}
}
}
catch (Exception)
{
// Let the user know what went wrong.
}
}
}
catch (Exception)
{
}
}
private static string copywarehouse(string filename)
{
string sourcePath = #"C:\Test";
string targetPath = #"C:\Test";
string sourceFile = System.IO.Path.Combine(sourcePath, filename);
string destFile = System.IO.Path.Combine(targetPath, filename+ "tempfile.txt");
try
{
System.IO.File.Copy(sourceFile, destFile, true);
}
catch (Exception)
{
}
return destFile;
}
internal class FileDetails
{
public string TempFileName { get; private set; }
private StringBuilder _content;
public FileDetails(string tempFileName)
{
TempFileName = tempFileName;
_content = new StringBuilder();
}
public void AddContent(string content)
{
_content.Append(content);
}
public string GetContent()
{
return _content.ToString();
}
}
}
}
EDIT 2:
Can you change the copywarehouse to this and see it the problem persists:
private void copywarehouse(string filename)
{
const string sourcePath = #"C:\Test";
const string targetPath = #"C:\Test";
try
{
string sourceFile = Path.Combine(sourcePath, filename);
string destFile = Path.Combine(targetPath, "tempfile.txt");
string currentcontent;
using (var sr = new StreamReader(sourceFile))
{
currentcontent = sr.ReadToEnd();
}
using (var wr = new StreamWriter(destFile, false, Encoding.ASCII))
{
wr.WriteLine(currentcontent);
}
}
catch (Exception)
{
}
}
Most likely this is a CR+LF issue.
The POS expects the file to have line endings with CR+LF (Carriage Return (0x0D) + New line (0x0A)) combination.
The filenew.WriteLine(originalcontent) appends only the new line character. When you type, I think, you editor must be creating the CR+LF combination for all line endings.
I suggest you try filenew.Write( originalcontent + "\r\n");
One difference is that your application does not write to tempfile.txt directly but to another file and then copies that file to tempfile.txt.

Error in my XML?

I have the following code:
public class DeserializeAndCompare
{
public static List<string> IntoXML()
{
List<string> PopList = new List<string>();
XmlSerializer serializer = new XmlSerializer(PopList.GetType());
string k = FileToolBox.position0;
FileStream filestreamer = new FileStream(k.ToString(), FileMode.Open);
PopList = (List<string>)serializer.Deserialize(filestreamer);
filestreamer.Close();
return PopList;
}
}
I keep hitting an error with the line:
PopList = (List)serializer.Deserialize(filestreamer);
The error: InvalidOperationException was unhandled, There is an error in XML document(1,1).
In this line:
FileStream filestreamer = new FileStream(k, FileMode.open);
I am trying to reference the 0th position of an array that holds strings. I'm basically going thru my directory, finding any files with a .xml extension and holding the filename paths in an array.
Here is the code for my array:
public static class FileToolBox
{
public static string position0;
public static void FileSearch()
{
//string position0;
//array holding XML file names
string[] array1 = Directory.GetFiles(#"s:\project", "*.xml");
Array.Sort(array1);
Array.Reverse(array1);
Console.WriteLine("Files:");
foreach (string fileName in array1)
{
Console.WriteLine(fileName);
}
position0 = array1[0];
}
public static string Position0
{
get
{
return position0;
}
set
{
position0 = value;
}
}
}
Am i missing something here? How do i get rid of this error?
Thanks in advance for the help.
Your XML file is not well formed, use a tool like XML Spy, XML notepad or open it up in IE and it will give you the error and the line it is on. You most likely have invalid characters like & somewhere in the file
That error is specifically indicating that the XML file being read is malformed. You should start by posting your XML. Also, try opening the XML in Firefox, because it may point out the problem with the XML as well.
Your xml document is not well formed, you need to open your xml file up and analyze it.
There are multiple xml validators on the web, but here's one from w3schools.
Give this a shot:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace Util
{
/// <summary>
/// Not to be confused with System.Xml.Serialization.XmlSerializer, which this uses internally.
///
/// This will convert the public fields and properties of any object to and from an XML string,
/// unless they are marked with NonSerialized() and XmlIgnore() attributes.
/// </summary>
public class XMLSerializer
{
public static Byte[] GetByteArrayFromEncoding(Encoding encoding, string xmlString)
{
return encoding.GetBytes(xmlString);
}
public static String SerializeToXML<T>(T objectToSerialize)
{
return SerializeToXML(objectToSerialize, Encoding.UTF8);
}
public static String SerializeToXML<T>(T objectToSerialize, Encoding encoding)
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings =
new XmlWriterSettings { Encoding = encoding, Indent = true };
using (XmlWriter xmlWriter = XmlWriter.Create(sb, settings))
{
if (xmlWriter != null)
{
new XmlSerializer(typeof (T)).Serialize(xmlWriter, objectToSerialize);
}
}
return sb.ToString();
}
public static void DeserializeFromXML<T>(string xmlString, out T deserializedObject) where T : class
{
DeserializeFromXML(xmlString, new UTF8Encoding(), out deserializedObject);
}
public static void DeserializeFromXML<T>(string xmlString, Encoding encoding, out T deserializedObject) where T : class
{
XmlSerializer xs = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(GetByteArrayFromEncoding(encoding, xmlString)))
{
deserializedObject = xs.Deserialize(memoryStream) as T;
}
}
}
}
public static void Main()
{
List<string> PopList = new List<string>{"asdfasdfasdflj", "asdflkjasdflkjasdf", "bljkzxcoiuv", "qweoiuslfj"};
string xmlString = Util.XMLSerializer.SerializeToXML(PopList);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
string fileName = #"C:\temp\test.xml";
xmlDoc.Save(fileName);
string xmlTextFromFile = File.ReadAllText(fileName);
List<string> ListFromFile;
Util.XMLSerializer.DeserializeFromXML(xmlTextFromFile, Encoding.Unicode, out ListFromFile);
foreach(string s in ListFromFile)
{
Console.WriteLine(s);
}
}
Check the output XML file and see what the encoding is, and compare that to what encoding you're trying to read in. I got caught with this problem before because I use a StringBuilder to output the XML string, which writes in UTF-16, but I was trying to read in as UTF-8. Try using Encoding.Unicode and see if that works for you.
Your code will only work with XML files which have the following structure...
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>Hello</string>
<string>World</string>
</ArrayOfString>

Categories