From EXCEL to XSD generated class in C# - 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();
}

Related

C# / AutoCAD .NET API: Read Excel Spread Sheet & Draw Objects based on Data

I am working on a project where I have integrated C# with AutoCAD. What I am going to do is make an AutoCAD command that uses C# (in Visual Studio) to read an Excel Spreadsheet (which is Electrical Engineering data) and then based on the data in the spreadsheet, it will then draw the appropriate graphical object in AutoCAD.
The Spreadsheet: (picture here). The "Service" Column describes the type of equipment we will show on a schematic diagram (drawn in AutoCAD). For example, if the equipment is a compressor, then the program should draw our predefined compressor schematic in AutoCAD, or if the equipment is a VFD pump motor, then the program should draw our predefined VFD schematic in AutoCAD.
In AutoCAD: The schematic diagram is pre-drawn, and the coordinates are easy to work with in the C# code. The difficult part is that I want to read the spreadsheet "section" column and then use this column to instruct the coordinates for placing the graphical schematic objects. For example, if the Section value of the column is 1A, I am trying to place this object at (x= 7.25, y=12, z=0). Then if the section value is 3A, then place the schematic object at its designated x,y,z value. Doing this all while selecting the correct schematic object based on the other "Service" column is a little over my head. I came up with a possible method, but I am gonna have to write a ton of duplicate code and that's why I came here to ask for help.
Problem/My Question: I am not sure about the best way to approach how to use C# to select the correct schematic object from the "Service" column of the spreadsheet, then place the graphical object where is belongs based on its "Section" value of the same spreadsheet. How would I efficiently approach this with writing C#?
So far, I have been able to read the spreadsheet into memory and draw everything in the schematic diagram ("OneLineBackground" in code below) except the equipment objects that need placement on x,y,z grid by section.
I have two C# files: One is "Commands" where I am building basic AutoCAD
commands. The other is "Logic" where I am calling the methods from the "Commands" class.
Here is Logic file:
class Logic
{
#region draw one-line diagram CURRENT DWG
[CommandMethod("ElecOneLine1")]
static public void ElecOneLine1()
{
string Path = Commands.SelectSpreadsheet();
System.Data.DataTable table = Commands.ReadExcelToTable(Path);
Commands.InsertBlocksCurrentDwg();
Commands.DrawOneLineBackgroundCurrentDwg("OneLineBackground", 35.5478, 23.3750, 0, table.Rows[0]);
}
#endregion
Here is the "Commands" class:
public class Commands
{
#region Open File Dialog to load spreadsheet
[CommandMethod("LoadSpreadsheet")]
static public string SelectSpreadsheet()
{
Document doc =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
OpenFileDialog ofd =
new OpenFileDialog(
"Select Excel spreadsheet to link",
null,
"xls; xlsx; xlsm",
"ExcelFileToLink",
OpenFileDialog.OpenFileDialogFlags.DoNotTransferRemoteFiles
);
System.Windows.Forms.DialogResult dr =
ofd.ShowDialog();
if (dr != System.Windows.Forms.DialogResult.OK)
return null;
ed.WriteMessage(
"\nFile selected was \"{0}\".",
ofd.Filename
);
return ofd.Filename;
}
#endregion
#region Read Excel Spreadsheet to Table
public static System.Data.DataTable ReadExcelToTable(string path)
{
string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path + ";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';";
System.Data.DataSet set = new DataSet();
using (OleDbConnection conn = new OleDbConnection(connstring))
{
conn.Open();
System.Data.DataTable sheetsName = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "Table" });
string firstSheetName = sheetsName.Rows[0][2].ToString();
string sql = string.Format("SELECT * FROM [{0}]", firstSheetName);
OleDbDataAdapter ada = new OleDbDataAdapter(sql, connstring);
ada.Fill(set);
conn.Close();
}
return set.Tables[0];
}
#endregion
#region Insert AutoCAD Block Definitions into current dwg from template (.dwt)
[CommandMethod("InsertBlocksCurrentDwg")]
static public void InsertBlocksCurrentDwg()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
using (Database OpenDb = new Database(false, true))
{
OpenDb.ReadDwgFile("C:\\Users\\Ben\\Documents\\CADautomation\\ElecOneLines.dwg",
System.IO.FileShare.ReadWrite, true, "");
ObjectIdCollection ids = new ObjectIdCollection();
using (Transaction tr =
OpenDb.TransactionManager.StartTransaction())
{
//For example, Get the block by name
BlockTable bt;
bt = (BlockTable)tr.GetObject(OpenDb.BlockTableId
, OpenMode.ForRead);
if (bt.Has("OneLineBackground"))
{
ids.Add(bt["OneLineBackground"]);
}
if (bt.Has("vfdPumpMotor"))
{
ids.Add(bt["vfdPumpMotor"]);
}
if (bt.Has("compressor"))
{
ids.Add(bt["compressor"]);
}
tr.Commit();
}
//if found, add the block
if (ids.Count != 0)
{
//get the current drawing database
Database destdb = doc.Database;
IdMapping iMap = new IdMapping();
destdb.WblockCloneObjects(ids, destdb.BlockTableId, iMap, DuplicateRecordCloning.Ignore, false);
}
}
}
#endregion
#region Draw Block in correct coordinates current dwg
[CommandMethod("DrawOneLineBackgroundCurrentDwg")]
static public void DrawOneLineBackgroundCurrentDwg(string name, double x, double y, double z, System.Data.DataRow dr )
{
Database db = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
using (Transaction myT = db.TransactionManager.StartTransaction())
{
//Get the block definition
string blockName = name;
BlockTable bt =
db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
BlockTableRecord blockDef =
bt[blockName].GetObject(OpenMode.ForRead) as BlockTableRecord;
//Also open paper space - we'll be adding our BlockReference to it
BlockTableRecord ps =
bt[BlockTableRecord.PaperSpace].GetObject(OpenMode.ForWrite)
as BlockTableRecord;
//Create new BlockReference, and link it to our block definition
Point3d point = new Point3d(x, y, z);
using (BlockReference blockRef =
new BlockReference(point, blockDef.ObjectId))
{
//Add the block reference to paper space
ps.AppendEntity(blockRef);
myT.AddNewlyCreatedDBObject(blockRef, true);
//Iterate block definition to find all non-constant
// AttributeDefinitions
foreach (ObjectId id in blockDef)
{
DBObject obj = id.GetObject(OpenMode.ForRead);
AttributeDefinition attDef = obj as AttributeDefinition;
if ((attDef != null) && (!attDef.Constant))
{
using (AttributeReference attRef = new AttributeReference())
{
attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
if (attRef.Tag == "ATTTEST1")
{
attRef.TextString = dr.Table.Rows[6][0].ToString();
}
//Add the AttributeReference to the BlockReference
blockRef.AttributeCollection.AppendAttribute(attRef);
myT.AddNewlyCreatedDBObject(attRef, true);
}
}
}
}
//complete db transaction
myT.Commit();
}
}
#endregion
}

to get data from excelfile "*.xlsx" into an array using c#

file path is #"E:\BCFNA-orig-1.xsl"
excel file consists of 9 columns and 500 rows i want to get data from each row into an array int[] NumberOfInputs = {7,4,4,4,2,4,5,5,0}; " the values inside array are supposed to get from excel file , use it in my program and than get data from next row.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.OleDb;
using System.IO;
namespace ConsoleApplication3
{
class Program
{
static void Main()
{
}
public class SomethingSometingExcelClass
{
public void DoSomethingWithExcel(string filePath)
{
List<DataTable> worksheets = ImportExcel(filePath);
foreach(var item in worksheets){
foreach (DataRow row in item.Rows)
{
//add to array
}
}
}
/// <summary>
/// Imports Data from Microsoft Excel File.
/// </summary>
/// <param name="FileName">Filename from which data need to import data
/// <returns>List of DataTables, based on the number of sheets</returns>
private List<DataTable> ImportExcel(string FileName)
{
List<DataTable> _dataTables = new List<DataTable>();
string _ConnectionString = string.Empty;
string _Extension = Path.GetExtension(FileName);
//Checking for the extentions, if XLS connect using Jet OleDB
_ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=E:\\BCFNA-
orig-1.xls;Extended
Properties=Excel 8.0";
DataTable dataTable = null;
using (OleDbConnection oleDbConnection =
new OleDbConnection(string.Format(_ConnectionString, FileName)))
{
oleDbConnection.Open();
//Getting the meta data information.
//This DataTable will return the details of Sheets in the Excel
File.DataTable dbSchema =
oleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables_Info, null);
foreach (DataRow item in dbSchema.Rows)
{
//reading data from excel to Data Table
using (OleDbCommand oleDbCommand = new OleDbCommand())
{
oleDbCommand.Connection = oleDbConnection;
oleDbCommand.CommandText = string.Format("SELECT * FROM
[B1415:J2113]", item["TABLE_NAME"].ToString());
using (OleDbDataAdapter oleDbDataAdapter = new
OleDbDataAdapter())
{
oleDbDataAdapter.SelectCommand = oleDbCommand;
dataTable = new
DataTable(item["TABLE_NAME"].ToString());
oleDbDataAdapter.Fill(dataTable);
_dataTables.Add(dataTable);
}
}
}
}
return _dataTables;
}
}
}
}
//////////////////////////////////////
above is the code which i am using to get data from excel but
///////////////////////////////////////////////////////
below is the nested loop in which i want to use data
/////////////////////////////////////////////////
for (ChromosomeID = 0; ChromosomeID < PopulationSize; ChromosomeID++)
{
Fitness = 0;
Altemp = (int[])AlPopulation[ChromosomeID];
for (int z = 0; z < 500; z++)
{
int[] NumberOfInputs = new int[9];
//// this is the array where in which data need to be added
InputBinary.AddRange(DecBin.Conversion2(NumberOfInputs));
for (i = 0; i < Altemp.Length; i++)
{
AlGenotype[i] = (int)Altemp[i];
}
Class1 ClsMn = new Class1();
AlActiveGenes = ClsMn.ListofActiveNodes(AlGenotype);
ClsNetworkProcess ClsNWProcess = new
ClsNetworkProcess();
AlOutputs = ClsNWProcess.NetWorkProcess(InputBinary,
AlGenotype, AlActiveGenes);
int value = 0;
for (i = 0; i < AlOutputs.Count; ++i)
{
value ^= (int)AlOutputs[i]; // xor the
output of the system
}
temp = Desired_Output[0];
if (value == temp) // compare system Output with
DesiredOutput bit by bit
Fitness++;
else
Fitness = Fitness;
}
AlFitness.Add(Fitness);
}
}
Zahra, no one on here that is answering questions is paid to answer them. We answer because others have helped us so we want to give back. Your attitude of "want a complete code with all reference assemblies used" seems rather demanding.
Having said that. xlsx is a proprietary format. You will need a tool like ExcelLibrary to be able to do this. Even though this answer is more related to writing to xlsx it should still give you some more options: https://stackoverflow.com/a/2603625/550975
I would suggest to use my tool Npoi.Mapper, which is based on popular library NPOI. You can import and export with POCO types directly with convention based mapping, or explicit mapping.
Get objects from Excel (XLS or XLSX)
var mapper = new Mapper("Book1.xlsx");
var objs1 = mapper.Take<SampleClass>("sheet2");
// You can take objects from the same sheet with different type.
var objs2 = mapper.Take<AnotherClass>("sheet2");
Export objects
//var objects = ...
var mapper = new Mapper();
mapper.Save("test.xlsx", objects, "newSheet", overwrite: false);

how to convert csv file to xml file in c# by columns

right now I have csv file in there it contains Worker, Account Id, Account Code, Hierarchy, and Date column. how do I write c# code to convert csv file to xml file?
select new XElement("Worker",
new XElement("Account Id", columns[0]),
new XElement("Account Code", columns[1]),
new XElement("Hierarchy", columns[2]),
new XElement("Date", columns[3]),
For now I have code something like that, how can I make improve on that code?
Perhaps you could ensure the column names are the same by doing something like:
new XElement(columns[0].Key, columns[0].value)
That way you wouldn't have to continually type in every single column name, and could just use a foreach(..) block to generate it instead.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.OleDb;
using System.IO;
namespace ConsoleApplication55
{
class Program
{
const string csvFILENAME = #"c:\temp\test.csv";
const string xmlFILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
CSVReader reader = new CSVReader();
DataSet ds = reader.ReadCSVFile(csvFILENAME, true);
ds.WriteXml(xmlFILENAME, XmlWriteMode.WriteSchema);
}
}
public class CSVReader
{
public DataSet ReadCSVFile(string fullPath, bool headerRow)
{
string path = fullPath.Substring(0, fullPath.LastIndexOf("\\") + 1);
string filename = fullPath.Substring(fullPath.LastIndexOf("\\") + 1);
DataSet ds = new DataSet();
try
{
if (File.Exists(fullPath))
{
string ConStr = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}" + ";Extended Properties=\"Text;HDR={1};FMT=Delimited\\\"", path, headerRow ? "Yes" : "No");
string SQL = string.Format("SELECT * FROM {0}", filename);
OleDbDataAdapter adapter = new OleDbDataAdapter(SQL, ConStr);
adapter.Fill(ds, "TextFile");
ds.Tables[0].TableName = "Table1";
}
foreach (DataColumn col in ds.Tables["Table1"].Columns)
{
col.ColumnName = col.ColumnName.Replace(" ", "_");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return ds;
}
}
}
Well there's a class from MSDN called XmlCsvReader You only have to specify your filepath where the csv document is located. Then you specify your root's name which is Worker and it'll take care of the rest when it's loaded. The only thing that needs to be done is to specify where you want to output it using the Save method!
XmlDocument doc = new XmlDocument();
XmlCsvReader reader = new XmlCsvReader(new Uri("//yourfilepath.input.csv"), doc.NameTable);
reader.FirstRowHasColumnNames = true;
reader.RootName = "Worker";
reader.RowName = "Worker";
doc.Load(reader);
doc.Save("output.xml");

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