StreamWriter along with XmlSerializer in DotNet6 does not write WhiteSpaces? - c#

Actually I tried this basic code in C# which serializes the DataSet into XML document.
static void Main(string[] args)
{
XmlSerializer ser = new XmlSerializer(typeof(DataSet));
// Creates a DataSet; adds a table, column, and ten rows.
DataSet ds = new DataSet("myDataSet");
DataTable t = new DataTable("table1");
DataColumn c = new DataColumn("thing");
t.Columns.Add(c);
ds.Tables.Add(t);
DataRow r;
for (int i = 0; i < 10; i++)
{
r = t.NewRow();
r[0] = "Thing " + i;
t.Rows.Add(r);
}
StreamWriter writer = new StreamWriter("DemoNet5.xml");
ser.Serialize(writer, ds);
writer.Close();
}
And this creates the "DemoNet5.xml" file with proper WhiteSpaces and Indentation in .NET 5. But When I try to run the same code in .NET 6
I am not getting the WhiteSapces and Indentation so that the contents of the xml are written in single line.
Later on when I try to read that .xml document I face issues.
Is there someone who can help me with this ? I want my xml contents to be in proper format that is with proper indetation and WhiteSpaces.
Xml file created using .NET6
I have also attached the XML document created using DotNet6.

Related

Can multiple zip file entries be active using ZipOutputStream class?

I am trying to use DotNetZip open source library for creating large zip files.
I need to be able to write to each stream writer part of the data row content (see the code below) of the data table. Other limitation I have is that I can't do this in memory due to the contents being large (several giga bytes each entry).
The problem I have is that despite writing to each stream separately, the output is all written to the last entry only. The first entry contains blank. Does anybody have any idea on how to fix this issue?
static void Main(string fileName)
{
var dt = CreateDataTable();
var streamWriters = new StreamWriter[2];
using (var zipOutputStream = new ZipOutputStream(File.Create(fileName)))
{
for (var i = 0; i < 2; i++)
{
var entryName = "file" + i + ".txt";
zipOutputStream.PutNextEntry(entryName);
streamWriters[i] = new StreamWriter(zipOutputStream, Encoding.UTF8);
}
WriteContents(streamWriters[0], streamWriters[1], dt);
zipOutputStream.Close();
}
}
private DataTable CreateDataTable()
{
var dt = new DataTable();
dt.Columns.AddRange(new DataColumn[] { new DataColumn("col1"), new DataColumn("col2"), new DataColumn("col3"), new DataColumn("col4") });
for (int i = 0; i < 100000; i++)
{
var row = dt.NewRow();
for (int j = 0; j < 4; j++)
{
row[j] = j * 1;
}
dt.Rows.Add(row);
}
return dt;
}
private void WriteContents(StreamWriter writer1, StreamWriter writer2, DataTable dt)
{
foreach (DataRow dataRow in dt.Rows)
{
writer1.WriteLine(dataRow[0] + ", " + dataRow[1]);
writer2.WriteLine(dataRow[2] + ", " + dataRow[3]);
}
}
Expected Results:
Both file0.txt and file1.txt need to written.
Actual results:
Only file1.txt file is written all content. file0.txt is blank.
It seems to be the expected behaviour according to the docs
If you don't call Write() between two calls to PutNextEntry(), the first entry is inserted into the zip file as a file of zero size. This may be what you want.
So to me it seems that it is not possible to do what you want through the current API.
Also, as zip file is a continuous sequence of zip entries, it is probably physically impossible to create entries in parallel, as you would have to know the size of each entry before starting a new one.
Perhaps you could just create separate archives and then combine them (if I am not mistaken there was a simple API to do that)

From EXCEL to XSD generated class in C#

I have this situation, I have been provided with an XSD schema consisting of four XSD files which I was able to convert to a class using the XSD.exe tool and include it in my project, for this example this class is named "Test_XSD". On the other side I have a populated excel sheet table consisting of 10 columns which I need to map to certain elements in the "Text XSD". The "Test_XSD" schema is complex however if I map the 10 columns to their relevant elements is sufficient since many other elements are not mandatory. I have searched and searched but cannot find a simple example to start building on it.
I am able to read the excel file in Visual Studio and convert to XML, however this does not conform with the XSD generated class. I know that I have to create an instance of the "Test_XSD" and load it with the data from the Excel but I don't have any clue from where to start. Can someone explain what needs to be done.
This is what I've done so far, not too much I admit but this is something totally new for me and to be honest I didn't have yet understood the way forward although I've researched a lot.
static void Main(string[] args)
{
// Using an OleDbConnection to connect to excel
var cs = $#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={#"C:\AAAA\Report.xlsx"};Extended Properties=""Excel 12.0 Xml; HDR = Yes; IMEX = 2"";Persist Security Info=False";
var con = new OleDbConnection(cs);
con.Open();
// Using OleDbCommand to read data of the sheet(sheetName)
var cmd = new OleDbCommand($"select * from [Sheet1$]", con);
var ds = new DataSet();
var da = new OleDbDataAdapter(cmd);
da.Fill(ds);
//// Convert DataSet to Xml
//using (var fs = new FileStream(#"C:\Users\MT2362\Downloads\CRS_XML.xml", FileMode.CreateNew))
//{
// using (var xw = new XmlTextWriter(fs, Encoding.UTF8))
// {
// ds.WriteXml(xw);
// }
//}
XSD xsd = new XSD();
xsd.version = "TEST VERSION";
Console.WriteLine(xsd.version);
Console.ReadKey();
}
I've noted taht the class generated from the XSD ("Test_XSD") is composed of multiple partial class, hence I think that an instance for each class must be created.
Thanks in advance, code snippets are highly appreciated.
The object of your XSD class would have public properties. If you set the value of these properties (similar to your .version in your example), then your object is fully populated.
Is this what you want ?
After running the XSD.exe tool, the output would be a list of C# classes that would be available to you.
Since you were able to successfully read from the Excel file and create and XML file for the dataset.
Perform the following:
Add a new class to your project as follows:
public class ExcelNameSpaceXmlTextReader : XmlTextReader
{
public ExcelNameSpaceXmlTextReader(System.IO.TextReader reader)
: base(reader) { }
public override string NamespaceURI
{
get { return ""; }
}
}
Then in a separate Utitlity class add a deserializer function as follows
public class Utility
{
public T FromXml<T>(String xml)
{
T returnedXmlClass = default(T);
using (TextReader reader = new StringReader(xml))
{
returnedXmlClass = (T)new XmlSerializer(typeof(T)).Deserialize(new ExcelNameSpaceXmlTextReader(reader));
}
return returnedXmlClass;
}
}
Now add code to consume the read in data from XML as the object you want to serialize the data to by consuming the generic Utility function
So your code would be like
static void Main(string[] args)
{
// Using an OleDbConnection to connect to excel
var cs = $#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={#"C:\AAAA\Report.xlsx"};Extended Properties=""Excel 12.0 Xml; HDR = Yes; IMEX = 2"";Persist Security Info=False";
var con = new OleDbConnection(cs);
con.Open();
// Using OleDbCommand to read data of the sheet(sheetName)
var cmd = new OleDbCommand($"select * from [Sheet1$]", con);
var ds = new DataSet();
var da = new OleDbDataAdapter(cmd);
da.Fill(ds);
// Convert DataSet to Xml
using (var fs = new FileStream(#"C:\Users\MT2362\Downloads\CRS_XML.xml", FileMode.CreateNew))
{
using (var xw = new XmlTextWriter(fs, Encoding.UTF8))
{
ds.WriteXml(xw);
}
}
XDocument doc = XDocument.Load("C:\Users\MT2362\Downloads\CRS_XML.xml");
Test_XSD test_XSD = Utility.FromXml<Test_XSD>(doc.Document.ToString());
XSD xsd = new XSD();
xsd.version = "TEST VERSION";
Console.WriteLine(xsd.version);
Console.ReadKey();
}

C# Pass multiple parameters into XML using Queue

I have a webservice that obtains data from Oracle CRM OnDemand. I want to create another WS that takes the fields for a given customer record and passes those fields as parameters into an XML writer which then creates the XML to be passed to another webservice (being developed by another team).
I can create the XML fine and pass the parameters. However, I am only testing 3-4 fields and passing them. I will need way more than 4 parameters to be passed, and I know this is pretty poor programming to create a function that takes 3+ parameters. (EDIT) I have created a queue that takes in the parameters from the page, and I pass just the queue. I want to dequeue the data field followed by a string of what I want to pass into the XML page.
This is what I have right now.
...for (int intIndx = 0; intIndx < intCount; intIndx++)
{
//Create queue to store all the data obtained from a given Account
Queue<string> q = new Queue<string>();
//Easier to reference
var acctName= objAcctQryOut.ListOfAccount[intIndx].AccountName;
var acctWebsite = objAcctQryOut.ListOfAccount[intIndx].WebSite;
q.Enqueue(acctName);
addyInsert.CountryCode = objAcctQryOut.ListOfAccount[intIndx].PrimaryBillToCountry;
q.Enqueue(addyInsert.CountryCode);
addyInsert.Line1 = objAcctQryOut.ListOfAccount[intIndx].PrimaryBillToStreetAddress;
q.Enqueue(addyInsert.Line1);
addyInsert.Line2 = accountInfo.PrimaryBillToStreetAddress2;
q.Enqueue(addyInsert.Line2);
addyInsert.Line3 = accountInfo.PrimaryBillToStreetAddress3;
q.Enqueue(addyInsert.Line3);
addyInsert.City = objAcctQryOut.ListOfAccount[intIndx].PrimaryBillToCity;
q.Enqueue(addyInsert.City);
addyInsert.CountyCodeVertex = accountInfo.PrimaryBillToCounty;
q.Enqueue(addyInsert.CountyCodeVertex);
addyInsert.StateProvinceCodeVertex = accountInfo.PrimaryBillToState;
q.Enqueue(addyInsert.StateProvinceCodeVertex);even know?
custResponse.CustomerNumber = accountInfo.FuriganaName;
q.Enqueue(custResponse.CustomerNumber);
custInput.BillingCurrency = accountInfo.CurrencyCode;
q.Enqueue(custInput.BillingCurrency);
custInput.Email = accountInfo.CustomText1;
q.Enqueue(custInput.Email);
custInput.TravelPortCustomerTypeCode = accountInfo.AccountType;
q.Enqueue(custInput.TravelPortCustomerTypeCode);
var count = q.Count;
var xml = new XML();
xml.sendAccountInfoXML(q);
//xml.sendAccountInfoXML(acctName, addyInsert.CountryCode, addyInsert.Line1, addyInsert.Line2, addyInsert.Line3, acctWebsite);
}
private void createXML(Queue<string> q)
{
string saveLoc = #"C:\Users\XML Test\test{0}.xml";
XmlTextWriter writer = new XmlTextWriter(saveLoc, System.Text.Encoding.UTF8);
XmlDocument doc = new XmlDocument();
writer.WriteStartDocument(true);
writer.Formatting = Formatting.Indented;
writer.Indentation = 2;
writer.WriteStartElement("HEADER");
createNode(q, writer);
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
doc.Save(writer);
}
private void createNode(Queue<string> q, XmlWriter writer)
{
Queue<string> x = new Queue<string>();
x.Enqueue("ACCOUNTNAME");
x.Enqueue("BILLINGCOUNTRY");
x.Enqueue("BILLINGLINE1");
x.Enqueue("BILLINGLINE2");
x.Enqueue("BILLINGLINE3");
x.Enqueue("BILLINGCITY");
x.Enqueue("BILLINGCOUNTY");
x.Enqueue("BILLINGSTATE");
x.Enqueue("CUSTOMERNUMBER");
x.Enqueue("BILLINGCURRENCY");
x.Enqueue("CUSTOMEREMAIL");
x.Enqueue("CUSTOMERTYPE");
//x.Enqueue("CUSTOMURL");
writer.WriteStartElement("ACCOUNTINFO");
for (int i = 0; i < x.Count; i++)
{
writer.WriteStartElement(x.Dequeue());
for (int j = 0; j < q.Count; j++)
{
writer.WriteString(q.Dequeue());
writer.WriteEndElement();
}
}
writer.WriteEndElement();
}
However, I feel that the nested loops are not properly functioning. Would you mind trying to guide me through it and point out where I'm messing up? Thank you.

Reading XML with Schema XSD

I have a problem with the reading an xml, that was created saving the same schema that i used to read.
When I read a DataTable, for example Person, that has one row, the DataTable read the row but show me like all columns where null, when all columns are not null.
The code I use is the following
private DataSet LoadShema(string path)
{
string _archivoXsd = System.AppDomain.CurrentDomain.BaseDirectory +"Scheme.xsd";//HERE IS WHERE THE .XSD FILE IS
DataSet esquemaXSD = new DataSet();
string archivoXml = path;
FileStream FsXSD = new FileStream(_archivoXsd, FileMode.Open);
FileStream FsXML = new FileStream(archivoXml, FileMode.Open);
XmlTextReader xtrXSD = new XmlTextReader(FsXSD);
try
{
esquemaXSD.ReadXmlSchema(xtrXSD);
xtrXSD.Close();
FsXSD.Close();
XmlTextReader xtrXML = new XmlTextReader(FsXML);
esquemaXSD.ReadXml(xtrXML);
xtrXML.Close();
FsXML.Close();
}
catch
{
}
return esquemaXSD;
}
This is how I load the xml in the scheme, then another thing I do is assigning:
_dtPerson = new DataTable();
_dtPerson = esquemaXSD.Tables["Person"];
and for last, what I do is the following:
if (_dtPerson.Rows.Count == 1)
{
string name = Convert.ToString(_dtPerson.Rows[0]["Name"]);
}
and when i do the last code line, an exception that said "Can not convert DBNull object to other types".

Read in xls file as well as current csv file in app

I have the following code -
private void button1_Click(object sender, EventArgs e)
{
string csv = File.ReadAllText("FilePath");
WebService.function res = new WebService.function();
XDocument doc = ConvertCsvToXML(csv, new[] { "," });
I was wondering how a could adjust the code so that it not only reads .csv files but also .xls files?
I created a public XDocument to do this -
public XDocument ConvertCsvToXML(string csvString, string[] separatorField)
{
var sep = new[] { "\n" };
string[] rows = csvString.Split(sep, StringSplitOptions.RemoveEmptyEntries);
var xsurvey = new XDocument(
new XDeclaration("1.0", "UTF-8", "yes"));
var xroot = new XElement("details");
If I understand your question correctly, you are looking to parse an excel file as text in the same manner that you parse the csv file. While this is possible, you should consider using Office Interop interfaces to do this. If you want to parse the raw file you'll need to account for the different formats between Office versions and a whole slew of encoding/serialization tasks; no small task.
Here are some resources to get you started:
Reading Excel from C#
How to Automate Excel from C#
I'm not sure from your question...but if you are asking how to read an excel file in c#, this will work:
string fileName = [insert path and name];
string connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;data source={0}; Extended Properties=Excel 8.0;", fileName); // Create the data adapter pointing to the spreadsheet
var oa = new OleDbDataAdapter("SELECT * FROM [xxx$]", connectionString); // xxx is tab name
// Create a blank data set
var ds = new DataSet(); // Fill the data set using the adapter
oa.Fill(ds, "table1"); // Create a data table from the data set
DataTable dt1 = ds.Tables["table1"];
foreach (DataRow dr in dt1.Rows)
{
...
}

Categories