Из html-таблиц в таблицы значений, функция

Парсинг HTML-таблиц, занесение результатов в таблицы значений. Обработка вложенных друг в друга html-таблиц. Обработка объединённых ячеек. Одна функция — и готово.

Делал тут чтение с одного сайта, да и написал функцию… Дай, думаю, выложу — авось прямо в таком виде кому пригодится. Что умеет: умеет из файла или из html-фрагмента читать все находящиеся в нём таблицы, включая вложенные друг в друга. Итоговый результат — массив из таблиц значений. В ячейки таблиц пишется либо простое значение (обычно строковое), либо вложенная таблица значений, либо массив значений (если ещё были узлы, в т.ч. вложенные таблицы). Колонки — произвольного типа, их именование примитивное, «к1», «к2» и т.д. На правильность чтения вертикально объединённых ячеек (rowSpan) не рассчитана.

Прошу пардону, но раскраска исходников лежит вне досягаемости; потом разрисую, а копипастить уже и так можно.

Функция ПолучитьТаблицыЗначенийИзHTML(рИсходныйДокумент,мТаблиц=Неопределено)

 Если мТаблиц=Неопределено Тогда // первый запуск, читаем сам документ

 мТаблицИтого=Новый Массив;

 рКодировка=«UTF-8»;

 чтен=Новый ЧтениеHTML;

 Если ТипЗнч(рИсходныйДокумент)=Тип(«Строка») Тогда

 // считаем, что передали строку HTML-кода (фрагмент)

 чтен.УстановитьСтроку(рИсходныйДокумент,рКодировка);

 ИначеЕсли ТипЗнч(рИсходныйДокумент)=Тип(«Файл») Тогда

 // считаем, что передали файл, проверенно существующий и читающийся оттуда, где он есть

 чтен.ОткрытьФайл(рИсходныйДокумент.ПолноеИмя,рКодировка);

 Иначе

 Сообщить(«Передан неверный аргумент: «+СокрЛП(рИсходныйДокумент)+«, недопустимый тип!»,СтатусСообщения.Важное);

 Возврат мТаблицИтого;

 КонецЕсли;

 пострДОМ=Новый ПостроительDOM;

 гдок=пострДОМ.Прочитать(чтен);

 // запускаем уже рекурсивное чтение

 ПолучитьТаблицыЗначенийИзHTML(гдок.ЭлементДокумента,мТаблицИтого);

 // возвращаемся с верхнего уровня и вообще выходим

 Возврат мТаблицИтого;

 Иначе

 // рекурсивный запуск, уже читается ДокументHTML

 Для каждого элдок Из рИсходныйДокумент.ДочерниеУзлы Цикл

 Если ТипЗнч(элдок)=Тип(«ЭлементТаблицаHTML») Тогда // таблица, переходим непосредственно к её обработке

 //===========================================================================================

 Если элдок.ДочерниеУзлы.Количество()=1 Тогда

 рЭлемент=элдок.ДочерниеУзлы.Элемент(0);

 Если ТипЗнч(рЭлемент)=Тип(«ЭлементHTML») Тогда

 Если рЭлемент.ЕстьДочерниеУзлы() Тогда

 // колонки добавляются по факту и по порядку

 тзнч=Новый ТаблицаЗначений;

 Для каждого рСтрока Из рЭлемент.ДочерниеУзлы Цикл

 ОбработкаПрерыванияПользователя();

 мЗначенийКолонок=Новый Массив;

 Для каждого рЯчейка Из рСтрока.ДочерниеУзлы Цикл

 ОбработкаПрерыванияПользователя();

 Если ТипЗнч(рЯчейка)<>Тип(«ЭлементЯчейкаТаблицыHTML») Тогда Продолжить КонецЕсли;

 // в ячейке может быть как один элемент (тогда вносится простое значение), так и несколько (тогда их массив)

 мЗначенийЯчейки=Новый Массив;

 Для каждого рУзел Из рЯчейка.ДочерниеУзлы ЦИкл

 Если ТипЗнч(рУзел)=Тип(«ТекстDOM») Тогда

 рЗначение=СокрЛП(рУзел.ТекстовоеСодержимое);

 ИначеЕсли ТипЗнч(рУзел)=Тип(«ЭлементТаблицаHTML») Тогда

 // идём ещё глубже, обрабатывая таблицу через вызов обработки её родителя

 мПодтаблиц=Новый Массив;

 ПолучитьТаблицыЗначенийИзHTML(рУзел.РодительскийУзел,мПодтаблиц);

 Если мПодтаблиц.Количество()=0 Тогда // ни одной таблицы не было

 рЗначение=Неопределено;

 ИначеЕсли мПодтаблиц.Количество()=1 Тогда

 рЗначение=мПодтаблиц.Получить(0);

 Иначе

 рЗначение=мПодтаблиц; // прямо как массив и идёт

 КонецЕсли;

 Иначе

 // идём ещё глубже в общем виде

 мПодтаблиц=Новый Массив;

 ПолучитьТаблицыЗначенийИзHTML(рУзел,мПодтаблиц);

 Если мПодтаблиц.Количество()=0 Тогда // ни одной таблицы не было

 рЗначение=Неопределено;

 ИначеЕсли мПодтаблиц.Количество()=1 Тогда

 рЗначение=мПодтаблиц.Получить(0);

 Иначе

 рЗначение=мПодтаблиц; // прямо как массив и идёт

 КонецЕсли;

 КонецЕсли;

 Если ТипЗнч(рЗначение)=Тип(«Массив») Тогда // перекидываем в итоговый

 Для каждого знчм Из рЗначение Цикл мЗначенийЯчейки.Добавить(знчм) КонецЦикла;

 Иначе // просто добавляем

 мЗначенийЯчейки.Добавить(рЗначение);

 КонецЕсли;

 КонецЦикла;

 рЗначениеЯчейки=?(мЗначенийЯчейки.Количество()=1,мЗначенийЯчейки[0],мЗначенийЯчейки);

 // определяем, сколько колонок вмещает текущая ячейка (возможно объединение, тогда будет повтор значения)

 квокол=?(рЯчейка.ОбъединениеКолонок=0,1,рЯчейка.ОбъединениеКолонок);

 //Если рЯчейка.Атрибуты.Количество()<>0 Тогда // можно и так, оставил для общего интересу…

 // рАтрОбъКол=рЯчейка.Атрибуты.ПолучитьИменованныйЭлемент(«colspan»); // именно в нижнем регистре

 // Если рАтрОбъКол<>Неопределено Тогда квокол=рАтрОбъКол.Значение КонецЕсли;

 //КонецЕсли;

 Для й=1 По квокол Цикл

 мЗначенийКолонок.Добавить(рЗначениеЯчейки);

 КонецЦикла;

 КонецЦикла;

 // теперь массив значений для строки таблицы значений готов

 стротзнч=тзнч.Добавить();

 Для ы=0 По мЗначенийКолонок.Количество()-1 Цикл

 Если ы>тзнч.Колонки.Количество()-1 Тогда // по ситуации добавляем колонку произвольного типа

 тзнч.Колонки.Добавить(«к»+СокрЛП(ы));

 КонецЕсли;

 стротзнч[ы]=мЗначенийКолонок.Получить(ы);

 КонецЦикла;

 КонецЦикла;

 Иначе

 тзнч=Неопределено;

 КонецЕсли; // если есть дочерние/нет дочерних

 Иначе

 тзнч=Неопределено;

 КонецЕсли; // по типу исходного основного элемента таблицы

 Иначе

 тзнч=Неопределено;

 КонецЕсли; // по количеству исходных узлов

 //===========================================================================================

 Если тзнч<>Неопределено Тогда мТаблиц.Добавить(тзнч) КонецЕсли;

 Иначе

 Если элдок.ЕстьДочерниеУзлы() Тогда

 ПолучитьТаблицыЗначенийИзHTML(элдок,мТаблиц);

 КонецЕсли;

 КонецЕсли;

 КонецЦикла;

 КонецЕсли;

 Возврат Неопределено; // тут результат нас не интересует

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

 

