X++ SysExcelWorkbook.saveAs - change encoding - excel

I'm trying to convert XLS to CSV using job in AX2012. I have some non-ASCII characters in my XLS and I need to find out how can I set SysExcelWorkbook.saveAs method to use specific encoding (eg. UTF-8).
static void ExcelToCsv(Args _args)
{
SysExcelApplication application;
SysExcelWorkbooks workbooks;
SysExcelWorkbook workbook;
FileName xlsFile, csvFile;
;
application = SysExcelApplication::construct();
application.displayAlerts(false);
workbooks = application.workbooks();
xlsFile = #"C:\test.xlsx";
csvFile = #"C:\result.csv";
workbooks.open(xlsFile);
workbook = workbooks.item(1);
workbook.saveAs(csvFile, 6);
// workbook.saveAs(resFile, 22);
// workbook.saveAs(resFile, 23);
// workbook.saveAs(resFile, 24);
application.quit();
}
The code above generates CSV, but all non-ASCII characters are not displaying property when opening in text editor. I expect that I will be able to choose encoding for my CSV file programmatically or use source (XSL) encoding. Is there a way to achieve this with X++?

I don't think you can do this without some workarounds as it appears to be an Excel limitation. It's do-able though if you really need it.
It uses the Excel COM object to do the work, and you can see the reference here, where I can't find any options to specify encoding:
https://learn.microsoft.com/en-us/office/vba/api/excel.workbook.saveas
Here is the same issue, albeit in Powershell instead of X++ with solution (I think) being to export to UnicodeText instead of CSV, then replacing \t with , in the output file.
It looks like you could output to UnicodeText by making the below change to your code, then you could just use some other string-replace to update the final file.
#Excel
// workbook.saveAs(csvFile, 6); // 6 == #xlCSV
workbook.saveAs(csvFile, #xlUnicodeText);
I'm not sure if this truly fixes your encoding issue without testing. I'd also want to double-check how single/double quotes are handled.

Related

StreamWriter trouble writing doubles to .txt file (C++)

I'm trying to write some double values to a text file the user creates via a SaveFileDialog, but everytime I do a streamWriterVariable->Write(someDoubleVariable), I instead see some kind of weird ASCII character in the text file where the double should be (music note, |, copyright symbol, etc). I'm opening the file with notepad if it's that of any significance. A basic outline of my code:
SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog;
saveFileDialog1->Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1->Title = "Save File Here";
saveFileDialog1->RestoreDirectory = true;
if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )
{
FileInfo ^fleTest = gcnew FileInfo(saveFileDialog1->FileName);
StreamWriter ^sWriter = fleTest->CreateText();
sWriter->AutoFlush = true;
double test = 5.635; //Some arbitrary double I made up for test purposes
sWriter->Write(test);
sWriter->Flush();
sWriter->Close();
}
Thanks for your help!
Have you tried to set the encoding explicitly?
StreamWriter^ sWriter = gcnew StreamWriter(saveFileDialog1->FileName, false, System::Text::Encoding::ASCII);
The code you've provided does exactly what you ask it to, that is to write a double to the file in the internal computer format. What you most likely want it to write out the textual representation of the double.
In other words you should try sWriter->Write(test.ToString()) or some variation over this, to get the textual version of your double. This also applies to bool and most other variable representation.

Export Excel : Avoid stripping the leading zeros

I am Export a data to Excel Sheet in C#.Net. There i am having column which has the data like "00123450098". The data is exported without the first zero's. I want to show the data as it is.
Here is my export excel code.
string style = #"<style> .text { mso-number-format:\#; } </style> ";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader(
"content-disposition", string.Format("attachment; filename={0}", fileName));
HttpContext.Current.Response.ContentType = "application/ms-excel";
HtmlForm frm = new HtmlForm();
...................
...................
table.RenderControl(htw);
HttpContext.Current.Response.Write(style);
//render the htmlwriter into the response
HttpContext.Current.Response.Write(sw.ToString());
HttpContext.Current.Response.End();
While exporting to excel, adding \t before the value being inserted will solve the problem.
Eg:
string test = "000456";
string insertValueAs = "\t" + test;
The string test would then be considered as a string value and not an integer value. Thus, it would retain the leading zeros.
I have faced the same issue, and above solution worked for me. Hope this post helps!
If exporting to CSV / TSV, put this into each cell containing a textual "number" with leading 0s or (especially) 16+ digits:
="0012345"
..where 0012345 is the number you want to export to that cell.
I wish I could remember where I saw that.
In Excel file, Numbers cell always strips the leading zeros, you can set numbers with leading zeros by following a single quote. i.e.
00123450098 to '00123450098
but then, the format for that cell will changes to text.
If your generated excel file, have any formula, which is include that cell reference as number then it will not work as expected.
I had this problem as well. The solution I came up with was to sneak the leading zeros in using excel's built in char() function. In excel, char() returns the value of the ASCII character code that is passed to it, so char(048) returns 0.
Before exporting to excel, prepend your variable like so...
varName = "=CHAR(048)&" + varName;
I found my answer for this using a combination of StackOverflow link and a blog.
There are excel formatting styles that can be applied to the gridview on rowdatabound. I used those and now my export does not strip the leading zeros.
Below is an example of my code.
ExpenseResultsGrid.RowDataBound += new GridViewRowEventHandler(ExpenseResultsGrid_RowDataBound);
protected void AllQuartersGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{//add this style to prevent truncating leading zeros in fund code during export to excel
e.Row.Cells[2].Attributes.CssStyle.Add("mso-number-format", "\\#");
}
}
While exporting, just add an empty string like "" before the value that is inserted:
string x = "000123";
myWorksheet.Cells[1,1] = "" + x;

How can I programatically convert .xls and .csv files to .xlsx?

Is there a programmatic solution to this that does not involve having Office on the server?
Update:
This solution will be deployed in a .Net shop, so for now PHP and Java approaches aren't on the table (though I was impressed with the libraries themselves).
We will be receiving documents in csv, .xls, and .xlsx formats that need to be parsed and their data shoved into a DB. We're planning on using the OpenXML SDK for all of the parsing goodness and want to operate over only one file type.
You can achieve this using the Apache POI library for Java.
HSSF is the POI Project's pure Java implementation of the Excel '97(-2007) file format.
XSSF is the POI Project's pure Java implementation of the Excel 2007 OOXML (.xlsx) file format.
I've used it to read in a complete mix of .xls and .xlsx files, and I always output .xlsx.
For .csv files, import using the Super CSV library and export using the Apache POI library above.
The main motivation for Super Csv is to be the best, fastest and most programmer friendly free CSV package for Java.
Or use PHPExcel ( http://www.phpexcel.net ) if you want a PHP solution rather than java
For csv files i would recommend a combination of http://kbcsv.codeplex.com/ to read the csv file into a datatable and EPPPLUS to use its .FromDataTable Method to convert it to an xlsx file.
I works great for me and is very fast.
For reading xls files there is no free Implementation that I know of :(
and you can use for parse columns.
object columnValue = ws.Cells[i, ColIndex, i, ColIndex].Value; // get Specific cell.
you can use below method for .csv, xlsx, .txt files.
public yourReturnType compute()
{
#region .XLSX Section
if (FilePath.FullName.Contains(".xlsx") || FilePath.FullName.Contains(".xls"))
{
// Open and read the XlSX file.
using (var package = new ExcelPackage(FilePath))
{
ExcelWorkbook wb = package.Workbook; // Get the work book in the file
if (wb != null)
{
if (wb.Worksheets.Count > 0)
{
ExcelWorksheet ws = wb.Worksheets.First(); // Get the first worksheet
yourParseCode(ws);
}
} // if End.
} // using end.
}
#endregion
#region .CSV Section
if (FilePath.FullName.Contains(".csv") || FilePath.FullName.Contains(".txt"))
{
CSVParser c = new CSVParser(FilePath);
DataTable dt = c.ReadCSVFile();
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("temporary");
ws.Cells["A1"].LoadFromDataTable(dt, true);
yourParseCode (ws);
////pck.Save(); // no need to save this temporary sheet.
}
}
#endregion
return (yourReturnType );
}

vba code for excel - to encoding gibberish to hebrew

i have files that open with excel.
when i open the file the text is like gibberish.
i need to encode - tools-internet option - general-encode - hebrew iso-visual
and then the file turn to hebrew
there is a vba code that do that ?
thanks,
omri
I don't really have a way to test this, so I am just taking a shot:
Excel.ActiveWorkbook.WebOptions.Encoding = msoEncodingHebrew
Use the following function from ADODB Stream, with the following code.
Page 1255 is the original Hebrew page.
And you need to reference the latest Microsoft ActiveX Data Objects Library.
(Tools/References)
Public Function CorrectHebrew(gibberish As String) As String
Dim inStream As ADODB.stream
Set inStream = New ADODB.stream
inStream.Open
inStream.Charset = "WIndows-1255"
inStream.WriteText gibberish
inStream.Position = 0 ' bring it back to start preparing for the ReadText
inStream.Charset = "UTF-8"
CorrectHebrew = inStream.ReadText ' return the corrected text
inStream.Close
End Function

How to work around the [1] IE bug while saving an excel file from a Web server?

I've noticed that Internet Explorer adds a number in square brackets to files downloaded from the internet (usually [1]). This creates a big problem with downloading Excel spreadsheets as square brackets are not a valid filename character inside Excel worksheet name. That problem is IE specific, others browsers are keeping same file name.
So, if you have a pivot table auto-refreshed on file opening for example, you'll get an error message saying the name "file[1].yourPivotTableName" is not valid.
Is there any solution to that problem ?
EDIT : It seems that whatever the filename suggested by HTTP directives, IE adds [1] in all cases, which cause the problem ! (So, answers about filenames aren't helpful in that case)
EDIT : I've tried some VBA code to save file under another name when it'll open. However, it doesn't work (same error message than before). Do you think there's a way to fix that with VBA ?
I've got it working using VBA provided by this cool guy (think of him fondly).
It renames the file and then reattaches the pivots.
http://php.kennedydatasolutions.com/blog/2008/02/05/internet-explorer-breaks-excel-pivot-tables/
I think that this happens when you open the spreadsheet in IE and IE saves it to a temporary file. And I think it only happens when the spreadsheet's filename has more than one dot in it. Try it with a simple "sample.xls".
Another workaround is to tell users to save the file to the desktop and then open it.
It's a built-in feature in Internet Explorer.
Stop using "Open", start using "Save" in the file-download window, otherwise IE will append "[1]" to filename of the file that it places in some temporary folder.
You could build some .NET application using System.IO.FileSystemWatcher that catches the event of the creation of the downloaded file or something and renames the file.
I have solved this issue by using method where we pass 3 parameters: Filename, file extension(without the .dot) and the HTTP request); then doing the UTF-8 encoding of the filename and extension.
Sample Code:
public static String encoding(String fileName, String extension, HttpServletRequest request)
{
String user = request.getHeader( "user-agent" );
boolean isInternetExplorer = ( user.indexOf( "MSIE" ) > -1 );
String var = "";
try
{
fileName = URLEncoder.encode( fileName, "UTF-8" );
fileName = fileName.trim().replaceAll( "\\+", " " );
extension = URLEncoder.encode( extension, "UTF-8" );
extension = extension.trim().replaceAll( "\\+", " " );
if ( isInternetExplorer )
{
disposition = "attachment; filename=\"" + fileName+"."+extension+"\"";
}
else
{
var = "attachment; filename*=UTF-8''" + fileName+"."+extension;
}
}
catch ( UnsupportedEncodingException ence )
{
var = "attachment; filename=\"" + fileName+"."+extension;
ence.printStackTrace();
}
return var;
}
This worked just fine in my case.
Hope it will help you all.
Actually, the correct .NET-code is as following:
Response.AppendHeader("content-disposition", "attachment;filename=file.xls");
Response.ContentType = "application/vnd.ms-excel";
Note: AppendHeader, not AddHeader, which I think only works in debug web-server and IIS7.
The following has worked for me:
private string EncodeFileName(string fileName)
{
fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", " ");
if (HttpContext.Current.Request.UserAgent.ToLower().Contains("msie"))
{
var res = new StringBuilder();
var chArr = fileName.ToCharArray();
for (var j = 0; j < chArr.Length; j++)
{
if (chArr[j] == '.' && j != fileName.LastIndexOf("."))
res.Append("%2E");
else
res.Append(chArr[j]);
}
fileName = res.ToString();
}
return "\"" + fileName + "\"";
}
You could just make sure that in the options box for the pivot the auto refresh is switched off. Now even when opened from the server the pivot will work perfectly
I have encountered the same problem and came up with (imo) a better solution that does not need any VBA.
If you set "Content-Disposition" header to "attachment; filename=<...>" instead of "inline; filename=<...>" the normal browsers will open dialog that will allow to save or open a file with a filename defined in a header, but Internet Explorer will behave in kind of weird way. It will open file download dialog and if you press Save it will suggest a filename that is defined in the header, but if you press Open it will save file to a temporary folder and open it with a name that is the same as your URN (without 'namespace'), e.g. if your URI is http://server/folder/file.html, so IE will save your file as file.html (no brackets, woo hoo!). This leads us to a solution:
Write a script that handles request from http://server/folder/* and when you need to serve an XLS file just redirect to that script (use your filename instead of asterisk) with Content-Disposition set to inline.
Put these four lines in your code:
response.reset();
response.setHeader("Expires", "0");
response.setHeader("Cache-Control","must-revalidate,post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
Hope this helps.
In .NET I have found from experience only this seems to work for me:
Response.AddHeader("Content-Disposition", "attachment; filename=excel.xls");
Response.AddHeader("Content-Type", "application/vnd.ms-excel");
Response.ContentType = "application/vnd.ms-excel";
The duplication smells, but so far I have never got to the bottom of it (maybe Sebs post explains this). Also the "content-Disposition" value appears very finicky use a : instead of a ; or ommit the space between it and 'filename' and it blows!
Also if you have compression enabled on IIS this may fix things for you:
Response.ClearHeaders()

Resources