Яка хороша модель дизайну для генерації файлу Excel (xlsx) у коді?


12

Докладніше див. У розділі Моє оновлення внизу.


Іноді у мене є проекти, де мені доводиться виводити деякі дані у вигляді файлу Excel (формат xlsx). Зазвичай процес:

  1. Користувач натискає деякі кнопки в моїй програмі

  2. Мій код виконує запит БД і якось обробляє результати

  3. Мій код генерує файл * .xlsx, використовуючи бібліотеки інтеропів Excel com або якусь сторонній бібліотеку (наприклад, Aspose.Cells)

Я легко можу знайти приклади коду, як це зробити в Інтернеті, але я шукаю більш надійний спосіб зробити це. Я хотів би, щоб мій код дотримувався деяких принципів проектування, щоб мій код був легкодоступним і легко зрозумілим.


Ось як виглядала моя перша спроба генерування файлу xlsx:

var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);

Плюси: Не так багато. Це працює, так що це добре.

Мінуси:

  • Посилання на клітини жорстко кодуються, тому в мене в коді є чарівні цифри.
  • Додавати або видаляти стовпці та рядки важко без оновлення багатьох посилань на комірки.
  • Мені потрібно вивчити якусь сторонній бібліотеку. Деякі бібліотеки використовуються, як і інші бібліотеки, але проблеми все ще можуть бути. У мене виникла проблема, коли бібліотеки com interop використовують посилання на клітини на основі 1, тоді як Aspose.Cells використовує посилання на клітини на основі 0.

Ось одне рішення, яке стосується деяких мінусів, які я перераховував вище. Я хотів розглядати таблицю даних як власний об'єкт, який можна переміщувати та змінювати, не занурюючись в маніпуляції з клітинками і не порушуючи інших посилань на комірки. Ось псевдокод:

var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
    {
        { "Row 1", "Row 1", "Row 1" },
        { "Row 2", "Row 2", "Row 2" },
        { "Row 3", "Row 3", "Row 3" }
    });

body.PutBelow(headers);

У рамках цього рішення у мене буде об’єкт BlockEngine, який бере контейнер Блоків і виконує маніпуляції з комірки, необхідні для виведення даних у вигляді * .xlsx-файлу. Блок-об'єкт може мати до нього форматування.

Плюси:

  • Це видаляє більшість магічних чисел, якими був мій початковий код.
  • Це приховує багато коду маніпуляції з клітинками, хоча маніпуляція з комірками все ще потрібна в об'єкті BlockEngine, про який я згадував.
  • Набагато простіше додавати та видаляти рядки, не впливаючи на інші частини електронної таблиці.

Мінуси:

  • Додавання або видалення стовпців все ще важко. Якби я хотів поміняти місцями два та три стовпці, мені доведеться безпосередньо поміняти вміст комірок. У цьому випадку було б вісім правок, а значить, вісім можливостей зробити помилку.
    • Якщо у мене є якесь форматування для цих двох стовпців, я також повинен це оновити.
  • Це рішення не підтримує розміщення горизонтального блоку; Я можу розмістити лише один блок нижче іншого. Звичайно, я міг би мати це tableRight.PutToRightOf(tableLeft), але це спричинило б проблеми, якби tableRight та tableLeft мали різну кількість рядків. Щоб розмістити таблиці, двигун повинен був знати всі інші таблиці. Мені це здається зайвим.
  • Мені все-таки потрібно вивчити сторонній код, хоча через шар абстракції через об'єкти Block та BlockEngine код буде менш щільно пов'язаний із сторонніми бібліотеками, ніж моя перша спроба. Якби я хотів підтримати безліч різноманітних варіантів форматування в зв'язаному вигляді, я, мабуть, мав би написати багато коду; мій BlockEngine був би величезним безладом.

Ось рішення, яке займає інший маршрут. Ось процес:

  1. Я беру дані своїх звітів і генерую XML-файл у обраному вами форматі.

  2. Потім я використовую перетворення xsl для перетворення файлу xml у файл таблиці Excel 2003 XML.

  3. Звідти я просто конвертую таблицю xml у файл xlsx, використовуючи сторонні бібліотеки.

Я знайшов цю сторінку, яка описує подібний процес і включає приклади коду.

