Created
November 28, 2019 13:20
-
-
Save b4tman/3a7236d05d241cb65cf8ca71ff174e81 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Область XLSX | |
// https://msdn.microsoft.com/ru-ru/library/office/documentformat.openxml.spreadsheet.cell.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1 | |
// https://infostart.ru/public/665512/ | |
// https://infostart.ru/public/280340/ | |
Процедура XLSX_Распаковать(ИмяФайла, Каталог) | |
Зип = Новый ЧтениеZipФайла; | |
Зип.Открыть(ИмяФайла); | |
Зип.ИзвлечьВсе(Каталог, РежимВосстановленияПутейФайловZIP.Восстанавливать); | |
КонецПроцедуры | |
Процедура XLSX_Упаковать(ИмяФайла, Каталог) | |
ЗаписьZIP = Новый ЗаписьZipФайла(); | |
ЗаписьZIP.Открыть(ИмяФайла); | |
ЗаписьZIP.Добавить(Каталог+"*", РежимСохраненияПутейZIP.СохранятьОтносительныеПути, РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно); | |
ЗаписьZIP.Записать(); | |
КонецПроцедуры | |
Функция XLSX_ПрочитатьДокументDOM(Каталог) | |
ЧтениеXML = Новый ЧтениеXML; | |
ПостроительDOM = Новый ПостроительDOM; | |
ЧтениеXML.ОткрытьФайл(Каталог+"xl\worksheets\sheet1.xml"); | |
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML); | |
ЧтениеXML.Закрыть(); | |
Возврат ДокументDOM; | |
КонецФункции | |
Процедура XLSX_ЗаписатьДокументDOM(Каталог, ДокументDOM) | |
ЗаписьXML = Новый ЗаписьXML; | |
ЗаписьDOM = Новый ЗаписьDOM; | |
Парам_XML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь, Ложь); | |
ЗаписьXML.ОткрытьФайл(Каталог+"xl\worksheets\sheet1.xml", Парам_XML, Ложь); | |
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML); | |
ЗаписьXML.Закрыть(); | |
КонецПроцедуры | |
Процедура XLSX_УстановитьЗначениеЯчейки(ДокументDOM, Разыменователь, КодЯчейки, Знач ЗначениеЯчейки, Знач ТипЗначения="") | |
Если ПустаяСтрока(ТипЗначения) Тогда | |
Если Тип("Число") = ТипЗнч(ЗначениеЯчейки) Тогда | |
ТипЗначения = "Число"; | |
ИначеЕсли Тип("Строка") = ТипЗнч(ЗначениеЯчейки) Тогда | |
ТипЗначения = "Строка"; | |
Иначе | |
ТипЗначения = "Строка"; | |
ЗначениеЯчейки = Строка(ЗначениеЯчейки); | |
КонецЕсли; | |
КонецЕсли; | |
ПоискЯчейки = ДокументDOM.ВычислитьВыражениеXPath(СтрШаблон("//*[@r='%1']", КодЯчейки), ДокументDOM.ЭлементДокумента, Разыменователь); | |
УзелЯчейки = ПоискЯчейки.ПолучитьСледующий(); | |
Если Неопределено = УзелЯчейки Тогда | |
УзелЯчейки = XLSX_ДобавитьЯчейку(ДокументDOM, Разыменователь, КодЯчейки); | |
КонецЕсли; | |
Если Неопределено = УзелЯчейки Тогда | |
Лог(СтрШаблон("Ошибка заполнения ячейки: %1", КодЯчейки)); | |
Иначе | |
Для Каждого ДочернийУзел Из УзелЯчейки.ДочерниеУзлы Цикл | |
УзелЯчейки.УдалитьДочерний(ДочернийУзел); | |
КонецЦикла; | |
Если "Строка" = ТипЗначения Тогда | |
УзелЯчейки.УстановитьАтрибут("t", "inlineStr"); | |
Узел_is = ДокументDOM.СоздатьЭлемент("is"); | |
Узел_t = ДокументDOM.СоздатьЭлемент("t"); | |
ЗначениеУзла = ДокументDOM.СоздатьТекстовыйУзел(ЗначениеЯчейки); | |
Узел_t.ДобавитьДочерний(ЗначениеУзла); | |
Узел_is.ДобавитьДочерний(Узел_t); | |
УзелЯчейки.ДобавитьДочерний(Узел_is); | |
ИначеЕсли "Число" = ТипЗначения Тогда | |
УзелЯчейки.УстановитьАтрибут("t", "n"); | |
Узел_v = ДокументDOM.СоздатьЭлемент("v"); | |
ЗначениеУзла = ДокументDOM.СоздатьТекстовыйУзел(Формат(ЗначениеЯчейки, "ЧРД=.; ЧГ=0")); | |
Узел_v.ДобавитьДочерний(ЗначениеУзла); | |
УзелЯчейки.ДобавитьДочерний(Узел_v); | |
КонецЕсли; | |
КонецЕсли; | |
КонецПроцедуры | |
Функция XLSX_МестоДляВставкиЯчейки(ДокументDOM, Разыменователь, НомерСтолбца, НомерСтроки, УзелСтроки) | |
// поиск узла перед которым нужно вставить узел ячейки (например L3 нужно вставить перед М3 если он есть, или перед N3,... или в конец) | |
// FIXME: возможно, не самое оптимальное решение (поиск по перебору колонок перед нужной) | |
СледЯчейка = Неопределено; | |
Если УзелСтроки.ЕстьДочерниеУзлы() Тогда | |
ТекНомерК = НомерСтолбца - 1; | |
Пока ТекНомерК > 0 Цикл | |
ТекКод = XLSX_КодСтолбцаExcel(ТекНомерК) + НомерСтроки; | |
ПоискУзла = ДокументDOM.ВычислитьВыражениеXPath(СтрШаблон("//*[@r='%1']", ТекКод), УзелСтроки, Разыменователь); | |
ПредЯчейка = ПоискУзла.ПолучитьСледующий(); | |
Если НЕ Неопределено = ПредЯчейка Тогда | |
СледЯчейка = ПредЯчейка.СледующийСоседний; | |
Прервать; | |
КонецЕсли; | |
ТекНомерК = ТекНомерК - 1; | |
КонецЦикла; | |
// если не нашли след. ячейку по предыдущим, то проверим | |
// возможно у первого узла больший номер колонки чем у новой ячейки | |
// например если первый элемент D1 а новая ячейка B1, то след.ячейка = первая | |
Если Неопределено = СледЯчейка Тогда | |
ПервыйУзел = УзелСтроки.ПервыйДочерний(); | |
ТекКод = ПервыйУзел.ПолучитьАтрибут("r"); | |
ТекАдр = XLSX_ПолучитьАдресЯчейки(ТекКод); | |
ТекНомерК = XLSX_НомерСтолбцаExcel(ТекАдр.КодСтолбца); | |
Если ТекНомерК > НомерСтолбца Тогда | |
СледЯчейка = ПервыйУзел; | |
КонецЕсли; | |
КонецЕсли; | |
КонецЕсли; | |
Возврат СледЯчейка; | |
КонецФункции | |
Функция XLSX_ДобавитьЯчейку(ДокументDOM, Разыменователь, КодЯчейки) | |
Результат = Неопределено; | |
// разбиение кода ячейки на столбец и строку | |
АдресЯчейки = XLSX_ПолучитьАдресЯчейки(КодЯчейки); | |
НомерСтолбца = XLSX_НомерСтолбцаExcel(АдресЯчейки.КодСтолбца); | |
// поиск строки / <row ... | |
ПоискСтроки = ДокументDOM.ВычислитьВыражениеXPath(СтрШаблон("//*[@r='%1']", АдресЯчейки.НомерСтроки), ДокументDOM.ЭлементДокумента, Разыменователь); | |
УзелСтроки = ПоискСтроки.ПолучитьСледующий(); | |
// нет такой строки | |
// TODO: добавить строку? (надо также менять <dimension ref="A1:R4"/>) | |
Если Неопределено = УзелСтроки Тогда | |
Лог(СтрШаблон("Ошибка: не найдена строка файла - %1", АдресЯчейки.НомерСтроки)); | |
Возврат Результат; | |
КонецЕсли; | |
// TODO: добавить проверку наличия колонки и добавление её (надо также менять <dimension ref="A1:R4"/> и <cols>) | |
// создание узла / <c r="G1" s="2" t="s"> | |
УзелЯчейки = ДокументDOM.СоздатьЭлемент("c"); | |
УзелЯчейки.УстановитьАтрибут("r", КодЯчейки); | |
СледЯчейка = XLSX_МестоДляВставкиЯчейки(ДокументDOM, Разыменователь, НомерСтолбца, АдресЯчейки.НомерСтроки, УзелСтроки); | |
УзелСтроки.ВставитьПеред(УзелЯчейки, СледЯчейка); | |
Результат = УзелЯчейки; | |
Возврат Результат; | |
КонецФункции | |
Функция XLSX_ПолучитьАдресЯчейки(КодЯчейки) | |
Результат = Новый Структура("КодСтолбца,НомерСтроки", "", 0); | |
ПозицияНомераСтроки = 0; | |
Если 2 > СтрДлина(КодЯчейки) Тогда Возврат Результат; КонецЕсли; | |
Для ТекПозиция=1 По СтрДлина(КодЯчейки) Цикл | |
ТекСимвол = Сред(КодЯчейки, ТекПозиция, 1); | |
Если НЕ 0 = СтрНайти("0123456789", ТекСимвол) Тогда | |
ПозицияНомераСтроки = ТекПозиция; | |
Прервать; | |
КонецЕсли; | |
КонецЦикла; | |
Если НЕ 0 = ПозицияНомераСтроки Тогда | |
Результат.КодСтолбца = Лев(КодЯчейки, ПозицияНомераСтроки - 1); | |
Результат.НомерСтроки = Прав(КодЯчейки, 1 + СтрДлина(КодЯчейки) - ПозицияНомераСтроки); | |
Результат.НомерСтроки = Число(Результат.НомерСтроки); | |
КонецЕсли; | |
Возврат Результат; | |
КонецФункции | |
Функция XLSX_КодСтолбцаExcel(Знач Номер) | |
// формирует буквенный код столбца Excel, например: 1 - A, 2 - B, 27 - AA, 703 - AAA, ... | |
Результат = ""; | |
КолвоАлфавит = 1 + КодСимвола("Z") - КодСимвола("A"); // 26 | |
СмещениеСимвола = КодСимвола("A") - 1; // 64 | |
Пока Номер > 0 Цикл | |
Если Номер <= КолвоАлфавит Тогда | |
Результат = Символ(СмещениеСимвола + Номер) + Результат; | |
Номер = 0; | |
Иначе | |
ТекСимвол = ((Номер - 1) % КолвоАлфавит) + 1; | |
Номер = Цел((Номер - 1) / КолвоАлфавит); | |
Результат = Символ(СмещениеСимвола + ТекСимвол) + Результат; | |
КонецЕсли; | |
КонецЦикла; | |
Возврат Результат; | |
Конецфункции | |
Функция XLSX_НомерСтолбцаExcel(Знач БуквКод) | |
// формирует номер столбца Excel по буквенному коду, например: 1 - A, 2 - B, 27 - AA, 703 - AAA, ... | |
Результат = 0; | |
КолвоАлфавит = 1 + КодСимвола("Z") - КодСимвола("A"); // 26 | |
СмещениеСимвола = КодСимвола("A") - 1; // 64 | |
Множитель = 1; | |
ДлиннаКода = СтрДлина(БуквКод); | |
Пока ДлиннаКода > 0 Цикл | |
ТекСимвол = Прав(БуквКод, 1); | |
Результат = Результат + Множитель * (КодСимвола(ТекСимвол) - СмещениеСимвола); | |
ДлиннаКода = ДлиннаКода - 1; | |
Если 0 = ДлиннаКода Тогда | |
БуквКод = ""; | |
Иначе | |
БуквКод = Лев(БуквКод, ДлиннаКода); | |
КонецЕсли; | |
Множитель = Множитель * КолвоАлфавит; | |
КонецЦикла; | |
Возврат Результат; | |
Конецфункции | |
//XLSX | |
#КонецОбласти |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment