Обсуждение:Вывод в Excel через XML (TFE) лайт версия
0 (0)
- Обсуждение:Вывод в Excel через XML (TFE) лайт версия ( Обсуждение примера 04.02.2020 15:54 )0(0)Быстрое создание отчётов в Excel, не сильно отличающееся от использования стандартной printLn. Использована идея KaMPiLeR по быстрому выводу в Excel через XML и добавлены простота и удобство использования.
Посмотреть пример
>> Ответить- Дополнительный пример ( Avantage 05.02.2020 12:00 )0(0)Внутри архива лежит также более реальный макрос для КФМ, который в случае затребования более подробной инфы по счетам, создаёт для каждого счёта, попадающего в список отловленных на первой странице, отдельный лист с операциями за данный период и привязывает к ячейке со счётом на первой странице ссылку на страницу с подробностями, а в первую ячейку страницы с подробностями впихивает обратную ссылку на ячейку со счётом на первой странице, чтобы пользователю не телепаться с поиском глазками среди кучи листов.
В первых строках private макроса MakeFile() есть пара закомментированных строк, позволяющая напрямую создать файл на локальной машине во временной папке. Возможно в вашей системе этот вариант будет более быстрым, чем создание файла на сервере в TXTFile, а затем перенос его на локал через copyfile(), как сделано (в моей системе это оказалось наоборот в разы дольше). Желающие поэкспериментированть не забудьте закомментить тот самый copyfile в конце макроса.
И спасибо огромное KaMPiLeRу за идею - скорость вывода в Excel возросла на порядок, если не больше, скорость написания макросов с выводом в Excel - тоже, и поскольку сам вызов Excel происходит когда сам файл уже полностью готов, то и пользователей перестали донимать коллизии, приводившие к невозможности работать в другом Excel-файле во время формирования нового из макроса, чтобы не помешать выводу.
>> Ответить- идея не нова - в похапе народ тож так делает - генерит xml потом отдает на скачку. ( KaMPiLeR 06.02.2020 10:23 )0(0)
- Да, с вордом так же можно. Я проверил. Но там проще взять готовый шаблон и делать подстановки. Типа: ( Avantage 06.02.2020 11:12 )2(1)
Import Bankinter, rsexts, rcw;
/*─────────────────────────────────────────────────────────────────────────┐
│ Процедура для импорта при необходимости вывести что-то в ворд по шаблону│
│ Шаблон копируется в локальную папку временных файлов, открывается в Word│
│ и делается замена попарно │
│ Пример: DoWord("..\\TXTFILE\\SHABLON\\Dog1.dot", │
│ "@NumDog@", _NumDog, │
│ "@DatDog@", String(_DogDat), │
│ "@FIOclient@",_clFIO); // число пар замен не ограничено │
│ │
└─────────────────────────────────────────────────────────────────────────*/
macro DoWord(_ShablonTName)
var _ms,_wrd, _fso, _Doc, _fName, _fExt, _dir, _dat0=date(0,0,0), _tim0=Time(0,0,0), _dat1=date(0,0,0), _tim1=time(0,0,0);
SplitFile(_ShablonTName, _fName, _fExt);
_ms = CreateObject ("rsax","TRsAxServer","RsAxServer",IsStandAlone());
_fso = _ms.CreateComObject ("Scripting.FileSystemObject", False);
// Проверяем наличие шаблона
_dir = TDIRLIST(_shablonTName,"F");
if (_dir.count <= 0)
MsgBox("Отсутствет шаблон:|" + _ShablonTName + "|обратитесь в IT отдел");
return;
else
_dat0 = _dir.fDate(0);
_tim0 = _dir.fTime(0);
end;
_fName = MergeFile(_fso.GetSpecialFolder(2).path, _fName, _fExt); //скопируем его на локал в системную папку временных файлов данного юзверя
if (not _fso.FileExists(_fname)) // если там нет такого же - просто копируем
if (not copyFile(_ShablonTName, "$"+_fName ))
MsgBox("Hе удалось перенести шаблон на локальный компьютер!|из|" +_ShablonTName+"|в|"+_fname);
end;
else // если там есть уже такой
DtTmSplit(_fso.GetFile(_fName).DateLastModified, _Dat1, _Tim1);
if ((_dat1 != _dat0) or (_tim1 != _Tim0)) // если время или дата файлов не совпадают - копируем
if (not copyFile(_ShablonTName, "$"+_fName ))
MsgBox(String("Hе удалось перенести ИЗМЕНИВШИЙСЯ шаблон на локаль:|из [",_dat0:f,"] (",_tim0:f,")|"
,_ShablonTName,"|в [",_dat1:f,"] (",_tim1:f,")|",_fname));
end;
end;
end;
_wrd = _ms.CreateComObject ("Word.Application", False);
_wrd.WindowState=1;
_Doc=_wrd.Documents.Add(_fName, False);
_wrd.Visible = False;
_wrd.ActiveWindow.View=1;
var _ShabWord="", _SubstWord="", _ii=0;
for (_ii,2,ParmCount(), 2)
GetParm(_ii-1, _ShabWord);
GetParm(_ii, _SubstWord);
_doc.Content.Find.Execute(_ShabWord, False, False, False, False, False, True, 1, False, _SubstWord, 2);
end;
_wrd.ActiveWindow.View.Type=3;
_wrd.Visible = True;
_fso = _doc = _wrd = _ms = null;
end;
>> Ответить- Слегка поправленная версия: ( НоскиПоэта 25.10.2021 13:05 )0(0)
/* TurboFileExcel - Lite версия Автор идеи: KaMPiLeR, допиливание Avantage, Носки Поэта
Быстрое создание Excel файла через запись xml на сервере, а затем копирование его на локал с последующим открытием и созхранением в Excel на локале
Использование: xxx=TFE("ИмяЛиста") , где ИмяЛиста - название первого листа с Strlen() <= 31
Основные функции:
.ColSizes("строка") - задание ширин столбцов в одной строке через запятую. Если первой стоит буква F и после неё число - это номер строки в которой будет автофильтр.
Если после F нет числа, а сразу запятая - автофильтр ставится по строке ограничения области прокрутки (см. SplitRow)
.SplitRow(номер) - задание номера строки для области прокрутки (не обязательно). Если есть хоть один заголовок ("H^") то строка для ограничения области прокрутки задаётся по нему.
.SplitCol(номер) - задание номера колонки для области прокрутки (не обязательно).
.AddRow(Зачение1, Значение2, Значение3, ...) - заполнение строки таблицы значениями. Значения желательно указвать в виде строки "ФОРМАТ^Значение". Типы ФОРМАТОВ описаны ниже.
.Go(ИмяФайла) - Собственно создание, перенос и открытие файла в папке временных файлов данного пользователя (если не указан полный локальный путь)
Если в ИмяФайла первым символом поставить "$" - файл будет создан и открыт в локальной папке "Мои Документы" данного пользователя.
Если первым символом поставить "#" - файл будет создан в локальной папке "Мои Документы", но открываться не будет. Используется для пакетного создания кучи файлов.
Если перед именем файла указаны подпапки (Типа: "$From_RS\\Клиенты\\1111\\2222\\ИмяФайла" - нужное дерево папок будет создано "Моих Документах", и файл ляжет в нужную.
.AddSheet("ИмяЛиста") - добавляет новый лист с заданным именем и делает его активным
.ActiveSheet(Номер) - делает текущим лист с заданным номером и все дальнейшие действия будут с ним. Возвращает текущий лист в виде объекта, даже если номер не задан.
ФОРМАТ для .AddRow() может состоять из следующих символов:
Типы Формата:
Задаются в строке перед собственно значением и отделяются от него знаком ^
#: - вокруг ячейки обводится решётка
_: - под ячейкой проводится линия границы
Nx: (x- цифра от 1 до 9) - число с "x" знаками после запятой. Если "x" нет, то по умолчанию 2 знака после запятой. Вместо N0 используйте I.
I: Целое число ( аналог N0)
D: Дата
T: время
S: Строка
W: строка с переносом
C: (center) - горизонтальное центрирование
L: (left) - горизонтальное выравнивание влево
R: (Right) - горизонтальное выравнивание вправо
U: (Up) - вертикальное выравнивание по верху (по умолчанию вериткальное выравнивание по нижней границе ячейки)
Ц: (Центр) - вертикальное выравнивание по центру
B: Bold (жирный шрифт)
Шxx: Размер шрифта xx, например Ш15 = выводить в эту ячейку шрифтом с размером 15 (по умолчанию размер шрифта = 11)
H: полный аналог BWC# - применяется для стандартных заголовков колонок таблицы. Если в строке встретился формат H - по данной строке будет автоматически выставлен SplitRow
M: Фон ячейки розовый (magenta)
G: Фон ячейки зелёный
Y: Фон ячейки жёлтый
Есть ещё 2 типа для объединения ячеек, но, если есть возможность их не использовать - лучше не использовать, поскольку объединение мешает дальнейшей работе фильтров
MLx: Объединить с левой ячейкой. Может использоваться несколько раз подряд. Информация и форматирование берутся из самой-самой левой ячейки
MU: Объединить с верхней ячейкой. Тоже может использоваться несколько раз подряд друг под другом. Информация и форматирование берутся из самой-самой верхней ячейки
И есть тип для ссылки из данной ячейки на лист, на конкретную ячейку другого листа, на конкретную ячейку данного листа
@...@ : Ссылка должна быть заключена между собаками. Это может быть @ИмяЛиста@, или @ИмяЛиста!НомерЯчейки@ или просто @!НомерЯчейки@ - если она на этом же листе
Если ссылка идёт в конце стиля, непосредственно перед ^ - тогда финальную собаку можно не ставить.
*/
import Globals, rsexts, rslx, rcw;
private const NumMask=String(V_DOUBLE,",",V_DOUBLEL,",",V_DECIMAL,",",V_NUMERIC,",",V_MONEY,",",V_MONEYL);
private macro GetGUIDFileName // ну очень уникальное имя для файла.
return strsubst(Substr(ActiveX("Scriptlet.TypeLib").guid,2,36), "-", "");
end;
macro GetLocalTmpPath // путь к локальной папке временных файлов данного пользователя
return CreateObject ("rsax","TRsAxServer","RsAxServer",IsStandAlone()).CreateComObject("Scripting.FileSystemObject").GetSpecialFolder(2).Path;
end;
macro CheckLocalFolder(_dir) // Проверка наличия и досоздание папок в полном пути к локальной папке данного пользователя
var _FSO = CreateObject("rsax","TRsAxServer","RsAxServer",IsStandAlone()).CreateComObject("Scripting.FileSystemObject");
var _ret = _FSO.FolderExists(_dir);
if (not _ret)
_FSO.CreateFolder(_dir);
_ret = _FSO.FolderExists(_dir);
end;
_FSO = null;
return _ret;
end;
macro GetLocalDocumentsPath //Получить путь к папке "Мои Документы" данного пользователя на случай если хочется сохранять в "Мои документы" локального пользователя
return CreateObject ("rsax","TRsAxServer","RsAxServer",IsStandAlone()).CreateComObject("wScript.Shell").SpecialFolders("MyDocuments");
end;
private macro GoToWindow(_winName)
return CreateObject ("rsax","TRsAxServer","RsAxServer",IsStandAlone()).CreateComObject("wScript.Shell").AppActivate(_winName);
end;
macro CopyFile2Local(_FromFullName, _toFullNewName) //быстрое копирование файла на локал через упаковку в zip, копирование уже архива на локал и распаковку.
var _zf, _zn,_zp, _fP="", _fn="", _fx="", _fz="";
if (not ExistFile(_fromFullname))
return false;
end;
_fP = SplitFile(_FromFullName, _fn, _fx);
_fn = _fn + _fx;
_zn = GetGuidFileName() +".zip";
_zp = MergeFile(_fp,_zn);
_zf = CreateZip(_zp);
if (ZipAdd(_zf,_fn,_FromFullName))
CloseZip(_zf);
_fP = SplitFile(_toFullNewName, _fz,_fx);
if (copyFile(_zp,_fp +"\\"+_zn,True, "Копирую на локаль"))
RemoveFile(_zp);
if (Substr(_toFullNewName,1,1) == "$") // если в направлении КУДА указан Локальный путь ($ в начале пути)
_fp = Substr(_fp,2);
CreateObject ("rsax","TRsAxServer","RsAxServer",False).CreateComObject("Shell.Application").NameSpace(_fp).CopyHere(MergeFile(_fp,_zn+"\\"+_fn),16);
_fp = "$" +_fp;
else // если указан путь от сервера RS-Bank
if (not UnzipItem(_zf,0,MergeFile(_fp,_fn)))
return False;
end;
end;
RemoveFile(MergeFile(_fp,_zn));
renameFile(MergeFile(_fp,_fn), _toFullNewName);
return True;
end;
end;
return False;
end;
private class TFESheet; // собсно рабочий класс листа
var
name : string="Лист1",//название листа
data = TArray(),
lSplitRow : Integer=0, //последняя строка заголовка - строки под ней будут скроллироваться
lSplitCol : Integer=0, //последняя колонка заголовка - колонки правее неё будут скроллироваться
cSize : String=""; //ширины колонок
end;
class TFE(aFirstSheetName: string); //рабочий класс всей таблицы совсеми листами
private var
fileName: string,
ffout,
sheets=TArray,
Styles:string="^",
iSheet:integer=0;
macro ActiveSheet(_NewSheetNum): TFESheet; // Функция, которая делает активным и возвращает лист с заданным номером. Если такого номера ещё нет, то добавляет его
if (valType(_NewSheetNum) == V_INTEGER)
if ((_newSheetNum > 0) and (_NewSheetNum <= sheets.Size))
iSheet = _newSheetNum;
end;
end;
if(iSheet==0)
return NULL;
else
return sheets[iSheet-1];
end;
end;
private macro NormalizeStr(_str) // замена спецсимволов xml в строке
return StrSubst(StrSubst(StrSubst(_str, "<", "<"), ">", ">"), "\"",""");
end;
private Macro NeedLandscape(_str) //вычисление по суммарной длине колонок - ненастолько ли наша таблица широка, что её пора уже печатать на горизонтально развёрнутых листах
const SizeForNeedLandscape = 600;
var _ii=0, _size=0;
if (Strlen(_str) < 3) return False; end;
_ii = index(_str,",");
while (_ii > 0)
_size = _size + int(Trim(Substr(_str,1,_ii-1)));
if (_size > SizeForNeedLandscape)
return True;
end;
_str = trim(Substr(_str,_ii+1));
_ii = index(_str,",");
end;
_size = _size + int(_str);
if (_size > SizeForNeedLandscape)
return True;
end;
return False;
end;
Private macro ssType(_str)
if ((index(_str, "N") > 0) or (index(_str,"I") > 0))
return "Number";
elif ((index(_str, "S") > 0) or (index(_str,"W") > 0) or (index(_str,"H") > 0))
return "String";
elif ((index(_str, "D") > 0) or (index(_str,"T") > 0))
return "DateTime";
end;
return "String";
end;
Private macro PrintCell(_aData, _indexStr)
var _Format:String="", _ii:integer, _RefStr="", _MergeStr="";
if (ValType(_aData) != V_STRING)
return;
end;
_ii = index(_aData, "^");
if (_ii <= 0)
ffout.WriteLine(String(" <Cell><Data ss:Type=\"String\">",NormalizeStr(_aData),"</Data></Cell>"));
else
_format = trim(substr(_aData,1,_ii-1));
_aData = trim(substr(_aData,_ii+1));
_ii = index(_format,"@");
if (_ii > 0)
_RefStr = Substr(_format,_ii+1);
_format = Substr(_format,1,_ii-1);
_ii = Index(_refStr,"@");
if ( _ii > 0)
if (_ii < StrLen(_refStr))
_Format = _format + Substr( _refStr,_ii+1);
end;
_refStr = Substr(_refStr,1,_ii-1);
end;
_ii = index(_refStr,"!"); // есть ли ссылка на конкретную ячейку ??
If (_ii <= 0) // нет, ссылка на лист
_refStr = _refStr + "!A1"; // добавим ссылку на ячеёку.
elif (_ii == 1) // ссылка на ячеку на данном листе
_refStr = Substr(_refStr,2);
end;
if (StrLen(_refStr) > 0)
_refStr = " ss:HRef=\"#" + _refStr + "\"";
end;
end;
if (Index(_format, "M") > 0)
if (index(_format,"ML") > 0)
return True;
elif (index(_format,"MU") > 0)
return False;
elif (index(_format,"MR") == 1)
_format = substr(_format,3);
while (StrIsNumber(substr(_format,1,1)))
_MergeStr = _mergeStr + substr(_format,1,1);
_format = Substr(_format,2);
end;
_MergeStr = String(" ss:MergeAcross=\"",_MergeStr,"\"");
elif (index(_format,"MD") == 1)
_format = substr(_format,3);
while (StrIsNumber(substr(_format,1,1)))
_MergeStr = _mergeStr + substr(_format,1,1);
_format = Substr(_format,2);
end;
_MergeStr = String(" ss:MergeDown=\"",_MergeStr,"\"");
end;
end;
if (index(_format,"D") > 0)
if (CompareStrWithMasks("??.??.????",_adata) == 0)
_aData = Substr(_aData,7,4) + "-" + Substr(_aData,4,2) + "-" + Substr(_aData,1,2) + "T00:00:00";
elif (CompareStrWithMasks("?.??.????",_adata) == 0)
_aData = Substr(_aData,6,4) + "-" + Substr(_aData,3,2) + "-0" + Substr(_aData,1,1) + "T00:00:00";
end;
elif (index(_format,"T") > 0)
if (CompareStrWithMasks("??:??*",_adata) == 0)
_aData = "1900-01-01T" + _aData;
elif (CompareStrWithMasks("?:??*",_adata) == 0)
_aData = "1900-01-01T0" + _aData;
end;
end;
if (_format == "")
if (_aData == "")
return False; //пропустим эту ячейку
end;
ffout.WriteLine( String(" <Cell",_indexStr,_MergeStr,_RefStr,"><Data ss:Type=\"String\">",NormalizeStr(_aData),"</Data></Cell>"));
elif (_aData == "")
ffout.WriteLine( String(" <Cell",_indexStr,_MergeStr,_RefStr," ss:StyleID=\"",_format,"\"/>"));
elif (substr(_aData,1,1) == "=")
ffout.WriteLine( String(" <Cell",_indexStr,_MergeStr,_RefStr," ss:StyleID=\"",_format,"\" ss:Formula=\"",NormalizeStr(_aData),"\"><Data ss:Type=\"",ssType(_format),"\"/></Cell>"));
else
ffout.WriteLine( String(" <Cell",_indexStr,_MergeStr,_RefStr," ss:StyleID=\"",_format,"\"><Data ss:Type=\"",ssType(_format),"\">",NormalizeStr(_aData),"</Data></Cell>"));
end;
end;
return True;
end;
Private macro PrintStyle(_str)
var _ssAlign="", _ssFont="", _nn=0;
ffout.WriteLine(String(" <Style ss:ID=\"",_str,"\">"));
if ((index(_str,"#") > 0) or (index(_str,"H") > 0))
ffout.WriteLine(" <Borders>");
ffout.WriteLine(" <Border ss:Position=\"Bottom\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>");
ffout.WriteLine(" <Border ss:Position=\"Left\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>");
ffout.WriteLine(" <Border ss:Position=\"Right\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>");
ffout.WriteLine(" <Border ss:Position=\"Top\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>");
ffout.WriteLine(" </Borders>");
elif (index(_str,"_") > 0)
ffout.WriteLine(" <Borders>");
ffout.WriteLine(" <Border ss:Position=\"Bottom\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>");
ffout.WriteLine(" </Borders>");
end;
if ((index(_str,"C") > 0) or (index(_str,"H")>0))
_ssAlign = _ssAlign + " ss:Horizontal=\"Center\"";
elif (index(_str,"L") > 0)
_ssAlign = _ssAlign + " ss:Horizontal=\"Left\"";
elif (index(_str,"R") > 0)
_ssAlign = _ssAlign + " ss:Horizontal=\"Right\"";
end;
if ((index(_str,"U") > 0) and (index(_str,"MU") <= 0))
_ssAlign = _ssAlign + " ss:Vertical=\"Top\"";
elif (index(_str,"Ц") > 0)
_ssAlign = _ssAlign + " ss:Vertical=\"Center\"";
end;
if ((index(_str,"W") > 0) or (index(_str,"H")>0))
_ssAlign = _ssAlign + " ss:WrapText=\"1\"";
end;
if (_ssAlign != "")
ffout.WriteLine(String(" <Alignment",_ssAlign,"/>"));
end;
_ssFont = "";
_nn = index(_str,"Ш");
if ( _nn > 0)
_nn = Int(Substr(_str,_nn+1,2));
if (_nn > 4)
_ssFont = String(" ss:Size=\"",_nn,"\"");
end;
end;
_nn = 0;
if ((index(_str,"B") > 0) or (index(_str,"H")>0))
_ssFont = _ssFont + " ss:Bold=\"1\"";
end;
if (_ssFont != "")
ffout.WriteLine(" <Font" + _ssFont + "/>");
end;
if (index(_str,"M") > 0)
ffout.writeline(" <Interior ss:Color=\"#FF007F\" ss:Pattern=\"Solid\"/>");
elif (index(_str,"Y") > 0)
ffout.writeline(" <Interior ss:Color=\"#FFFF00\" ss:Pattern=\"Solid\"/>");
elif (index(_str,"G") > 0)
ffout.writeline(" <Interior ss:Color=\"#007F00\" ss:Pattern=\"Solid\"/>");
end;
_nn = index(_str,"N");
if (_nn > 0)
if ((_nn < StrLen(_str)) and (StrIsNumber(Substr(_str,_nn+1,1))))
_nn = int(Substr(_str,_nn+1,1));
if (_nn == 0)
ffout.writeline(" <NumberFormat ss:Format=\"#,##0\"/>");
else
ffout.writeline(" <NumberFormat ss:Format=\"#,##0."+MkStr("0",_nn)+"\"/>");
end;
else
ffout.writeline(" <NumberFormat ss:Format=\"Standard\"/>");
end;
elif (index(_str,"I") > 0)
ffout.writeline(" <NumberFormat ss:Format=\"#,##0\"/>");
elif ((index(_str,"S") > 0) or (index(_str,"W") > 0))
ffout.writeline(" <NumberFormat ss:Format=\"@\"/>");
elif (index(_str,"D") > 0)
ffout.writeline(" <NumberFormat ss:Format=\"Short Date\"/>");
elif (index(_str,"T") > 0)
ffout.writeline(" <NumberFormat ss:Format=\"Short Time\"/>");
else
ffout.writeline(" <NumberFormat ss:Format=\"@\"/>");
end;
ffout.WriteLine(" </Style>");
end;
macro ColSizes(_str)
ActiveSheet.cSize=StrSubst(_str," ","");
end;
Private macro AddStyle(_str)
var _ii:integer, _ch:string, _ret="";
_str = StrUpr(StrSubst(_str," ",""));
if (StrLen(_str) > 0)
if (index(Styles , "^"+_str+"^")<=0)
Styles = Styles + _str + "^";
end;
end;
end;
Private macro AddMergeLeft(_row, _col, _count)
var _ii=0, _str;
for (_ii,_col-1,0,-1)
_str = ActiveSheet.Data[_row][_ii];
if (index(_str,"ML") <= 0)
if (index(_str,"MR") == 1)
_str = Substr(_str,4);
while (StrIsNumber(substr(_str,1,1)))
_str = Substr(_str,2);
end;
end;
_str = String("MR",_col - _ii+_count-1, _str);
ActiveSheet.Data[_row][_ii] = _str;
break;
end;
end;
for (_ii,0,_count-1,1)
ActiveSheet.Data[_row][_col+_ii]="ML^";
end;
end;
Private macro AddMergeUp(_row, _col)
var _ii=0, _str;
for (_ii,_row-1,0,-1)
_str = ActiveSheet.Data[_ii][_col];
if (index(_str,"MU") <= 0)
if (index(_str,"MD") == 1)
_str = Substr(_str,4);
while (StrIsNumber(substr(_str,1,1)))
_str = Substr(_str,2);
end;
end;
_str = String("MD",_row - _ii,_str);
ActiveSheet.Data[_ii][_col] = _str;
break;
end;
end;
ActiveSheet.Data[_row][_col]="MU^";
end;
private macro AddCell( _aData)
var _format="",_ref="";
var _ii:integer = ValType(_aData);
if (_ii == V_ARRAY)
for (_ii, 0, aSize(_aData)-1,1)
AddCell(_aData(_ii));
end;
elif (_ii == V_GENOBJ) //TARRAY
for (_ii, 0, _aData.Size-1,1)
AddCell(_aData[_ii]);
end;
elif (_ii == V_DATE)
AddCell(String("D^",_aData:f));
elif (_ii == V_TIME)
AddCell(String("T^",_aData:f));
elif (_ii == V_INTEGER)
AddCell(String("I^",_aData));
elif (CompareStrWithMasks(NumMask,String(_ii)) == 0)
AddCell(String("N^",_aData:0:2));
elif (_ii == V_STRING)
_ii = index(_aData,"^");
if (_ii > 0)
_format = Substr(_aData,1,_ii-1);
_ii = index(_format,"@");
if (_ii > 0)
_ref = Substr(_format,_ii+1);
_format = Substr(_format,1,_ii-1);
_ii = index(_ref,"@");
if ((_ii > 0) and (_ii < StrLen(_ref)))
_format = _format + Substr(_Ref,_ii+1);
end;
end;
_ii = index(_format,"ML");
if (_ii>0)
if (not StrIsNumber(Trim(Substr(_format,_ii+2,2))))
_ii = 1;
else
_ii = Int(Trim(Substr(_format,_ii+2,2)));
end;
AddMergeLeft(ActiveSheet.data.Size-1,ActiveSheet.data[ActiveSheet.data.Size-1].Size, _ii);
return;
elif (index(_format,"MU")>0)
AddMergeUp(ActiveSheet.data.Size-1,ActiveSheet.data[ActiveSheet.data.Size-1].Size);
return;
elif (index(_format,"H")>0)
if (ActiveSheet.lSplitRow < ActiveSheet.data.Size)
ActiveSheet.lSplitRow = ActiveSheet.data.Size;
end;
end;
AddStyle(_format);
end;
ActiveSheet.data[ActiveSheet.data.Size-1][ActiveSheet.data[ActiveSheet.data.Size-1].Size]=_aData;
end;
end;
macro AddRow;
ActiveSheet.data[ActiveSheet.data.Size]=TArray;
var _ii: integer, _jj:integer, _iCol:integer=0, _aData;
for (_ii,1, ParmCount()-1, 1) // внутри объектов параметры должны начинаться с 1. А getparm(0) - ссылка на сам объект
if (GetParm(_ii, _adata))
AddCell( _aData);
end;
end;
end;
Private macro GetAllStringCount: integer;
var _ii: integer,
_ret:integer=0;
for (_ii,0,sheets.Size-1,1)
_ret=_ret+sheets[_ii].data.Size;
end;
return _ret;
end;
macro SplitRow(_RowNum)
ActiveSheet.lSplitRow = _RowNum;
end;
macro SplitCol(_ColNum)
ActiveSheet.lSplitCol = _ColNum;
end;
macro AddSheet(aName: string);
if(aName==null)
aName=string("Лист", sheets.Size+1);
end;
if(strlen(aName)>31)
RunError ("Длинна названия листа не может превышать 31 символ");
end;
sheets[sheets.Size]=TFESheet;
iSheet = sheets.Size;
//начальные значения
ActiveSheet.Name=aName;
end;
macro MakeFile(_xlsFilename, _zoom);
var _ii: integer, _jj:integer, _tStyle:string, _tData, _afRow=0, _afrange = "",
_shI: integer, _cnt = 0, _NotSkipped =True, _ffName;
// _ffName = GetLocalTmpPath() + "\\"+FileName + ".xml";
// ffout = CreateObject("rsax","TRsAxServer","RsAxServer",IsStandAlone()).CreateComObject("Scripting.FileSystemObject").CreateTextFile(_ffName,True,True);
_ffName=GetTxtFilename(FileName);
ffout =TSTREAMDOC(_ffName,"W","utf8");
// заголовки xml-файла
ffout.writeline("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
ffout.writeline("<?mso-application progid=\"Excel.Sheet\"?>");
ffout.writeline("<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"");
ffout.writeline(" xmlns:o=\"urn:schemas-microsoft-com:office:office\"");
ffout.writeline(" xmlns:x=\"urn:schemas-microsoft-com:office:excel\"");
ffout.writeline(" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"");
ffout.writeline(" xmlns:html=\"http://www.w3.org/TR/REC-html40\">");
ffout.writeline(" <ExcelWorkbook xmlns=\"urn:schemas-microsoft-com:office:excel\">");
ffout.writeline(" <ProtectStructure>False</ProtectStructure>");
ffout.writeline(" <ProtectWindows>False</ProtectWindows>");
ffout.writeline(" </ExcelWorkbook>");
ffout.writeline(" <Styles>");
ffout.writeline(" <Style ss:ID=\"Default\" ss:Name=\"Normal\">");
ffout.writeline(" <Alignment ss:Vertical=\"Bottom\"/>");
ffout.writeline(" <Borders/>");
ffout.writeline(" <Font ss:FontName=\"Times New Roman\" x:CharSet=\"204\" ss:Size=\"11\" ss:Color=\"#000000\"/>");
ffout.writeline(" <Interior/>");
ffout.writeline(" <NumberFormat/>");
ffout.writeline(" <Protection/>");
ffout.writeline(" </Style>");
_tStyle = trim(Substr(Styles,2));
_ii = index(_tStyle,"^");
while (_ii > 1)
PrintStyle(Substr(_tStyle,1,_ii-1));
_tStyle = Trim(Substr(_tStyle,_ii+1));
_ii = index(_tStyle,"^");
end;
ffout.writeline(" </Styles>");
//вывели все стили...
_shI=0;
InitProgress(GetAllStringCount, "", "Формирую файл отчёта...");
_cnt = 0;
for (_shI,0,sheets.Size-1,1)
ffout.writeline(" <Worksheet ss:Name=\""+sheets[_shI].Name+"\">");
ffout.writeline(" <Table>");
_tStyle = sheets[_shI].cSize;
_afRow = 0; _afrange = "";
if (Substr(_tStyle,1,1) == "F") // надо поставить автофильтр
_tStyle = Trim(Substr(_tStyle,2));
_ii = index(_tStyle,",");
if (_ii > 1)
_afRow = Int(substr(_tStyle,1,_ii-1));
end;
_tStyle = Trim(Substr(_tStyle,_ii+1));
if (_afRow <= 0)
_afRow = sheets[_shI].lSplitRow;
end;
if (_afRow > 0)
if (sheets[_shI].lSplitCol == 0)
_afRange = String("R", _afRow,"C1:R",_afRow,"C",sheets[_shI].Data[_afRow-1].Size);
else
_afRange = String("R", _afRow,"C",sheets[_shI].lSplitCol,":R",_afRow,"C",sheets[_shI].Data[_afRow-1].Size);
end;
end;
end;
_ii = index(_tStyle,",");
while (_ii > 0)
ffout.WriteLine(String(" <Column ss:Width=\"",trim(Substr(_tStyle,1,_ii-1)),"\"/>"));
_tStyle = trim(Substr(_tStyle,_ii+1));
_ii = index(_tStyle,",");
end;
ffout.WriteLine(String(" <Column ss:Width=\"",_tStyle,"\"/>"));
// Таблица
for (_ii, 0, sheets[_shI].data.Size-1, 1)
ffout.writeline(" <Row>");
_NotSkipped = True;
for (_jj,0,sheets[_shI].data[_ii].Size-1,1)
_tData = sheets[_shI].data[_ii][_jj];
if ((index(_tData,"{UPROW}") > 0) and (index(_tData, "^=")>0)) //это формула и упрощенное обозначение всего столбца над этой ячейкой
_tData = StrSubst(_tData,"{UPROW}",String("R[",sheets[_shI].lSplitRow-_ii,"]C:R[-1]C"));
end;
if (_notSkipped)
_notSkipped = PrintCell( _tData,"");
else
_notSkipped = PrintCell( _tData,String(" ss:Index=\"",_jj+1,"\""));
end;
end;
ffout.writeline(" </Row>");
UseProgress(_cnt=_cnt+1);
end;
ffout.writeline(" </Table>");
ffout.writeline(" <WorksheetOptions xmlns=\"urn:schemas-microsoft-com:office:excel\">");
if (NeedLandscape(sheets[_ShI].cSize))
ffout.writeline(" <PageSetup>");
ffout.writeline(" <Layout x:Orientation=\"Landscape\"/>");
ffout.writeline(" <Header x:Margin=\"0.3\"/>");
ffout.writeline(" <Footer x:Margin=\"0.3\"/>");
ffout.writeline(" <PageMargins x:Bottom=\"0.75\" x:Left=\"0.25\" x:Right=\"0.25\" x:Top=\"0.75\"/>");
ffout.writeline(" </PageSetup>");
ffout.writeline(" <FitToPage/>");
ffout.writeline(" <Print>");
ffout.writeline(" <FitHeight>0</FitHeight>");
ffout.writeline(" <PaperSizeIndex>9</PaperSizeIndex>");
ffout.writeline(" </Print>");
end;
if (String(_zoom) != "100")
ffout.writeline(String(" <Zoom>",_zoom,"</Zoom>"));
end;
ffout.writeline(" <Selected/>");
ffout.writeline(" <FreezePanes/>");
ffout.writeline(" <FrozenNoSplit/>");
if (sheets[_ShI].lSplitRow > 0)
ffout.writeline(" <SplitHorizontal>"+string(sheets[_shI].lSplitRow)+"</SplitHorizontal>");
ffout.writeline(" <TopRowBottomPane>"+string(sheets[_shI].lSplitRow)+"</TopRowBottomPane>");
end;
if (sheets[_ShI].lSplitCol > 0)
ffout.writeline(" <SplitVertical>"+string(sheets[_shI].lSplitCol)+"</SplitVertical>");
ffout.writeline(" <LeftColumnRightPane>"+string(sheets[_shI].lSplitCol)+"</LeftColumnRightPane>");
end;
if ((sheets[_ShI].lSplitRow > 0) or (sheets[_ShI].lSplitCol > 0))
ffout.writeline(" <ActivePane>2</ActivePane>");
ffout.writeline(" <Panes>");
ffout.writeline(" <Pane>");
ffout.writeline(" <Number>2</Number>");
ffout.writeline(" <ActiveRow>"+String(sheets[_shI].lSplitRow)+"</ActiveRow>");
ffout.writeline(" </Pane>");
ffout.writeline(" </Panes>");
end;
ffout.writeline(" <ProtectObjects>False</ProtectObjects>");
ffout.writeline(" <ProtectScenarios>False</ProtectScenarios>");
ffout.writeline(" </WorksheetOptions>");
if (_afRange != "")
ffout.writeline(String(" <AutoFilter x:Range=\"", _afRange,"\" xmlns=\"urn:schemas-microsoft-com:office:excel\"/>"));
end;
ffout.writeline(" </Worksheet>");
end;
RemProgress();
ffout.writeline("</Workbook>");
ffout = null;
copyFile2Local(_ffname,"$"+GetLocalTmpPath()+"\\"+fileName+".xml");
end;
private macro OpenFile(_XlsName, _WhatToDo, _passw);
var xls= CreateObject ("rsax","TRsAxServer","RsAxServer",IsStandAlone()).CreateComObject("Excel.Application",true);
var _ii = 0, _locPath=GetLocalTmpPath();
xls.Workbooks.open(GetLocalTmpPath()+"\\"+fileName+".xml");
xls.Sheets(1).Activate;
if (ValType(_xlsName) == V_STRING) // надо сохранить в excel файл
if (Strlen(_xlsname) > 0)
if (ValType(_passw) != V_STRING)
_passw = "";
else
_passw = trim(_passw);
end;
if ((index(_xlsname,":") == 2) or (index(_xlsname,"\\\\") == 1))// прописан полный путь с буквой диска, или именем сервера. Ничего не добавляем и считаем, что все папки уже есть
else
if ((_WhatToDo == "$") or (_WhatToDo == "#"))
_locPath = GetLocalDocumentsPath();
end;
_ii = index(_xlsName,"\\");
while (_ii > 0)
if (_ii > 1)
_locPath = MergeFile(_locPath,Substr(_xlsname,1,_ii-1));
if (not CheckLocalFolder(_locPath))
MsgBox("Невозможно создать папку " + _locPath);
return;
end;
end;
_xlsName = Substr(_xlsname,_ii+1);
_ii = index(_xlsName,"\\");
end;
_xlsName = MergeFile(_locPath,_xlsname);
end;
if (StrLen(_passw) > 2)
xls.ActiveWorkbook.Password = _passw;
end;
xls.ActiveWorkbook.SaveAs(_xlsname,51);
removeFile("$" + GetLocalTmpPath()+"\\"+fileName+".xml");
if ((_WhatToDo == "#") or (_WhatToDo == "^"))
xls.quit();
xls=null;
else
xls.Visible = true;
GoToWindow(FileName);
end;
else
xls.Visible = true;
end;
else
xls.Visible = true;
end;
OnError()
msgboxex("Невозможно открыть файл!|" + _xlsName);
end;
macro Go(_XlsFileName,_zoom, _passw); // программа формирования собственно файла, переноса его на локал и открытия/сохранения под нужным именем
var _WhatToDo=""; // первый символ в имени файла, если он таки является управляющим символом. Или пустая строка.
if (ValType(_zoom) == V_UNDEF)
_zoom = 100;
end;
if (ValType(_passw) != V_STRING)
_passw = "";
else
_passw = trim(_passw);
end;
if (ValType(_XlsFileName) == V_STRING)
if (Strlen(_XlsFileName) > 0)
_WhatToDo = substr(_XlsFileName,1,1);
if ((_WhatToDo == "$") or (_WhatToDo == "#")or (_WhatToDo == "@")or (_WhatToDo == "^"))
_XlsFileName = Substr(_xlsFileName,2);
else
_WhatToDo="";
end;
end;
end;
MakeFile(_XlsFileName, _zoom);
if (_WhatToDo == "@")
MsgBox("Файл "+filename + " перенесен на локал.");
else
openFile(_xlsFileName, _WhatToDo, _passw);
end;
end;
AddSheet(aFirstSheetName);
fileName=GetGUIDFileName;
end;
>> Ответить- кстати, сейчас работаю на цфт, у них этот метод давно используется - OOXML называется ( KaMPiLeR 09.11.2021 17:35 )0(0)
- кстати, сейчас работаю на цфт, у них этот метод давно используется - OOXML называется ( KaMPiLeR 09.11.2021 17:35 )
- Слегка поправленная версия: ( НоскиПоэта 25.10.2021 13:05 )
- Да, с вордом так же можно. Я проверил. Но там проще взять готовый шаблон и делать подстановки. Типа: ( Avantage 06.02.2020 11:12 )
- идея не нова - в похапе народ тож так делает - генерит xml потом отдает на скачку. ( KaMPiLeR 06.02.2020 10:23 )
- Дополнительный пример ( Avantage 05.02.2020 12:00 )