Плюси:

  • Це рішення майже не вимагає маніпуляцій з клітинами. Ви замість цього використовуєте xsl / xpath для маніпуляцій. Для того, щоб поміняти два стовпчики в таблиці, ви переміщуєте цілі стовпці у файлі xsl на відміну від інших моїх рішень, які потребували б заміни комірок.
  • Хоча вам ще потрібна стороння бібліотека, яка може конвертувати таблицю XML XML Excel 2003 у файл xlsx, це приблизно все, що вам знадобиться для бібліотеки. Кількість коду, який потрібно написати, який би зателефонував до сторонньої бібліотеки, невеликий.
  • Я думаю, що це рішення є найпростішим для розуміння і вимагає найменшої кількості коду.
    • Код, який створює дані у власному форматі XML, буде простим.
    • Файл xsl буде складним лише тому, що електронна таблиця XML 2003 Excel складна. Однак перевірити вихід файлу xsl легко: просто відкрийте вихід у Excel і перевірте наявність повідомлень про помилки.
    • Генерувати зразкові файли електронних таблиць Excel 2003 XML легко: просто створіть електронну таблицю, схожу на потрібний файл xlsx, а потім збережіть її як таблицю XML Excel 2003.

Мінуси:

  • Електронні таблиці XML Excel 2003 не підтримують певні функції. Наприклад, не можна автоматично встановити ширину стовпців. Ви не можете включати зображення в колонтитули чи колонтитули. Якщо ви збираєтеся експортувати отриманий файл xlsx у pdf, ви не можете встановити закладки pdf. (Я зламав разом виправлення цього за допомогою коментарів у клітинках.) Ви повинні зробити це за допомогою своєї сторонньої бібліотеки.
  • Потрібна бібліотека, яка підтримує таблиці Excel 2003 XML.
  • Використовується 11-річний формат файлу MS Office.

Примітка. Я розумію, що файли xlsx - це фактично поштові файли, що містять файли xml, але форматування xml здається занадто складним для моїх цілей.


Нарешті, я розглядав рішення, що стосуються SSRS, але це здається занадто роздутим для моїх цілей.


Назад до мого початкового запитання, що таке хороша схема дизайну для генерації файлів Excel у коді ?. Я можу придумати декілька рішень, але жодне не здається ідеальним. У кожного є недоліки.


Оновлення. Тому я спробував як моє рішення BlockEngine, так і моє рішення XML-електронної таблиці для генерації подібних файлів XLSX. Ось моя думка щодо них:

  • Рішення BlockEngine:

    • Для цього просто потрібно занадто багато коду з урахуванням альтернатив.
    • Мені було занадто просто перезаписати один блок на інший, якщо я зсув неправильно.
    • Я спочатку заявив, що форматування може бути додане на рівні блоку. Я вважав, що це не набагато краще, ніж робити форматування окремо від вмісту блоку. Я не можу придумати вдалого способу поєднання вмісту та форматування. Я також не можу знайти хороший спосіб тримати їх окремо. Це просто безлад.
  • Рішення електронної таблиці XML:

    • Я зараз іду з цим рішенням.
    • Повторюється, що для цього рішення потрібно набагато менше коду. Я ефективно замінюю BlockEngine самим Excel. Мені все одно потрібен злом для таких функцій, як закладки та розриви сторінок.
    • Формат електронної таблиці XML - вибагливий, але легко змінити невеликі зміни та порівняти результати з існуючим файлом у вашій улюбленій програмі Diff. І як тільки ви з'ясуєте якусь ідіосинкразію, можете поставити її на місце і забути про неї звідти.
    • Я все ще стурбований тим, що це рішення спирається на більш старий формат файлу Excel.
    • Створений мною XSLT файл легко працювати. Справа з форматуванням тут набагато простіша, ніж з рішенням BlockEngine.

Відповіді:


7

Якщо ви дійсно хочете, щоб щось добре працювало для вас, то я пропоную вам звикнути до ідеї "зайвого складного" ... така природа стосується форматів файлів Microsoft Office.

Мені подобається ваша ідея "блоків" ... Я б зробив підкласифіковані блокові об'єкти, як "Таблиця", стовпці та рядки незалежні від поняття комірок. Потім використовуйте механізм свого блоку для перетворення цих файлів у XSLS-файли.

Раніше я успішно використовував SDK OpenXML , але не намагайтеся читати документацію і починати з нуля. Натомість створіть в Excel точну копію того, що ви хочете, збережіть її та огляньте її за допомогою наданого інструменту Reflector Document. Він дасть вам код C #, необхідний для створення документа, з якого ви зможете дізнатися та змінити.


Офісні документи НЕ "зайво складні" - вони роблять або дозволяють величезний спектр операцій, форматування, функціональність тощо
warren

5
Я не стверджую, що самі формати файлів є надмірно складними, наскільки я стверджую, що робота з ними. Наприклад, використання SDK OpenXML вимагає знати магічний порядок додавання елементів ... додавання макета слайда до презентації, наприклад, не працює. Ви повинні додати його спочатку до слайду, а потім до презентації. Чому? Тому що Microsoft таким чином кодувала бібліотеки. Є також багато дивних кругових посилань, якими можна керувати. Я розумію, що формат потребує складності, але робота з ним не повинна бути настільки болючою.
mgw854

3

Ось таке рішення, яке я часто використовував у минулому:

  • створити звичайний документ Excel (як правило, у форматі xlsx) як шаблон, що містить усі заголовки стовпців, включаючи їх заголовок та форматування за замовчуванням для стовпців та, можливо, форматування комірок заголовка.

  • вставте цей шаблон у ресурси вашої програми. Під час виконання першого кроку - це витягнути шаблон як новий файл і помістити його в папку призначення

  • використовувати Interop або сторонню бібліотеку для заповнення даних у новостворений xlsx. Не посилайтеся на твердо кодовані номери стовпців, натомість використовуйте деякі метадані (наприклад, заголовки стовпців) для ідентифікації правильних стовпців.

Плюси:

  • щось на зразок вашого блокового підходу зараз працює краще. Наприклад, розміщення стовпців: не потрібно нічого змінювати у вашому блоковому коді, оскільки правильні стовпці визначаються їх заголовками

  • якщо ваші стовпці мають унікальне форматування, більшість форматування можна виконати безпосередньо в Excel, маніпулюючи шаблоном. Це дає вам відчуття WYSIWYG разом із свободою користуватися будь-яким варіантом форматування, доступним в Excel, без необхідності писати для цього код

Мінуси:

  • вам все-таки потрібно скористатися стороннім лібом або Interop. Я згадав, що Interop повільний?

  • коли в шаблоні змінюються заголовки стовпців, вам потрібно адаптувати також ваш код (але це може бути легко виявлено за допомогою процедури перевірки, яка сигналізує, якщо очікувані стовпці відсутні)

  • коли вам потрібно динамічне форматування різних комірок в одному стовпці, вам все одно доведеться мати справу з цим у коді

Як загальний підказку, який би підхід ви не вибрали: він має переваги відокремити макет від контенту та використовувати декларативні рішення.


0

Слід врахувати дві речі:

  • Складність створення файлу у заданому форматі
  • Сприйнятливість коду до злому, коли структура змісту файлу потребує змін.

Щодо першого:

Якщо потрібні для створення електронних таблиць не містять форматування чи формул , то вам досить просто створити файл CSV або розділених на вкладку замість фактичного XLSX. Excel відкриває ці файли, часто за замовчуванням на багатьох ПК. Це не допоможе вам у жорсткому кодуванні стовпців та рядків, але це заощадить додаткову роботу щодо маніпулювання об'єктною моделлю Excel.

Якщо вам потрібно форматування або формули, то робота з об’єктною моделлю Excel є розумним способом, особливо якщо ви створюєте електронну таблицю, яка не надто "жорстко кодована" сама по собі. Іншими словами, якщо ваша електронна таблиця належним чином використовує відносні формули та назви діапазонів, вона може поєднуватися з менш жорстким кодуванням магічних чисел.

Щодо другого:

Ви можете працювати через клітинку за коміркою із жорстко кодованими посиланнями рядків та стовпців, або ви можете працювати з масивами / Список колекцій та forциклів, щоб узагальнити сукупність комірок.


У своєму первісному питанні мені не було зрозуміло, що я хочу контролювати параметри форматування та друку та таке в своєму рішенні. Щодо другого моменту, я вважаю, що ви маєте на увазі те, що я описав у своєму BlockEngineрішенні. Я міг взяти IList<IBusinessObject>і виплюнути Blockпредмет. Плюси і мінуси все одно були б однаковими.
користувач2023861
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.