Чтение/Запись документа Excel 2007 без офиса, без внешних компонент. (с примером для 7.7, 8.1 и 8.2 на управляемых формах)




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2025-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

78 Comments

  1. Душелов

    Свойство «Лист» у обработки — это таблица значений.

    Reply
  2. Душелов

    Собственно код довольно прост, идея, думаю, ясна 😉

    Reply
  3. СергейКа

    + адназначна. Идея супер.

    Reply
  4. Шёпот теней

    Душелов… НУуу…, блин, ТЫ ДАёШЬ…

    … жаль что пятьПлюсиков не могу поставить…

    воОотВеДь…

    Reply
  5. Душелов

    Для 7-ки сделаю, наверное, вечером обработочку… Но сразу оговорюсь, понадобится либо ВК для архивирования, либо какой-либо архиватор, ибо сама платформа с зипами работать не умеет.

    Reply
  6. Шёпот теней

    гы… уговорил… поставил в твоих других работах…

    всё равно за всё заслуженно….!!! удачи во всём….!!!!

    воооот….ведь….

    Reply
  7. WiseSnake

    Респект!

    Reply
  8. CheBurator

    > ибо сама платформа с зипами работать не умеет.

    если считать, что работаем на хрюне и выше — то можно юзать встроенный в винды зиповщик

    Reply
  9. Душелов

    (8) Это какой?

    Reply
  10. CheBurator

    встроенный!!! пошарь на мисте! там Абрахамс показывал ккак делать.. если не найдешь стукнись — у мну есть в загашнике где-то… просто ща работы срочная дофига

    Reply
  11. СЫРОЖА

    Не понял, причем тут архиватор? И вообще, если это только идея,

    причем тут привязка к 2007-му экзелю?

    Reply
  12. Душелов

    (11) :))))) Мои «идеи» отличаются от «идей» некоторых других «коллег» по инфостарту.

    А посмотреть разработку?

    Reply
  13. seermak

    Вопрос на расширение кругозора): 1.а зачем в шаблоне заполнено поле значением «aha». 2. а как сделать так, чтобы сохранилось форматирование(допустим объединение ячеек). Узнал много нового о «.xlsx». За это отдельное спасибо!)))

    Reply
  14. Душелов

    (13) 1. Да просто… Только, чтобы экзель создал все нужные файлы для шаблона, на всякий случай.

    2. По поводу форматирования — это уже надо копать в сторону других файлов, отвечающих за оформление. Как я делаю — беру файл, объединяю, к примеру, ячейки, сохраняю и смотрю изменения.

    Reply
  15. Noy
  16. Душелов

    (15) Спасибо, я уже разобрался… 😉

    Вот только метод Темп.CopyHere(Файл), открывает диалог и предлагает заменить файлы, если такие существуют. И на 2 параметр (8, 16 и т.д.) не реагирует никак. Но это я поборю 🙂

    Reply
  17. baa

    Душелов, я на тебя отдельную папку завел в каталоге для скачаных файлов 1С. Так сказать есть 7.7, есть 8.1 и есть отдельный проект «Душелов» 🙂 Однозначно молодец.

    Reply
  18. Душелов

    Упарился я с вашей 7-кой… 😉 Давно не писал ничего толкового…

    Вообщем… В 7-ке тоже, никаких ВК.

    Reply
  19. Душелов

    Как бы глюки какие-то возможно в 7-ке, т.к. работа с архивами и xml тоже написаны на языке платформы (мисте привет ;)).

    Reply
  20. Трактор

    Вах, молодец! Скачивать не стал. Просто буду знать что такая разработка есть.

    Reply
  21. Трактор

    Не удержался. Скачал. Красиво. Спасибо.

    Reply
  22. biv75

    Супер! Плюсую однозначно

    Reply
  23. minimaxpo

    Гут, мне нравится ход ваших мыслей.

    Reply
  24. Vitalk

    В принципе, хорошая вешь! Кому то да и пригодится!

    Только небольшая помарочка в Excel2007. Когда пустой путь к файлу и при нажатии на «Открыть» пишет: Преобразование значения к типу Число не может быть выполнено ФайлЛиста = ВременныйКаталог + «xlworksheetssheet» + НомерЛиста + «.xml». Просто не определена переменная «ВременныйКаталог»!

    Reply
  25. alexmif

    Скачал! Не удержался. Интересная мысль… Теперь не забыть куда скачал.

    + однозначно, хотя мона и +++++.

    Reply
  26. Aleanza

    Если есть пустое поле в таблице значений тип «Строка» оно глючит.

    Reply
  27. Aleanza

    Но плюс ставлю

    Reply
  28. Aleanza

    А еще оно не сохраняет заголовки, очень не удобно 🙁

    Reply
  29. bxz

    Возникла проблема при записи таблицы значений с количеством строк больше 999 решилась заменой функции ПолучитьИмяСтроки(а) на:

    Функция ПолучитьИмяСтроки(а)

    Возврат Формат(а + 1,»ЧГ=»);

    КонецФункции

    но это все не важно )) за идею ++++++++

    Reply
  30. Душелов

    (26), (30) поправил

    Добавил версию для 8.2 на управляемых формах для тонкого клиента.

    Reply
  31. RuslanBZ

    В версии 8.2 при нажатии на открыть ругается в функции ОткрытьЛист(НомерЛиста)

    {ВнешняяОбработка.Excel2007.МодульОбъекта(64)}: Значение не является значением объектного типа (Строки)

    Для Каждого Стр Из Колонки.Строки Цикл

    Reply
  32. detec

    Идея очень красивая. Но для произвольных файлов, редактируемых пользователями, я бы не советовал. Взял 3 файла. Два выгружены из PL/SQL Developer, один сделан из пользовательского в Office 2010. В результате открылся только 1. Остальные ругнулись .

    {ВнешняяОбработка.Excel2007(63)}: Значение не является значением объектного типа (Строки)

    Для сч = 0 По Колонки.Строки.Количество() — 1 Цикл

    {ВнешняяОбработка.Excel2007(93)}: Поле объекта не обнаружено (F)

    НоваяСтрока[МассивБукв[ИндексСтроки]] = ЗначениеЯчейки;

    Reply
  33. При сохранении ТЗ в которой были пустые ячейки, обработка выдает ошибку.

    {ВнешняяОбработка.Excel2007(266)}: Ошибка при вызове метода контекста (Индекс): Несоответствие типов (параметр номер ‘1’)

    ЗначЯчейки = СписокСтрок.Индекс(Элем);

    по причине:

    Несоответствие типов (параметр номер ‘1’)

    Reply
  34. Не помогло. Все равно дает ошибку:

    {ВнешняяОбработка.Excel2007(266)}: Ошибка при вызове метода контекста (Индекс): Несоответствие типов (параметр номер ‘1’)

    ЗначЯчейки = СписокСтрок.Индекс(Элем);

    по причине:

    Несоответствие типов (параметр номер ‘1’)

    Reply
  35. Интересный момент. Пробую сохранить ТЗ размером 14 на 710 ячеек.

    1. Выдает ошибки при пустых ячейках. Если ячейка не текст, а большое поле типа Memo.

    2. Где то с 283 строки в ячейки начинает подставлять числа, начиная с 1000. и пошел часть ячеек записывает нормально а потом оп и 1001, часть ячеек нормально, 1002 и т д.

    Хотя вторая ошибка это возможно результат исправления первой ) Такой я программист )))

    Reply
  36. Да так и есть ошибка №2 из п. (36) это результат моих фокусов.

    Но 2 момента остались:

    1. Если есть пустое большое поле, то она выдает ошибку

    2. Дата при открытии получается в формате DD.MM. YYYY обрезается. При этом если стр.252: ЗначЯчейки = Лист.Получить(иСтр).Получить(иКол); заменить на ЗначЯчейки = Строка(Лист.Получить(иСтр).Получить(иКол)); то эта ошибка решается. Но появляются другие 🙂

    Не подумайте что я жалуюсь. Идея супер. Буду искать причины и править. Но если кто быстрее меня сообразит, дайте знать. т.к. искать я могу очень долго )))

    Reply
  37. markers

    Подтверждаю проблему с «сдвигом» ячеек при наличии пустых ячеек, решил её по своему, но потом полез сюда, и заменил всё на новый код, начал матюгатся как в (33) Вернул старый код с своей правкой, Автору боооольшое спасибо! Надеюсь когда вернётся сможет нам помочь.

    ADD: Кстати старый код работает нормально и быстро, интересно, новый код быстрей?

    Reply
  38. markers

    Кому нужно получить список листов и кто не догадался как это сделать, даю функцию:

    Функция Excel2007СписокЛистов(ВременныйКаталог);
    Листы = НайтиФайлы(ВременныйКаталог + «xlworksheets», «sheet*.xml»);
    Возврат Листы.Количество();
    КонецФункции 

    Reply
  39. Душелов

    Выложите сюда проблемный файл, посмотрим.

    Reply
  40. markers

    (40) Ловите, простой прайс правда сделанный в 2003-ем и сконвертированный в 2007-й

    Там 3 листа, 2-й пустой, в моём варианте они обрабатываются все вместе

    Reply
  41. markers

    (40) Ну что, есть успехи?

    Reply
  42. webstep

    если в файле excel данные не стоят стройными рядами, а «гуляют» по полю, то при работе алгоритма возникает ошибка потому что «мелкософтмасдай» почему то в «cols» пишет не все колонки. Пришлось ориентироваться на «dimension». Соответственно в функции ОткрытьЛист заменил код

    //создаем колонки
    Колонки = ДеревоДанных.Строки.Найти(«cols», «Объект», Истина);
    сч = 0;
    Для Каждого Стр Из Колонки.Строки Цикл
    Если Стр.Объект <> «col» Тогда
    Продолжить;
    КонецЕсли;
    
    Лист.Колонки.Добавить(МассивБукв[сч]);
    сч = сч + 1;
    КонецЦикла;

    Показать

    на

    //создаем колонки
    Колонки = ДеревоДанных.Строки.Найти(«dimension», «Объект», Истина);
    Счетчик = 0;
    Для Каждого Стр Из Колонки.Строки Цикл
    Если Стр.Объект = «ref» Тогда
    Диапозон = Стр.Значение;
    //поиск максимального значения колонки
    Счетчик=МассивБукв.Количество();
    Пока Счетчик>0 Цикл
    Счетчик = Счетчик — 1;
    Если Найти(Диапозон, МассивБукв[Счетчик])>0 Тогда
    Для Индекс=0 По Счетчик Цикл
    Лист.Колонки.Добавить(МассивБукв[Индекс]);
    КонецЦикла;
    Счетчик = 0;
    КонецЕсли;
    КонецЦикла;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    

    Показать

    теперь колонки формирует правильно.

    Reply
  43. webstep

    проблема сдвига ячеек…

    удалил

    ИндексСтроки = -1;

    и, ориентируясь на значение в «r», заменил:

    ИндексСтроки = ИндексСтроки + 1;

    на

    //поиск колонки
    СтрЗначение = Колонка.Строки.Найти(«r», «Объект»);
    Если СтрЗначение <> Неопределено Тогда
    ИмяКолонки = СтрЗначение.Значение;
    КонецЕсли;
    ИндексСтроки = Неопределено;
    Счетчик = МассивБукв.Количество();
    Пока Счетчик>0 Цикл
    Счетчик = Счетчик — 1;
    Если Найти(ИмяКолонки, МассивБукв[Счетчик])>0 Тогда
    ИндексСтроки = Счетчик;
    Счетчик = 0;
    КонецЕсли;
    КонецЦикла;
    …………………….

    Показать

    проблема решена

    Reply
  44. webstep

    да, все это в функции ОткрытьЛист модуля обработки

    прошу не пинать ногами — на больших таблицах код может работать медленно, но это уже менять МассивБукв на что-то иное…

    и вот еще что… обработка благодаря этому самому массиву букв расчитана на не очень большие таблицы, но я на всякий случай предусмотрел его расширение и на двухбуквенные колонки, поэтому поиск ведется от конца к началу, а не наоборот.

    кстати, как здесь можно свой комментарий удалить? вот еще проблема…

    Reply
  45. webstep
    Reply
  46. webstep

    да вот еще что до меня дошло — пустые строки тоже исчезают, нужно еще думать… впрочем для многих это не будет такой уж потерей 🙂

    и еще у меня в коде (46) тоже закралась ошибочка:

    Если Прав(НРег(ИмяФайла),4)<>».xlsx» Тогда 

    тут циферку 5 надо 😳

    Reply
  47. artbear

    (31) Вчера скачал версию для 8.1

    В нем (26) «Если есть пустое поле в таблице значений тип «Строка» оно глючит.» так и не исправлено.

    Reply
  48. artbear

    Также есть ошибка при записи листа, если у числа в таблице есть дробная часть 🙁

    Запись проходит успешно, но при попытке открыть полученный файл в Офис 2007 выдается ошибка о невозможности открытия 🙁

    Проблема в том, что число выгружается в формате через запятую 🙁

    а нужно через точку.

    ЗЫ или это зависит от региональных установок? вроде они у меня штатные как для Офиса, так и для 1С

    Reply
  49. artbear

    (49) + Исправление

    В методе ЗаписатьДанныеЛиста(хмл)


    нужно поправить код

     Попытка
    А = Число(ЗначЯчейки);
    ЭтоЧисло = Истина;
    Исключение
    

    на код

     Попытка
    А = Число(ЗначЯчейки);
    ЭтоЧисло = Истина;
    ЗначЯчейки = СтрЗаменить(Формат(А, «ЧРД=.»), Символы.НПП, «»); // Артур
    Исключение
    

    ЗЫ кстати, приведенный код решает проблему неверного сохранения чисел более 999, при сохранении в строку в которых появляется неразрывный пробел.

    При открытии подобного файла в Офис 2007 также будет ошибка открытия 🙁

    Reply
  50. artbear

    Проблема из (30) по записи файла с количеством строк более 999 также не решена 🙁

    для ее исправления нужно исправить код модуля

    1. завести новую функцию

    Функция ЧислоВСтроку(значениеЧисла) // Артур для исключения ошибок открытия файлов

    Возврат СокрЛП(Формат(значениеЧисла, «ЧРД=.; ЧГ=»));

    КонецФункции

    2. прописать ее использование

    а) хмл.ЗаписатьАтрибут(«spans», «1:» + ЧислоВСтроку(ЧислоСтрок)); // вместо хмл.ЗаписатьАтрибут(«spans», «1:» + ЧислоСтрок);

    б) хмл.ЗаписатьАтрибут(«count», ЧислоВСтроку(Строки.Количество())); // Артур вместо //Строка(Строки.Количество())

    хмл.ЗаписатьАтрибут(«uniqueCount», ЧислоВСтроку(Строки.Количество())); // Артур вместо //Строка(Строки.Количество())

    Прикрепил готовый файл для 8.1 с моими правками + дополнения от webstep

    Reply
  51. Lalei2008

    А где же пример для 7?

    Reply
  52. Sprite

    Загружаю демо-конфигурацию 7.7

    Получаю сообщение:

    Папка=Шел.namespace(Архив+»»+Путь);

    {Глобальный модуль(365)}: Плохой тип переменной

    Help me!!!

    Reply
  53. Yury1001

    Рановато плюсанул пример 7.7 нерабочий: плохой тип переменной стр. 363

    Папка=Шел.namespace(Архив+»»+Путь);

    Архив = «D:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zip»

    Путь = «D:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zip\_rels»

    Архив+»»+Путь = «D:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zipD:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zip\_rels»

    поправил, теперь плохой тип 404

    ПутьФайла = «D:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zip[Content_Types].xml»

    чё к чему не пойму.

    Reply
  54. Yury1001

    (0) Вопросик в догонку: нужно выгрузить большой объем данных в excel 90 000 строк и штук 10 колонок, этим методом получится?

    Reply
  55. amatisol

    Народ а че реально работает? А то сидят многие на openoffice и хотят чтоб у них ексели открывались нормально, если реально работает то плюсау и скачаю

    Reply
  56. electronik

    В принципе, хорошая вешь нужная! С екзелем работаем если не все то через одного, поетому актуальность даного потрясающая. На основании даной разработки создал свою и что самое интерсное работает. Автору респект и уважение ну и заслуженое 5+++++

    Reply
  57. lesorubka

    Спасибо автору! Отлично работает! Жаль ушел от нас, столько бы еще сделал.

    Царствие ему Небесное!!!

    Reply
  58. AlexO

    (57) amatisol,

    это создание текстовых XML-ек и упаковка их в zip.

    Более ранние версии файлов Excel так создать не удастся.

    Reply
  59. Dansur

    Ему еще много лет будут говорить спасибо. жаль что он это уже не услышит. Покойся с миром.

    Reply
  60. nnurik

    Спасибо автору! Очень пригодилось.

    Reply
  61. tehas

    {ВнешняяОбработка.Excel2007.МодульОбъекта(119)}: Поле объекта не обнаружено (K)

    НоваяСтрока[МассивБукв[ИндексСтроки]] = ЗначениеЯчейки;

    файл (прайс 1С пересохранен в xlsx)

    Reply
  62. Spartan

    (26),(48) Как-то так видимо:

    Функция ПрочитатьСписокСтрок(ФайлСтрок)
    Строки = Новый СписокЗначений;
    
    хмл = Новый ЧтениеXML;
    хмл.ОткрытьФайл(ФайлСтрок);
    
    Пока хмл.Прочитать() Цикл
    //Если хмл.ТипУзла = ТипУзлаXML.Текст Тогда  // некорректно работает для пустых строк!!!
    // Строки.Добавить(хмл.Значение);
    //КонецЕсли;
    // Spartan — 29.03.2013 — начало
    Если хмл.Имя = «t» И хмл.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
    Если хмл.Прочитать() И хмл.Имя = «#text» Тогда
    Строки.Добавить(хмл.Значение);
    Иначе
    Строки.Добавить(«»);
    КонецЕсли;
    КонецЕсли;
    // Spartan — 29.03.2013 — конец
    КонецЦикла;
    
    хмл.Закрыть();
    
    Возврат Строки;
    КонецФункции
    

    Показать

    Reply
  63. mozz

    (64) Туда же:

    (уже встроены багфиксы из (51) )

    Процедура ЗаписатьДанныеЛиста(хмл)
    ЧислоСтрок = Лист.Количество();
    ЧислоКолонок = Лист.Колонки.Количество();
    
    Для иСтр = 0 По ЧислоСтрок — 1 Цикл
    хмл.ЗаписатьНачалоЭлемента(«row»);
    хмл.ЗаписатьАтрибут(«r», ПолучитьИмяСтроки(иСтр));
    хмл.ЗаписатьАтрибут(«spans», «1:» + ЧислоВСтроку(ЧислоСтрок)); // вместо хмл.ЗаписатьАтрибут(«spans», «1:» + ЧислоСтрок);
    
    Для иКол = 0 По ЧислоКолонок — 1 Цикл
    хмл.ЗаписатьНачалоЭлемента(«c»);
    хмл.ЗаписатьАтрибут(«r», ПолучитьОбласть(иСтр, иКол));
    
    ЗначЯчейки = Лист.Получить(иСтр).Получить(иКол);
    Попытка
    А = Число(ЗначЯчейки);
    ЭтоЧисло = Истина;
    ЗначЯчейки = СтрЗаменить(Формат(А, «ЧРД=.»), Символы.НПП, «»); // Артур
    Исключение
    ЭтоЧисло = Ложь;
    КонецПопытки;
    
    Т = ТипЗнч(ЗначЯчейки);
    Если НЕ ЭтоЧисло И ТипЗнч(ЗначЯчейки) = Тип(«Строка») Тогда
    Если НЕ ЗначЯчейки = «» тогда // mozz 30.04.2013 (здесь вываливалось на пустых ячейках)
    хмл.ЗаписатьАтрибут(«t», «s»);
    Элем = СписокСтрок.НайтиПоЗначению(ЗначЯчейки);
    ЗначЯчейки = СписокСтрок.Индекс(Элем);
    КонецЕсли; // mozz 30.04.2013
    КонецЕсли;
    
    хмл.ЗаписатьНачалоЭлемента(«v»);
    хмл.ЗаписатьТекст(Строка(ЗначЯчейки));
    хмл.ЗаписатьКонецЭлемента();
    
    хмл.ЗаписатьКонецЭлемента();
    КонецЦикла;
    
    хмл.ЗаписатьКонецЭлемента();
    КонецЦикла;
    КонецПроцедуры

    Показать

    Reply
  64. mozz

    (63) tehas,

    в функции:

    Функция ОткрытьЛист(НомерЛиста) Экспорт

    найди:

    НоваяСтрока[МассивБукв[ИндексСтроки]] = ЗначениеЯчейки;
    

    замени на:

    Если Лист.Колонки.Найти(МассивБукв[ИндексСтроки]) = Неопределено тогда
    Лист.Колонки.Добавить(МассивБукв[ИндексСтроки]);
    КонецЕсли;
    
    НоваяСтрока[МассивБукв[ИндексСтроки]] = ЗначениеЯчейки;
    

    и все взлетит!

    Reply
  65. Зеленоград

    Спасибо, Мастер! Покойся с миром!

    Reply
  66. Зеленоград

    Спасибо, Мастер! Покойся с миром!

    Коллеги, сайт автора перестал открываться. Там, как минимум, были полезные разработки.

    Есть ли необходимость и возможность сохранения ценных ресурсов в подобных случаях, кроме archive.org?

    Отвечайте или здесь, или в личку. Если это важно многим — будем думать, как реализовать.

    Reply
  67. makas
    ОткрытьФайлЭкзекль2007

    может быть ОткрытьФайлЭкзель2007 ?

    Reply
  68. SANILLA

    да ну на фик, не уже ли, так и есть, щас попробую, если работает, то точно то что надо. Благодарю!

    Reply
  69. Myskyl

    да да то что и искал, как раз нужен был пример работы с Экселем, а тут и ещё без всяких врешних компонент, супер, спасибо

    Reply
  70. host_kms

    Папка=Шел.namespace(Архив+»»+Путь);

    {Глобальный модуль(365)}: Плохой тип переменной

    Кто-нибудь решил эту проблему?

    Reply
  71. mukoza

    Поддерживаю предыдущий вопрос. Неужели у ни у кого не возникает подобной ошибки?

    Reply
  72. ugn-omsk
    Reply
  73. ugn-omsk

    (55) Yury1001,

    Вы пошли тем же путем, что и я.

    поправил, теперь плохой тип 404

    ПутьФайла = «D:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zip[Content_Types].xml»

    Здесь нужно добиться, чтобы

    ПутьФайла = «D:DataBaseДжигельЧтениеЗаписьExcelExcel2007Template.zip[Content_Types].xml»,

    т.е. просто [Content_Types].xml

    Постом выше привел код. Понимаю, что уже давно неактуально, но если вдруг на будущее кому-то пригодится.

    Потому как идея действительно очень интересная!

    Reply
  74. Пикачу

    7.7 такое не понимает:

    Пока Вложения.atEnd<a rel=»noindex,nofollow»…

    Это код для 8?

    А можно для 7.7?

    Reply
  75. sai_NT

    (76) Пикачу, Там скопированы стили с кодом html, правильно так:

    Пока Вложения.atEnd(0)=0 Цикл
    …

    и так далее, то есть смело удаляй тег а, оставив только текст: <a hrеf=…>бла-бла</a> -> бла-бла

    Reply
  76. anten22

    Для 7.7. Обработка некорректно обрабатывает ячейчки, внутри которых меняется шрифт. Чтоб исправить надо заменить функцию «экзель_ПрочитатьСписокСтрок». Переделанная функция добавляет строку в список по тегу «/s», объеденяя содержимое.

    Функция экзель_ПрочитатьСписокСтрок(ПутьКФайлу)
    Строки = СоздатьОбъект(«СписокЗначений»);
    ТекСтрока=»»;
    xml_ОткрытьФайл(ПутьКФайлу);
    Пока xml_Прочитать()=1 Цикл
    //будем добавлять строку по тегу /s
    //все что внутри тега будем объеденять
    Если xml_ИмяТега = «</t>» Тогда
    ТекСтрока=ТекСтрока+» «+СокрЛП(xml_Текст);
    КонецЕсли;
    Если xml_ИмяТега = «</si>» Тогда
    Строки.ДобавитьЗначение(ТекСтрока);
    ТекСтрока=»»;
    КонецЕсли;
    КонецЦикла;
    
    Возврат Строки;
    КонецФункции

    Показать

    Reply
  77. anten22

    И еще для 7.7. Как уже писали выше, неправильно читаются таблицы без заполненных ячеек. Обработка их сдвигает. При чем бывает 2 варианта: есть буква колонки, но не заполнены данные и есть когда буква вообще пропускается. Чтоб корректно работало надо заменить текст функции «экзель_открытьЛист»

    Функция экзель_ОткрытьЛист(НомерЛиста)
    
    ФайлЛиста = экзель_ВременныйКаталог + «xlworksheetssheet» + НомерЛиста + «.xml»;
    Если ФС.СуществуетФайл(ФайлЛиста) = 0 Тогда
    Возврат 0;
    КонецЕсли;
    //КонвертироватьФайл(ФайлЛиста);
    xml_ОткрытьФайл(ФайлЛиста);
    
    экзель_Лист = СоздатьОбъект(«ТаблицаЗначений»);
    
    номСтр = 0;
    номКолонка = 0;
    
    Пока xml_Прочитать()=1 Цикл
    //Сообщить(xml_ИмяТега);
    Если xml_ИмяТега = «<row>» Тогда
    номСтр = номСтр + 1;
    номКолонка = 0;
    экзель_Лист.НоваяСтрока();
    ИначеЕсли xml_ИмяТега = «<c>» Тогда
    //это вариант когда есть буква, но значение не записано. чтобы не было пропуска
    Если (лев(стр,5)=»»»<c r») и (Найти(стр,»/»)<>0) Тогда
    номКолонка = номКолонка + 1;
    Если экзель_Лист.КоличествоКолонок() < номКолонка Тогда
    экзель_Лист.НоваяКолонка(«К» + номКолонка);
    КонецЕсли;
    экзель_Лист.УстановитьЗначение(номСтр, «К» + номКолонка, «»);
    текБуква=xml_СписокАтрибутов.Получить(«r»);
    текБуква=лев(текБуква,1);
    теккод=КодСимв(текБуква);
    предыдущийКод=теккод;
    Продолжить;
    конецесли;
    
    //а это вариант когда буква пропущена
    //надо сравнивать какая была буква ячейки перед этим и какая сейчас.
    //буква должна быть в теге «r»
    текБуква=xml_СписокАтрибутов.Получить(«r»);
    текБуква=лев(текБуква,1);
    теккод=КодСимв(текБуква);
    если теккод=65 Тогда
    //буква А. сбрасываем на начало
    предыдущийКод=теккод;
    иначе
    //не буква А. прописываем пропущенные
    для сч=предыдущийКод+2 по теккод Цикл
    номКолонка = номКолонка + 1;
    Если экзель_Лист.КоличествоКолонок() < номКолонка Тогда
    экзель_Лист.НоваяКолонка(«К» + номКолонка);
    КонецЕсли;
    экзель_Лист.УстановитьЗначение(номСтр, «К» + номКолонка, «»);
    КонецЦикла;
    предыдущийКод=теккод;
    КонецЕсли;
    //Сообщить(текБуква);
    //текущаяБуква=
    ТипЯчейки = xml_ПолучитьАтрибут(«t»);
    xml_Прочитать();
    Если xml_ИмяТега <> «<v>» Тогда
    Продолжить;
    КонецЕсли;
    xml_Прочитать();
    
    ЗначениеЯчейки = СокрЛП(xml_Текст);
    Если ТипЯчейки = «s» Тогда
    ЗначениеЯчейки = экзель_СписокСтрок.ПолучитьЗначение(Число(ЗначениеЯчейки) + 1, ЗначениеЯчейки);
    КонецЕсли;
    
    номКолонка = номКолонка + 1;
    Если экзель_Лист.КоличествоКолонок() < номКолонка Тогда
    экзель_Лист.НоваяКолонка(«К» + номКолонка);
    КонецЕсли;
    
    экзель_Лист.УстановитьЗначение(номСтр, «К» + номКолонка, ЗначениеЯчейки);
    КонецЕсли;
    КонецЦикла;
    хз=»»;
    экзель_Лист.ВыбратьСтроку(хз);
    Возврат 1;
    КонецФункции

    Показать

    Reply
  78. anten22

    следующая версия. Предыдущая вываливалсь если пропущена колонка «А»

    Функция экзель_ОткрытьЛист(НомерЛиста)
    
    ФайлЛиста = экзель_ВременныйКаталог + «xlworksheetssheet» + НомерЛиста + «.xml»;
    Если ФС.СуществуетФайл(ФайлЛиста) = 0 Тогда
    Возврат 0;
    КонецЕсли;
    //КонвертироватьФайл(ФайлЛиста);
    xml_ОткрытьФайл(ФайлЛиста);
    
    экзель_Лист = СоздатьОбъект(«ТаблицаЗначений»);
    
    номСтр = 0;
    номКолонка = 0;
    //если пропущена колонка А, то будем прописывать с этой
    предыдущийКод=63;
    Пока xml_Прочитать()=1 Цикл
    //Сообщить(xml_ИмяТега);
    Если xml_ИмяТега = «<row>» Тогда
    номСтр = номСтр + 1;
    номКолонка = 0;
    экзель_Лист.НоваяСтрока();
    ИначеЕсли xml_ИмяТега = «<c>» Тогда
    //это вариант когда есть буква, но значение не записано. чтобы не было пропуска
    Если (лев(стр,5)=»»»<c r») и (Найти(стр,»/»)<>0) Тогда
    номКолонка = номКолонка + 1;
    Если экзель_Лист.КоличествоКолонок() < номКолонка Тогда
    экзель_Лист.НоваяКолонка(«К» + номКолонка);
    КонецЕсли;
    экзель_Лист.УстановитьЗначение(номСтр, «К» + номКолонка, «»);
    текБуква=xml_СписокАтрибутов.Получить(«r»);
    текБуква=лев(текБуква,1);
    теккод=КодСимв(текБуква);
    предыдущийКод=теккод;
    Продолжить;
    конецесли;
    
    //а это вариант когда буква пропущена
    //надо сравнивать какая была буква ячейки перед этим и какая сейчас.
    //буква должна быть в теге «r»
    текБуква=xml_СписокАтрибутов.Получить(«r»);
    текБуква=лев(текБуква,1);
    теккод=КодСимв(текБуква);
    если теккод=65 Тогда
    //буква А. сбрасываем на начало
    предыдущийКод=теккод;
    иначе
    //не буква А. прописываем пропущенные
    для сч=предыдущийКод+2 по теккод Цикл
    номКолонка = номКолонка + 1;
    Если экзель_Лист.КоличествоКолонок() < номКолонка Тогда
    экзель_Лист.НоваяКолонка(«К» + номКолонка);
    КонецЕсли;
    экзель_Лист.УстановитьЗначение(номСтр, «К» + номКолонка, «»);
    КонецЦикла;
    предыдущийКод=теккод;
    КонецЕсли;
    //хз=0;
    //экзель_Лист.ВыбратьСтроку(хз);
    //Сообщить(текБуква);
    //текущаяБуква=
    ТипЯчейки = xml_ПолучитьАтрибут(«t»);
    xml_Прочитать();
    Если xml_ИмяТега <> «<v>» Тогда
    Продолжить;
    КонецЕсли;
    xml_Прочитать();
    
    ЗначениеЯчейки = СокрЛП(xml_Текст);
    Если ТипЯчейки = «s» Тогда
    ЗначениеЯчейки = экзель_СписокСтрок.ПолучитьЗначение(Число(ЗначениеЯчейки) + 1, ЗначениеЯчейки);
    КонецЕсли;
    
    номКолонка = номКолонка + 1;
    Если экзель_Лист.КоличествоКолонок() < номКолонка Тогда
    экзель_Лист.НоваяКолонка(«К» + номКолонка);
    КонецЕсли;
    
    экзель_Лист.УстановитьЗначение(номСтр, «К» + номКолонка, ЗначениеЯчейки);
    КонецЕсли;
    КонецЦикла;
    Возврат 1;
    КонецФункции

    Показать

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *