|
09.06.2006, 11:00 | #1 |
Участник
|
2 belugin
Насчет & и т.п. Excel нормально отрабатывает их присутствие в данных, единственно - если угловые скобки идут парой <> - то будет ошибка формата. Но вообще согласен - надо отрабатывать такие ситуации. Вот код функции, заменяющей спецсимволы в строке X++: str 1 entity[5]; str 6 entityReference[5]; str getEntities(str s1) { int j, pos; ; for (j=1;j<=5;j++) { pos = strscan(s1, entity[j], 1, strlen(s1)); while (pos) { s1 = substr(s1, 1, pos-1) + entityReference[j] + substr(s1, pos+1, strlen(s1)); pos = strscan(s1, entity[j], pos + 1, strlen(s1)); } } return s1; } ; entity[1] = "&"; entity[2] = "<"; entity[3] = ">"; entity[4] = "'"; entity[5] = '"'; entityReference[1] = "&"; entityReference[2] = "<"; entityReference[3] = ">"; entityReference[4] = "'"; entityReference[5] = """; .... buf += strfmt( ... ledgerTrans.RecId, getEntities(ledgerTrans.AccountNum), getEntities(ledgerTable.AccountName), ledgerTable.AccountPlType, ledgerTrans.BondBatchTrans_RU, ledgerTrans.BondBatch_RU, date2str(ledgerTrans.TransDate, 321, 2, 3, 2, 3, 4), getEntities(ledgerTrans.Txt), strltrim(strrem(num2str(ledgerTrans.AmountMST, 10, 2, 1, 0), "+")), ledgerTrans.Crediting, #toFile ? "" : (cnt mod 2 == 1 ? " ss:StyleID=\"s15\"" : " ss:StyleID=\"s16\""), cnt mod 2 == 1 ? " ss:StyleID=\"s12\"" : " ss:StyleID=\"s13\"", cnt mod 2 == 1 ? " ss:StyleID=\"s10\"" : " ss:StyleID=\"s11\"", #toFile ? (cnt mod 2 == 1 ? " ss:StyleID=\"s15\"" : " ss:StyleID=\"s16\"") : ""); ... PS упс. исправил
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 09.06.2006 в 11:43. |
|
13.06.2006, 12:12 | #2 |
Moderator
|
Коллеги, на самом деле, наш фестиваль-"мундиаль" различных способов экспорта Axapta => Excel продолжается. Приглашаю вас к активному участию.
Хотелось бы увидеть данные по CSV, DDE, Clipboard+PasteSpecial и др. Экспортеры всех видов, присоединяйтесь! P.S. (пока идёт чемпионат мира по футболу, слово "мундиаль" считается приличным ) |
|
13.06.2006, 19:19 | #3 |
Moderator
|
Ну, я сам немножко поковырялся... не с целью бития рекордов, а как раз наоборот – с целью небольшой разборки, направленной на выяснения некоторого предела низкой скорости - типа "медленнее которой остается только способ вписывания значений в ячейки Excel шариковой ручкой"
Абстрагируемся на некоторое время от точности получаемых результатов (я имею в виду, в частности, потенциальные проблемы с пресловутыми ведущими нулями в текстовых значениях, состоящих из цифр, а также потерю точности в длинных цифровых текстовых кодах, например, в 20-тизначных банковских счетах, где возможно обнуление последних 5 разрядов) и сосредоточимся исключительно на скорости вывода (пусть пока текст "000333" пишется в ячейку Excel как число 333, а дата "13.06.06" как число 38881 - просто тупо посмотрим на длительность всего процесса в целом). Способы, представленные AndyD и Recoilme, демонстрируют высокую скорость выгрузки. Задался вопросом: а как поведет себя на тестовом задании популярный класс ComExcelDocument_RU? Примерно представлял, что "фигово" (о низкой скорости уже "слышал" на Форуме). Но захотелось оценить меру "фиговости", поэтому обо всём по порядку. Этот класс в своем первозданном виде (слой DIS) предоставляет нам в распоряжение 2 своих метода, которые можно использовать для решения нашей тестовой задачи: 1. метод static str numToNameCell(int _iCol, int _iRow) - например, для получения текстового адреса ячейки "B1" по номеру строки = 1 и по номеру столбца = 2 2. метод public void insertValue(BookMark _bookMark, anyType _anyVal, int _workSheet = 1) - для записи значения в эту ячейку "B1". Набросал тестовый джоб следующего вида: X++: static void SpeedTest_Job1(Args _args) { LedgerTrans ledgerTrans; LedgerTable ledgerTable; ComExcelDocument_RU excel; int row; int timeFullStart, timeFullFinish, timeFullTotal; ; timeFullStart = timenow(); excel = new ComExcelDocument_RU(); excel.newFile("", true, -1); row = 0; while select ledgerTrans join ledgerTable where ledgerTrans.AccountNum == ledgerTable.AccountNum { row++; if (row > 50000) break; excel.insertValue(ComExcelDocument_RU::numToNameCell( 1, row), ledgerTrans.RecId); excel.insertValue(ComExcelDocument_RU::numToNameCell( 2, row), ledgerTrans.AccountNum); excel.insertValue(ComExcelDocument_RU::numToNameCell( 3, row), ledgerTable.AccountName); excel.insertValue(ComExcelDocument_RU::numToNameCell( 4, row), strfmt('%1', ledgerTable.AccountPlType)); excel.insertValue(ComExcelDocument_RU::numToNameCell( 5, row), ledgerTrans.BondBatchTrans_RU); excel.insertValue(ComExcelDocument_RU::numToNameCell( 6, row), ledgerTrans.BondBatch_RU); excel.insertValue(ComExcelDocument_RU::numToNameCell( 7, row), ledgerTrans.TransDate); excel.insertValue(ComExcelDocument_RU::numToNameCell( 8, row), ledgerTrans.Txt); excel.insertValue(ComExcelDocument_RU::numToNameCell( 9, row), ledgerTrans.AmountMST); excel.insertValue(ComExcelDocument_RU::numToNameCell(10, row), strfmt('%1', ledgerTrans.Crediting)); } timeFullFinish = timenow(); timeFullTotal = timeFullFinish - timeFullStart; info('Время выполнения, сек'); info(int2str(timeFullTotal)); } Время выполнения джоба - 3615 сек, т.е. практически ровно 1 час. Для сравнения: время выполнения на этом же компе джобов AndyD и Recoilme - 29 сек и 12 сек соответственно. Решил заглянуть внутрь этих двух методов класса ComExcelDocument_RU. Заглянул. Расстроился… Есть ощущение, что адресация к ячейкам воплощалась по принципу "Что вижу в Excel - о том пою. Как вручную работаю - так и запрограммирую. Вижу ячейки в первой строке Excel - A1, B1, C1... но, однако, смекаю, что вывод на лист, скорее всего, будет производиться в двух циклах: внешний - по строкам, тут всё в порядке: 1, 2, 3, 4, 5... и внутренний - по столбцам - здесь неудобство: порядок чисел-номеров колонок 1, 2, 3, 4, 5... нужно превращать в буквы А, B, C, D, E... С одной целью - чтобы потом сцепить букву столбца и цифру строки и выйти на какой-нибудь Range("A1"), и дальше через метод insertValue задать значение свойства Value2". Возникает вопрос: А ЗА-ЧЕМ так, мягко говоря, сложно? Со времен версии Excel 5 (1994 год) - первой версии Excel, когда вместо специфического макроязыка версии 4 пришёл Visual Basic - так вот, со времен версии 5 в Excel присутствует способ адресации к ячейкам листа при помощи метода Cells(номер строки, номер столбца), предназначенный как раз для нужд циклического перебора ячеек. Для обращения к прямоугольным диапазонам ячеек используется формат Range(Cells(1-я строка диапазона, 1-й столбец диап-на), Cells(посл. Строка диап-на, посл.столбец диап-на)) - а не только адресация вида Range("A1:H150"), как это пишет макрорекордер на VBA в Excel. Существуют другие полезные методы адресации, например, Offset... Набросал второй тестовый джоб: X++: static void SpeedTest_Job2(Args _args) { LedgerTrans ledgerTrans; LedgerTable ledgerTable; ComExcelDocument_RU excel; COM doc; COM actSheet; COM cells; int row; int timeFullStart, timeFullFinish, timeFullTotal; ; timeFullStart = timenow(); excel = new ComExcelDocument_RU(); excel.newFile("", true, -1); doc = excel.getComDocument(); actSheet = doc.ActiveSheet(); cells = actSheet.Cells(); row = 0; while select ledgerTrans join ledgerTable where ledgerTrans.AccountNum == ledgerTable.AccountNum { row++; if (row > 50000) break; COM::createFromVariant( cells.Item(row, 1) ).Value2( ledgerTrans.RecId ); COM::createFromVariant( cells.Item(row, 2) ).Value2( ledgerTrans.AccountNum ); COM::createFromVariant( cells.Item(row, 3) ).Value2( ledgerTable.AccountName ); COM::createFromVariant( cells.Item(row, 4) ).Value2( strfmt('%1', ledgerTable.AccountPlType) ); COM::createFromVariant( cells.Item(row, 5) ).Value2( ledgerTrans.BondBatchTrans_RU ); COM::createFromVariant( cells.Item(row, 6) ).Value2( ledgerTrans.BondBatch_RU ); COM::createFromVariant( cells.Item(row, 7) ).Value2( ledgerTrans.TransDate ); COM::createFromVariant( cells.Item(row, 8) ).Value2( ledgerTrans.Txt ); COM::createFromVariant( cells.Item(row, 9) ).Value2( ledgerTrans.AmountMST ); COM::createFromVariant( cells.Item(row, 10) ).Value2( strfmt('%1', ledgerTrans.Crediting) ); } timeFullFinish = timenow(); timeFullTotal = timeFullFinish - timeFullStart; info('Время выполнения, сек'); info(int2str(timeFullTotal)); } Опытные коллеги наверняка знают обо всем об этом. Обидно за новичков, которые приходят в Аксу, сталкиваются с ComExcelDocument_RU как с неким "стандартом де-факто" и первое время вынуждены идти по этому, как мне кажется, не совсем верному пути... Теряя это самое драгоценное время! |
|
|
За это сообщение автора поблагодарили: mazzy (5), DreamCreator (3), JeS (1), Silphidae (1). |
Теги |
benchmark, download, excel, faq, xml, законченный пример, производительность, экспорт/импорт |
|
|