16 Comments

  1. DrAku1a

    (0) оформите пожалуйста код, как полагается.

    Reply
  2. Yashazz

    (1) Я ж написал, разукрашки под рукой не случилось. 😉 Сегодня оформлю.

    Reply
  3. Steelvan

    А есть возможность обратной реализации?

    Из Таблицы значений (со вложенными таблицами) в таблицу HTML ?

    Пригодилось бы.

    Reply
  4. Yashazz

    (3) Уж подумываю сделать, есть такая задача.

    Reply
  5. Steelvan

    Отлично.

    Reply
  6. v.l.

    Яростно плюсую за то, что описал в статье примеры кода.

    Reply
  7. Yashazz
  8. Дмитрий74Чел

    у меня не отрабатывает: в моем файле таблица имеет более 1 строки, а у Вас стоит

    Если элдок.ДочерниеУзлы.Количество()=1 Тогда


    накосячил с копипастом )))

    Reply
  9. Yashazz

    (8) Фух, я уж напрягся. Если что, пишите.

    Reply
  10. vital1c

    Если таблица с заголовком

    <thead>

    , то не обрабатывает такие таблицы корректно, а ячейки такого заголовка имеют тип как ЭлементHTML

    Reply
  11. amatoravg

    не работает. в документе у меня одна таблица. возвращает массив с кучей пустых строк…. 🙁

    Reply
  12. Yashazz

    (11) Пожалуйста, киньте мне на yashazz пёсик mail.ру ваш исходный html, посмотрю. Очень интересно, что там такое попалось.

    Reply
  13. Иной

    Заранее спасибо =). Завтра буду юзать

    Reply
  14. andy3626603

    У меня то же самое что и 11

    Reply
  15. Yashazz

    (14) andy3626603, жду ваш html, посмотрим.

    Reply
  16. lm-alex

    Не отрабаытвает если ДочерниеУзлы.Количество() > 1

    Если элдок.ДочерниеУзлы.Количество()=1 Тогда

    рЭлемент=элдок.ДочерниеУзлы.Элемент(0);

    Reply

Leave a Comment

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