Доброго времени суток хабратчане! Сегодня я продолжу мучить вас великим и могучим Руслишем. Это продолжение статей:
» Разработка → Кроссплатформенное использование классов .Net из неуправляемого кода. Или аналог IDispatch на Linux
» Разработка → Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux
» Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux II
» Асинхронное программирование в 1С через .Net Native ВК
С того времени я добавил использование расширений Linq. В этой статье я коснусь практического использования моей компоненты. А именно кроссплатформенной работой с файлами Excel и Word c помощью OpenXML и NetStandart.
Собственно ради чего эта разработка и задумывалась. Исходники были взяты отсюда. К сожалению без Nuget подключить библиотеку к проекту нельзя. Но через CoreClr его можно подключить. Справочную информацию по работе с OpenXML можно посмотреть здесь.
Как мне… (Open XML SDK)
Итак начнем с чтения страниц Excel. Задача преобразовать данные в ТаблицуЗначений.
Рассмотрим более подробно методы для получения данных о ячейках таблицы
Теперь нам нужно преобразовать ТЗ с данными о ячейках в Таблицу Здначений аналогичной Странице Excel
Теперь перейдем к чтению данных файла Word.
Очень удобно использовать Productivity Tool", она умеет генерировать код Генерируем OfficeOpenXML-документы за 5 минут
Кроме того есть множество провайдеров к различным базам данных, как MS SQL так и другим, в том числе NoSQL
Приведу пример доступа к MS SQL
При этом можно сделать обертку DynamicObject над SqlDataReader и использовать так
В своих статьях я хочу донести прежде всего до 1С, что есть кроссплатформенная замена COM с помощью NetStadart. Но к моему большому сожалению пока данный подход никого не интересует. Привлекает внимание только Руслиш. Если у кого будут идеи чем можно привлечь внимание к замене COM пишите. Буду только рад.
Примеры и исходники можно скачать здесь.
» Разработка → Кроссплатформенное использование классов .Net из неуправляемого кода. Или аналог IDispatch на Linux
» Разработка → Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux
» Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux II
» Асинхронное программирование в 1С через .Net Native ВК
С того времени я добавил использование расширений Linq. В этой статье я коснусь практического использования моей компоненты. А именно кроссплатформенной работой с файлами Excel и Word c помощью OpenXML и NetStandart.
Собственно ради чего эта разработка и задумывалась. Исходники были взяты отсюда. К сожалению без Nuget подключить библиотеку к проекту нельзя. Но через CoreClr его можно подключить. Справочную информацию по работе с OpenXML можно посмотреть здесь.
Как мне… (Open XML SDK)
Итак начнем с чтения страниц Excel. Задача преобразовать данные в ТаблицуЗначений.
Процедура ПрочитатьExcel(ИмяФайла) // Загрузим сборку СборкаOpenXml=ъ(Врап.Сборка("DocumentFormat.OpenXml.dll")); // Получим типы SpreadsheetDocument=ъ(СборкаOpenXml.GetType("DocumentFormat.OpenXml.Packaging.SpreadsheetDocument")); SharedStringTablePart=ъ(СборкаOpenXml.GetType("DocumentFormat.OpenXml.Packaging.SharedStringTablePart")); CellValues=ъ(СборкаOpenXml.GetType("DocumentFormat.OpenXml.Spreadsheet.CellValues")); SharedString=ъ(CellValues.SharedString); Cell=ъ(СборкаOpenXml.GetType("DocumentFormat.OpenXml.Spreadsheet.Cell")); Sheet=ъ(СборкаOpenXml.GetType("DocumentFormat.OpenXml.Spreadsheet.Sheet")); Regex=ъТип("System.Text.RegularExpressions.Regex","System.Text.RegularExpressions",истина); // Вот чего не хватает в 1С так это Regex ШаблонКолонки=ъ(Врап.Новый(Regex.ПолучитьСсылку(),"[A-Za-z]+")); ШаблонСтроки=ъ(Врап.Новый(Regex.ПолучитьСсылку(),"\d+")); // Откроем файл Excel doc = ъ(SpreadsheetDocument.Open(ИмяФайла, false)); workbookPart = ъ(doc.WorkbookPart); // Строки хранятся отдельно // В ячейках хранится индекс pt=ъ(ъ(workbookPart.in(SharedStringTablePart.ПолучитьСсылку())).GetPartsOfType()); sstpart = ъ(pt.First()); sst = ъ(sstpart.SharedStringTable); ОбщиеСтроки=ъ(sst.ChildElements); workbook = ъ(workbookPart.Workbook); // Получим список страниц sheets = ъ(ъ(workbook.in(Sheet.ПолучитьСсылку())).Descendants()); sheets=ъ(Врап.ПолучитьЭнумератор(sheets.ПолучитьСсылку())); Пока sheets.MoveNext() Цикл sheet= ъ(sheets.Current); id=ъ(sheet.Id).Value; ИмяСтраницы=ъ(sheet.Name).Value; Сообщить(ИмяСтраницы); worksheetPart = ъ(workbookPart.GetPartById(id)); Worksheet=ъ(worksheetPart.Worksheet); // Так как данные хранятся только те которые имеют значения // Получим тз с колонками ИмяЯчейки,ИмяКолонки,НомСтроки,ЗначениеЯчейки //Где ИмяЯчейки= A1, ИмяКолонки=A,НомСтроки=1; Тз=ЗаписатьСтраницуВТЗ(Worksheet,ОбщиеСтроки); // через Найти используя ИмяЯчейки или // НайтиСтроки используя ИмяКолонки и НомСтроки // Получим таблицу с колонками A,B,D..AA,AB.. Тз=ПреобразоватьВТаблицу(Тз); Тз.ВыбратьСтроку(ИмяСтраницы); КонецЦикла КонецПроцедуры
Рассмотрим более подробно методы для получения данных о ячейках таблицы
Функция ИмяКолонки(ИмяЯчейки) //Получим Имя колнки ячейки match = ъ(ШаблонКолонки.Match(ИмяЯчейки)); return match.Value; КонецФункции // Можно можно эту тз проиндексировать и получать доступ к ячейкам Функция НомерСтроки(ИмяЯчейки) // Получим Номер строки ячейки match = ъ(ШаблонСтроки.Match(ИмяЯчейки)); return число(match.Value); КонецФункции Процедура ЗаписатьДанныеЯчейки(знач Тз,знач Ячейка,знач ОбщиеСтроки) Перем ТипДанных; // Получим адрес ячейки и Тип данных адрес=ъ(Ячейка.CellReference).InnerText; ТипДанных=Ячейка.DataType; ФлЕстьДанные=ложь; Если ТипДанных<> null Тогда ТипДанных=ъ(ъ(ТипДанных).Value); // Проверим тип данных на Строку Если ТипДанных.Equals(SharedString.ПолучитьСсылку()) Тогда //В CellValue хранится индек строки в таблице общих строк CellValue=ъ(ячейка.CellValue); Text=CellValue.Text; ssid = Число(Text); ChildElement=ъ(ОбщиеСтроки.get_Item(ssid)); ЗначениеЯчейки = ChildElement.InnerText; ФлЕстьДанные=истина; КонецЕсли; КонецЕсли; // Если это не строка то получим, то получим значение из CellValue Если не ФлЕстьДанные Тогда ЗначениеЯчейки= ячейка.CellValue; Если (ЗначениеЯчейки<> null) Тогда ЗначениеЯчейки=ъ(ЗначениеЯчейки); ЗначениеЯчейки=ЗначениеЯчейки.Text; ФлЕстьДанные=истина; КонецЕсли; КонецЕсли; Если ФлЕстьДанные Тогда Стр=Тз.Добавить(); Стр.ИмяЯчейки=адрес; Стр.ИмяКолонки=ИмяКолонки(адрес); Стр.НомСтроки =НомерСтроки(адрес); Стр.ЗначениеЯчейки=ЗначениеЯчейки; КонецЕсли; КонецПроцедуры Функция СоздатьТз() // Так как данные хранятся не ввиде таблицы // То создадим ТЗ с данными по ячейкам ТипЧисла = Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(10,0,ДопустимыйЗнак.Неотрицательный)); Тз=новый ТаблицаЗначений; Колонки=Тз.Колонки; Колонки.Добавить("ИмяЯчейки",ОписаниеСтроки()); Колонки.Добавить("ИмяКолонки",ОписаниеСтроки()); Колонки.Добавить("НомСтроки",ТипЧисла); Колонки.Добавить("ЗначениеЯчейки",ОписаниеСтроки()); возврат тз; КонецФункции Функция ЗаписатьСтраницуВТЗ(знач sheet,Знач ОбщиеСтроки) // Прочитаем все ячейки страницы cells = ъ(ъ(sheet.in(Cell.ПолучитьСсылку())).Descendants()); cells=ъ(Врап.ПолучитьЭнумератор(cells.ПолучитьСсылку())); Тз= СоздатьТз(); // Запишем данные ячейки в ТЗ Пока cells.MoveNext() Цикл Ячейка=ъ(cells.Current); ЗаписатьДанныеЯчейки(Тз,Ячейка,ОбщиеСтроки) КонецЦикла; возврат Тз; КонецФункции
Теперь нам нужно преобразовать ТЗ с данными о ячейках в Таблицу Здначений аналогичной Странице Excel
Функция ЗаписатьКолонки(Колонки,НачСтр,Разряд,КоличествоРазрядов,Сравнивать,ПоследняяКолонка) // Процедура создает колонки которые меньше или равны имени последней колоки // A,B,..,AA..ABC Для сч=КодСимвола("A") по КодСимвола("Z") Цикл НовСтр=НачСтр+Символ(сч); Если Разряд<КоличествоРазрядов Тогда рез= ЗаписатьКолонки(Колонки,НовСтр,Разряд+1,КоличествоРазрядов,Сравнивать,ПоследняяКолонка); Если Сравнивать и Рез Тогда возврат истина КонецЕсли; Иначе Колонки.Добавить(НовСтр,ОписаниеСтроки()); Если Сравнивать и НовСтр=ПоследняяКолонка Тогда возврат истина КонецЕсли КонецЕсли; КонецЦикла; возврат ложь; КонецФункции Процедура ��оздатьКолонки(Колонки,ПоследняяКолонка) // Создадим колонки учитывая разряды // Например если имя последней колоки ABC то колонки идут по разрядно //A..Z //AA..ZZ //AAA..ABC КоличествоРазрядов=СтрДлина(ПоследняяКолонка); Для сч=1 По КоличествоРазрядов Цикл Сравнивать=сч=КоличествоРазрядов; рез= ЗаписатьКолонки(Колонки,"",1,сч,Сравнивать,ПоследняяКолонка); Если Сравнивать и рез Тогда возврат; КонецЕсли; КонецЦикла; КонецПроцедуры Функция НайтиИмяПоследнейКолонки(Тз) рез=""; ДлинаРез=0; Для каждого стрТз из Тз Цикл Стр=стрТз.ИмяКолонки; СтрДл=СтрДлина(стр); Если СтрДл>ДлинаРез Тогда ДлинаРез=СтрДл; рез=Стр; ИначеЕсли СтрДл=ДлинаРез и Стр>рез Тогда рез=Стр; КонецЕсли; КонецЦикла; возврат рез; КонецФункции Функция ПреобразоватьВТаблицу(Тз) рез=новый ТаблицаЗначений; ПоследняяКолонка=НайтиИмяПоследнейКолонки(Тз); СоздатьКолонки(рез.Колонки,ПоследняяКолонка); Колонки=рез.Колонки; // Часто исползую данную функцию // Код можно посмотреть здесь http://infostart.ru/public/371762/ // Сгруппируем данные ТЗ по номеру строки Тз=глСгруппироватьТзПоПолю(тз,"НомСтроки"); сч=1; Для каждого стрТз из Тз Цикл НомСтроки=стрТз.НомСтроки; // Добавим строки номера которых меньше НомСтроки Пока сч<НомСтроки Цикл сч=сч+1; рез.Добавить(); КонецЦикла; сч=сч+1; стр=рез.Добавить(); ТзГр=стрТз.ТзПоГруппе; Для каждого стрТзГр из ТзГр Цикл // Можно конечно получить индекс зная смещение символа 64 относительно 1 и 26 разрядную систему // но найдем колонку по имени и её индекс Колонка=Колонки.Найти(стрТзГр.ИмяКолонки); стр.Установить(Колонки.Индекс(Колонка),стрТзГр.ЗначениеЯчейки); КонецЦикла; КонецЦикла; возврат рез; КонецФункции
Теперь перейдем к чтению данных файла Word.
Функция GetPlainText(знач Элемент) ЗаписьXML = Новый ЗаписьXML; ЗаписьXML.УстановитьСтроку(); // Получим секции и рекурсивно пройдемся по их значениям Секции=ъ(Элемент.Elements()); Секции=ъ(Врап.ПолучитьЭнумератор(Секции.ПолучитьСсылку())); Пока Секции.MoveNext() Цикл Секция= ъ(Секции.Current); ИмяСекции=Секция.LocalName; Если ИмяСекции= "t" Тогда Стр=Секция.InnerText; ЗаписьXML.ЗаписатьБезОбработки(Стр); ИначеЕсли ИмяСекции= "cr" или ИмяСекции= "br" Тогда ЗаписьXML.ЗаписатьБезОбработки(NewLine); ИначеЕсли ИмяСекции= "tab" Тогда ЗаписьXML.ЗаписатьБезОбработки(Таб); // Paragraph ИначеЕсли ИмяСекции= "p" Тогда ЗаписьXML.ЗаписатьБезОбработки(GetPlainText(Секция)); ЗаписьXML.ЗаписатьБезОбработки(NewLine+NewLine); Иначе ЗаписьXML.ЗаписатьБезОбработки(GetPlainText(Секция)); КонецЕсли; КонецЦикла; возврат ЗаписьXML.Закрыть(); КонецФункции Функция ПрочитатьWord(ИмяФайла) СборкаOpenXml=ъ(Врап.Сборка("DocumentFormat.OpenXml.dll")); WordprocessingDocument=ъ(СборкаOpenXml.GetType("DocumentFormat.OpenXml.Packaging.WordprocessingDocument")); Пакет = ъ(WordprocessingDocument.Open(ИмяФайла, ложь)); Элемент = ъ(ъ(ъ(Пакет.MainDocumentPart).Document).Body); if (Элемент = null) Тогда возврат "" КонецЕсли; возврат GetPlainText(Элемент); КонецФункции //
Очень удобно использовать Productivity Tool", она умеет генерировать код Генерируем OfficeOpenXML-документы за 5 минут
Кроме того есть множество провайдеров к различным базам данных, как MS SQL так и другим, в том числе NoSQL
Приведу пример доступа к MS SQL
СборкаSqlClient=ъ(Врап.Сборка("System.Data.SqlClient.dll")); SqlConnection=ъ(СборкаSqlClient.GetType("System.Data.SqlClient.SqlConnection")); SqlCommand=ъ(СборкаSqlClient.GetType("System.Data.SqlClient.SqlCommand")); connection =ъ(Врап.Новый(SqlConnection.ПолучитьСсылку(),ConnectionString)); connection.Open(); ТекстЗапроса = "Select Номенклатура.DESCR Наименование From sc84 Номенклатура where DESCR Like '%'+@Строка+'%' |order by Номенклатура.DESCR"; command = ъ(Врап.Новый(SqlCommand.ПолучитьСсылку(),ТекстЗапроса,connection.ПолучитьСсылку())); Parameters=ъ(command.Parameters); Parameters.AddWithValue("@Строка", "ДСП"); dr = ъ(command.ExecuteReader()); Пока dr.Read() Цикл Сообщить(dr.get_Item("Наименование")); КонецЦикла;
При этом можно сделать обертку DynamicObject над SqlDataReader и использовать так
Пока dr.Read() Цикл Сообщить(dr.Наименование); КонецЦикла;
В своих статьях я хочу донести прежде всего до 1С, что есть кроссплатформенная замена COM с помощью NetStadart. Но к моему большому сожалению пока данный подход никого не интересует. Привлекает внимание только Руслиш. Если у кого будут идеи чем можно привлечь внимание к замене COM пишите. Буду только рад.
Примеры и исходники можно скачать здесь.
