OpenXML 将值写入字符串,当转换为数字时,值会发生变化
OpenXML Writes Values as String and When Converted to Numbers the Values Change
我正在使用 OpenXML 将一些数据写入 Excel。我已经成功地将所有数据输入到电子表格中,但是当我这样做时,所有数据都是字符串格式。这是因为我主要使用 MSDN 上可用的示例代码,它们将数据插入 Excel 作为 InsertSharedStringItem
(A string
)。然而,我确实找到了两种将单元格转换为数字的方法。
第一个是简单的 CellValues.Number
而不是 CellValues.SharedString
但这似乎改变了单元格中的所有实际值并将它们更改为数字。一个例子是我在一列中有 0,现在它是 5,11 现在是 0,21 是 33,诸如此类的奇怪东西(如果数字像 0 一样重复,它们都会变成,在 0 的情况下,5)。显然那是行不通的。
然后我在 Excel 中找到了另一种将字符串转换为数字的方法,并找到了 here(如果您单击该答案中的 link 转到该用户来源,您需要将 'www.' 添加到 URL)。这个解决方案的问题是它会将所有字符串转换为双精度,但值与第一个解决方案相同,这次只是采用双精度格式。
还值得注意的是,我的第三列应该是一个字符串,不需要转换为数字,但无论如何它都会转换。
这就是我正在使用的:
private static void WriteToExcel(string[] contents, char[] desiredColumns)
{
string filePath = @"D:\Folder\test.xlsx";
try
{
using (SpreadsheetDocument StatsCollection = SpreadsheetDocument.Open(filePath, true))
{
string sheetName = "";
int totalRows = contents.Length / 15;
int contentsIndex = 0;
for (uint indexRow = 1; indexRow < totalRows; indexRow++)
{
for (int indexCol = 1; indexCol < 16; indexCol++)
{
sheetName = "Sheet1";
SharedStringTablePart shareStringPart;
if (StatsCollection.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
{
shareStringPart = StatsCollection.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
}
else
{
shareStringPart = StatsCollection.WorkbookPart.AddNewPart<SharedStringTablePart>();
}
int index = InsertSharedStringItem(contents[contentsIndex], shareStringPart);
WorkbookPart bookPart = StatsCollection.WorkbookPart;
Sheet mySheet = bookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).FirstOrDefault();
WorksheetPart sheetPart = (WorksheetPart)(bookPart.GetPartById(mySheet.Id));
Cell cell = InsertCellInWorksheet(desiredColumns[indexCol - 1].ToString(), indexRow, sheetPart);
cell.CellValue = new CellValue(index.ToString());
//I added the following if structure to check for numbers
if (IsNumeric(contents[contentsIndex].ToString()))
{
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
}
else
{
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
}
/*I removed the following lines
Stylesheet styleSheet = bookPart.WorkbookStylesPart.Stylesheet;
uint _doubleStyleId = createCellFormat(styleSheet, null, null, UInt32Value.FromUInt32(4));
cell.StyleIndex = _doubleStyleId;
*/
sheetPart.Worksheet.Save();
contentsIndex++;
}
}
Console.WriteLine("Copy Complete.");
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot find output Excel file.\n" + ex.Message);
}
}
这里是来自其他解决方案的 createCellFormat
方法。 与我的更新有关。由于我所做的更改,我不再需要此方法,但我会保留它,因为它与原始问题有关。
private static UInt32Value createCellFormat(Stylesheet styleSheet, UInt32Value fontIndex, UInt32Value fillIndex, UInt32Value numberFormatId)
{
CellFormat cellFormat = new CellFormat();
if (fontIndex != null)
{
cellFormat.FontId = fontIndex;
}
if (fillIndex != null)
{
cellFormat.FillId = fillIndex;
}
if (numberFormatId != null)
{
cellFormat.NumberFormatId = numberFormatId;
cellFormat.ApplyNumberFormat = BooleanValue.FromBoolean(true);
}
styleSheet.CellFormats.Append(cellFormat);
UInt32Value result = styleSheet.CellFormats.Count;
styleSheet.CellFormats.Count++;
return result;
}
当我尝试将单元格值从字符串转换为数字时,它按预期转换但更改了值。为什么会发生这种情况,我该如何解决这个问题,同时防止我的一列实际字符串被更改为数字?
更新:
我按照 this 解决方案设法修复了字符串到数字的转换,并且相应地更新了我的代码并添加了以下方法。
private static bool IsNumeric(string value)
{
double output = 0;
if(Double.TryParse(value, out output))
{
return true;
}
else
{
return false;
}
}
现在所有应该是数字的都是数字,所有需要保留为字符串的都是字符串。但是,我的数字的实际值仍在更改(应该为 0 的数字为 5、11 为 0、21 为 33 等)
问题是 CellValue
只是作为字符串的索引。您应该为数字使用实际数组 contents[contentsindex]
,因为您希望显示该数组的内容而不是 index
的值。将 CellValue
部分添加到您的 if..else... 语句中,如下所示。 @BlueBarren 和我在聊天中一起解决了这个问题。
if (IsNumeric(contents[contentsIndex]))
{
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
cell.CellValue = new CellValue(contents[contentsIndex]);
}
else
{
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
cell.CellValue = new CellValue(index.ToString());
}
我正在使用 OpenXML 将一些数据写入 Excel。我已经成功地将所有数据输入到电子表格中,但是当我这样做时,所有数据都是字符串格式。这是因为我主要使用 MSDN 上可用的示例代码,它们将数据插入 Excel 作为 InsertSharedStringItem
(A string
)。然而,我确实找到了两种将单元格转换为数字的方法。
第一个是简单的 CellValues.Number
而不是 CellValues.SharedString
但这似乎改变了单元格中的所有实际值并将它们更改为数字。一个例子是我在一列中有 0,现在它是 5,11 现在是 0,21 是 33,诸如此类的奇怪东西(如果数字像 0 一样重复,它们都会变成,在 0 的情况下,5)。显然那是行不通的。
然后我在 Excel 中找到了另一种将字符串转换为数字的方法,并找到了 here(如果您单击该答案中的 link 转到该用户来源,您需要将 'www.' 添加到 URL)。这个解决方案的问题是它会将所有字符串转换为双精度,但值与第一个解决方案相同,这次只是采用双精度格式。
还值得注意的是,我的第三列应该是一个字符串,不需要转换为数字,但无论如何它都会转换。
这就是我正在使用的:
private static void WriteToExcel(string[] contents, char[] desiredColumns)
{
string filePath = @"D:\Folder\test.xlsx";
try
{
using (SpreadsheetDocument StatsCollection = SpreadsheetDocument.Open(filePath, true))
{
string sheetName = "";
int totalRows = contents.Length / 15;
int contentsIndex = 0;
for (uint indexRow = 1; indexRow < totalRows; indexRow++)
{
for (int indexCol = 1; indexCol < 16; indexCol++)
{
sheetName = "Sheet1";
SharedStringTablePart shareStringPart;
if (StatsCollection.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
{
shareStringPart = StatsCollection.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
}
else
{
shareStringPart = StatsCollection.WorkbookPart.AddNewPart<SharedStringTablePart>();
}
int index = InsertSharedStringItem(contents[contentsIndex], shareStringPart);
WorkbookPart bookPart = StatsCollection.WorkbookPart;
Sheet mySheet = bookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).FirstOrDefault();
WorksheetPart sheetPart = (WorksheetPart)(bookPart.GetPartById(mySheet.Id));
Cell cell = InsertCellInWorksheet(desiredColumns[indexCol - 1].ToString(), indexRow, sheetPart);
cell.CellValue = new CellValue(index.ToString());
//I added the following if structure to check for numbers
if (IsNumeric(contents[contentsIndex].ToString()))
{
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
}
else
{
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
}
/*I removed the following lines
Stylesheet styleSheet = bookPart.WorkbookStylesPart.Stylesheet;
uint _doubleStyleId = createCellFormat(styleSheet, null, null, UInt32Value.FromUInt32(4));
cell.StyleIndex = _doubleStyleId;
*/
sheetPart.Worksheet.Save();
contentsIndex++;
}
}
Console.WriteLine("Copy Complete.");
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot find output Excel file.\n" + ex.Message);
}
}
这里是来自其他解决方案的 createCellFormat
方法。 与我的更新有关。由于我所做的更改,我不再需要此方法,但我会保留它,因为它与原始问题有关。
private static UInt32Value createCellFormat(Stylesheet styleSheet, UInt32Value fontIndex, UInt32Value fillIndex, UInt32Value numberFormatId)
{
CellFormat cellFormat = new CellFormat();
if (fontIndex != null)
{
cellFormat.FontId = fontIndex;
}
if (fillIndex != null)
{
cellFormat.FillId = fillIndex;
}
if (numberFormatId != null)
{
cellFormat.NumberFormatId = numberFormatId;
cellFormat.ApplyNumberFormat = BooleanValue.FromBoolean(true);
}
styleSheet.CellFormats.Append(cellFormat);
UInt32Value result = styleSheet.CellFormats.Count;
styleSheet.CellFormats.Count++;
return result;
}
当我尝试将单元格值从字符串转换为数字时,它按预期转换但更改了值。为什么会发生这种情况,我该如何解决这个问题,同时防止我的一列实际字符串被更改为数字?
更新:
我按照 this 解决方案设法修复了字符串到数字的转换,并且相应地更新了我的代码并添加了以下方法。
private static bool IsNumeric(string value)
{
double output = 0;
if(Double.TryParse(value, out output))
{
return true;
}
else
{
return false;
}
}
现在所有应该是数字的都是数字,所有需要保留为字符串的都是字符串。但是,我的数字的实际值仍在更改(应该为 0 的数字为 5、11 为 0、21 为 33 等)
问题是 CellValue
只是作为字符串的索引。您应该为数字使用实际数组 contents[contentsindex]
,因为您希望显示该数组的内容而不是 index
的值。将 CellValue
部分添加到您的 if..else... 语句中,如下所示。 @BlueBarren 和我在聊天中一起解决了这个问题。
if (IsNumeric(contents[contentsIndex]))
{
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
cell.CellValue = new CellValue(contents[contentsIndex]);
}
else
{
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
cell.CellValue = new CellValue(index.ToString());
}