当EPPlus中单元格具有多种样式时,公式单元格将提取xml样式表值

时间:2019-03-14 21:01:46

标签: c# excel excel-formula stream epplus

我不知道以前是否有人遇到过此问题。基本上,我正在读取公式单元格值。原始单元格有两种字体样式CalibriArial。在这种情况下,它将以某种方式尝试保留样式,并将值作为XML样式表读取(下面的示例)。

就我而言,我不太在乎样式。在阅读单元格时是否有一种忽略样式的方法?

<r xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <t>XS-1000</t>
</r>
<r xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <rPr>
        <b />
        <i />
        <sz val="18" />
        <rFont val="Arial" />
        <family val="2" />
    </rPr>
    <t>i</t>
</r>
<r xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <rPr>
        <b />
        <sz val="18" />
        <rFont val="Arial" />
        <family val="2" />
    </rPr>
    <t>™ ANALYZERS</t>
</r>

这是读取excel行的代码:

private List<string> ReadRow(ExcelRange cells, int row, int startColumn, int numberOfCols, bool skipEmptyCol = false)
{
    if (row < 1)
        throw new ArgumentException("invalid start line.", "startLine");

    if (startColumn < 1)
        throw new ArgumentException("invalid start column.", "startColumn");

    if (numberOfCols < 1)
        throw new ArgumentException("invalid number of columns.", "numberOfCols");

    var rowData = new List<string>();
    int currentColumn = startColumn;

    while ((startColumn + numberOfCols > currentColumn))
    {
        var cellValueString = "";
        var cellValue = (cells[row, currentColumn].Value ?? "").ToString();

        if (string.IsNullOrWhiteSpace(cellValueString) && !skipEmptyCol) { break; }

        rowData.Add(cellValueString);
        currentColumn++;
    }

    return rowData;
}

这是单元格中的公式,其读取值来自:

=SUBSTITUTE(SUBSTITUTE('XEC PDF'!A3, "HEMATOLOGY CONTROL FOR ","")," and ","/") 

1 个答案:

答案 0 :(得分:0)

所以问题出在单元格中,因为有两种不同的字体样式(“ TM”是上标,其他一切正常)。执行ExcelWorkbook.Calculate()方法时,它将使用xml标记转换单元格值以保留样式。就我而言,我正在使用公式来提取值,并且只需要在报表上显示这些上标即可。所以我的解决方案是清除那些richText,放回正常值,然后运行Calculate()。另外,当我从合并的单元格中读取数据时,我遇到了另一个问题,它只是爆炸了。所以我也在下面添加了一个解决方案。

**您还可以通过添加标签并解析来从XML格式的文本中提取值,然后获取值(可以将其添加到公共数据成员属性中)。我已将解决方案发布到底部。

        internal ImportFormulaSheetResponse ImportFormulaSheet(string formulaFilePath)
        {
            var impFormRes = new ImportFormulaSheetResponse();

            try
            {
                using (var workbookFormula = new ExcelPackage(new FileInfo(formulaFilePath)))
                using (var workbookOriginal = CreateExcelPackage(this.Stream))
                {
                    List<string> sheetNames = new List<string>();
                    List<string> formulaSheets = new List<string>();

                    foreach (var worksheet in workbookOriginal.Workbook.Worksheets)
                    {
                        List<int> parameterCols = new List<int> { 1, 2, 17 };

                        int rowCount = worksheet.Dimension.End.Row;
                        foreach(int col in parameterCols)
                        {
                            for (int row = 14; row < rowCount; row++)
                            {
                                if (worksheet.Cells[row, col].IsRichText)
                                {
                                    //removing super/sub script formatting from RichText Cell property
                                    var celVal = worksheet.Cells[row, col].Value;
                                    if (worksheet.Cells[row, col].Merge == true)
                                    {
                                        string range = GetMergedRange(worksheet, row, col);
                                        worksheet.Cells[range].Merge = false;
                                    }
                                    worksheet.Cells[row, col].Clear();
                                    worksheet.Cells[row, col].Value = celVal;
                                }
                            }
                        }
                    }

                    foreach (var worksheet in workbookFormula.Workbook.Worksheets)
                    {
                        if (worksheet.Name.Contains("Formula"))
                        {
                            workbookOriginal.Workbook.Worksheets.Add(worksheet.Name, worksheet);
                            formulaSheets.Add(worksheet.Name);
                        }
                        else
                        {
                            sheetNames.Add(worksheet.Name);
                        }
                    }

                    //Calculate so the formula references have updated values
                    workbookOriginal.Workbook.Calculate();
                    workbookOriginal.Save();
                    this.Stream = workbookOriginal.Stream;

                    return impFormRes;
                }
            }
            catch (Exception ex)
            {
                impFormRes.Notifications.AddError(ex.Source, ex.Message);
                return impFormRes;
            }
        }

        /// <summary>
        /// Find the merged range a specific cell it belongs to
        /// </summary>
        /// <returns>merged cell string</returns>
        internal string GetMergedRange(ExcelWorksheet worksheet, int row, int col)
        {
            ExcelWorksheet.MergeCellsCollection mergedCells = worksheet.MergedCells;
            foreach (var merged in mergedCells)
            {
                ExcelRange range = worksheet.Cells[merged];
                ExcelCellAddress cell = new ExcelCellAddress(row, col);
                if (range.Start.Row <= cell.Row && range.Start.Column <= cell.Column)
                {
                    if (range.End.Row >= cell.Row && range.End.Column >= cell.Column)
                    {
                        return merged.ToString();
                    }
                }
            }
            return "";
        }

/////////////////////////////////////////////////////////////////

    public class ExcelImport
    {
        //workbook.Calculate() generates xml style tag around a cell with multiple styling
        //so add root tag to make it a proper xml document, parse and read root value
        if (rowData[2].Contains("<"))
        {
            string myXML = "<root>" + rowData[2] + "</root>";
            XDocument doc = XDocument.Parse(myXML);
            InstrumentName = doc.Root.Value;
        }
    }