3

xlsx ファイルからテキストを抽出する必要があります (データベースの全文索引に入れるため)。次のコードを使用しています。

using(SpreadsheetDocument d = SpreadsheetDocument.Open(stream, false)) {
 // Load the shared strings table.
 SharedStringTablePart stringTable = 
  d.WorkbookPart.GetPartsOfType<SharedStringTablePart>()
  .FirstOrDefault();
 if(stringTable == null) System.Diagnostics.Debug.WriteLine("Null string table");
 foreach(WorksheetPart part in d.WorkbookPart.WorksheetParts) {
  foreach(SheetData sheet in part.Worksheet.Elements<SheetData>()) {
   bool added = false;
   foreach(Row r in sheet.Elements<Row>()) {
    foreach(Cell c in r.Elements<Cell>()) {
     if(c.DataType != null) {
      string v = c.CellValue.Text;
      if(v != null && c.DataType.Value == CellValues.SharedString) {
       var tableEntry = stringTable.SharedStringTable.ElementAt(int.Parse(v));
       if(tableEntry != null) {
        v = tableEntry.InnerText;
       }
      }
      if(v != null) {
       if(added) b.Append('\t');
       b.Append(v);
       added = true;
      }
     }
    }
    if(added) b.AppendLine();
   }
  }
 }
}
return b.ToString();

Web で見つけた例では、共有文字列テーブルについて言及されていませんでした。文字列データが出力されていないことに気付いたときに、そのことを知りました。

他に知っておくべき落とし穴はありますか?

コードに対するその他の批判はいつでも歓迎します。

4

1 に答える 1

1

セルから実際のデータを抽出するには、いくつかの注意が必要な部分があります。そこに格納されることもあれば (数値、日付、インライン文字列)、SharedStringTable を参照することもあります。私はかなりの数の関数を閲覧しましたが、これが私が思いついたものです(一部はコピーされ、一部は私のものです)。これを後でコードに快適にスライドできるはずです

foreach(r.Elements() のセル c) {

このような

文字列 v = GetValueFromCell(c, d.WorkbookPart);

        /// <summary>
        /// Return si value based on xml cell id number
        /// </summary>
        /// <param name="workbookPart"></param>
        /// <param name="id"></param>
        /// <returns>SharedStringItem for interpretation</returns>
        public static SharedStringItem GetSharedStringItemById(WorkbookPart workbookPart, int id)
        {
            return workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(id);
        }

        /// <summary>
        /// Return value from the cell based on the cell's information (innards and/or id)
        /// </summary>
        /// <param name="cell">spreadhseet cell</param>
        /// <param name="workbookPart">work book from uploaded file</param>
        /// <returns>string value of the cell</returns>
        public static string GetValueFromCell(Cell cell, WorkbookPart workbookPart)
        {
            int id;
            string cellValue = cell.InnerText;

            if (cellValue.Trim().Length > 0)
            {
                if (cell.DataType != null)
                {
                    switch (cell.DataType.Value)
                    {
                        case CellValues.SharedString:

                            Int32.TryParse(cellValue, out id);
                            SharedStringItem item = GetSharedStringItemById(workbookPart, id);
                            if (item.Text != null)
                            {
                                cellValue = item.Text.Text;
                            }
                            else if (item.InnerText != null)
                            {
                                cellValue = item.InnerText;
                            }
                            else if (item.InnerXml != null)
                            {
                                cellValue = item.InnerXml;
                            }
                            break;

                        case CellValues.Boolean:
                            switch (cellValue)
                            {
                                case "0":
                                    cellValue = "FALSE";
                                    break;
                                default:
                                    cellValue = "TRUE";
                                    break;
                            }
                            break;
                    }
                }

                else
                {
                    int excelDate;
                    if (Int32.TryParse(cellValue, out excelDate))
                    {

                        var styleIndex = (int)cell.StyleIndex.Value;

                        var cellFormats = workbookPart.WorkbookStylesPart.Stylesheet.CellFormats;
                        var numberingFormats = workbookPart.WorkbookStylesPart.Stylesheet.NumberingFormats;
                        var cellFormat = (CellFormat)cellFormats.ElementAt(styleIndex);

                        if (cellFormat.NumberFormatId != null)
                        {

                            var numberFormatId = cellFormat.NumberFormatId.Value;
                            var numberingFormat = numberingFormats.Cast<NumberingFormat>().SingleOrDefault(f => f.NumberFormatId.Value == numberFormatId);

                            if (numberingFormat != null && numberingFormat.FormatCode.Value.Contains("/yy")) //TODO here i should think of locales
                            {
                                DateTime dt = DateTime.FromOADate(excelDate);
                                cellValue = dt.ToString("MM/dd/yyyy");
                            }
                        }
                    }
                }
            }
            return cellValue;
        }
于 2015-04-09T16:31:55.310 に答える