Артефакт

Перевод таблицы Word в таблицу HTML / 9 марта 2007 г.

Постановка задачи

Есть документ Word, содержащий таблицы. Для простоты — единственную таблицу. Нужно получить HTML-код, соответствующий этой таблице. Я намеренно не говорю о свойствах бордюров, ширине ячеек и пр.: всё это можно задать уже в Dreamweaverе.

Попытка решить

Сначала я написал макрос, который вы можете найти в статье «Подготовка текстов для WWW». Он отлично работает, за исключением того, что слитые (merged) ячейки им не обрабатываются; более того, если таблица включает такие ячейки, макрос выдаёт ошибку. Понятно, почему: происходит попытка обращения к ячейке с несуществующим индексом.

Привожу текст этого макроса:

Sub setBasicTable()
Dim i As Integer, i2 As Integer
Dim j As Integer, j2 As Integer, k As Integer
Dim tString As String
k = 0
With ActiveDocument.Content
  For Each Table In ActiveDocument.Tables
  .InsertAfter "<table>"
    k = k + 1
    i2 = Table.Rows.Count
    j2 = Table.Columns.Count
    For i = 1 To i2
     .InsertParagraphAfter
     .InsertAfter "<tr>"
       For j = 1 To j2
        .InsertParagraphAfter
        .InsertAfter "<td>"
         tString = Left(Table.Cell(i, j), Len(Table.Cell(i, j)) - 2)
         tString = Replace(tString, Chr(13), "<br>")
         tString = Replace(tString, Chr(11), "<br>")
         If tString = "" Then tString = "&nbsp;"
        .InsertAfter tString
        .InsertAfter "</td>"
       Next j
     .InsertParagraphAfter
     .InsertAfter "</tr>"
    Next i
  .InsertParagraphAfter
  .InsertAfter "</table>"
  Next
End With
End Sub

После этого я решил, что неплохо бы всё же доделать начатое, и полез в интернет искать, что успели написать до меня умные дяди программисты.

Оказалось, что задача эта, действительно, по разным поводам уже рассматривалась, но решения найдено не было (в VBA нет способа выяснить, не является ли ячейка результатом слияния нескольких, по крайней мере — для ячеек, сливающихся по горизонтали). Впрочем, на одной русской странице я обнаружил то, что, как утверждал Виталий Сизов, было идеальным ответом на все вопросы сразу. Написанный Виталием код я и попытался адаптировать.

Что вышло

После некоторой войны с объектами, устранения всех попыток макроса писать результаты в посторонний файл и некоторых других исправлений, которые показались мне необходимыми, я получил, казалось бы, вполне работоспособный код (см. ссылку в конце статьи). И решил испробовать его на таблице со слитыми ячейками:

01 02,05 03
04 06
07 08,09

HTML-код, к моему величайшему сожалению, получился вот какой:

<table>
<tr>
<td>01</td>
<td ROWSPAN="2">02,05</td>
<td>03</td>
</tr>
<tr>
<td COLSPAN="2">04</td>
<td ROWSPAN="2">06</td>
</tr>
<tr>
<td>07</td>
<td COLSPAN="2">08,09</td>
</tr>
</table>

Идея, напомню, заключалась в том, чтобы переписать таблицу в некий массив и уже на его основе формировать HTML. «Несуществующие» ячейки (в нашем случае — пятая и девятая), найденные с помощью упомянутых выше ошибок макроcа (см. код по ссылке), заполнялись значением переменной FILLER, что учитывалось при генерации параметров rowspan и colspan. Виртуальная таблица выходила такой:

01 02,05 03
04 FILLER  06
07 08,09 FILLER 

Далее при переборе строк учитывалось число содержащих FILLER ячеек справа и внизу от каждой обычной ячейки, и это число прописывалось в качестве значения параметров colspan или rowspan соответственно.

Беда в том, что каждая ячейка, попадающая в rowspan, попадала и в colspan тоже. Иначе говоря, всё считалось дважды. Обратите внимание: при построчном переборе для ячейки с номером 02 параметр rowspan приравнивается к двум, но впоследствии colspan ячейки 04 тоже считается равным двум, и всё за счёт одной «несуществующей» ячейки с номером 05. То же самое происходит и вокруг девятой ячейки.

Код Виталия оказался неработающим. Если, конечно, я всё понял правильно, что не гарантируется.

Мои предположения

Первой идеей было выкрутиться за счёт измерения размеров ячеек. Например, высота второй должна быть вдвое больше, чем у первой.

Не тут-то было. Cell(1,2).Height возвращает то же самое wdUndefined (9999999 пунктов), что и Cell(1,1).Height. Правда, Cell(3,8).Width возвращает удвоенную ширину ячейки 07, но это нам мало что даёт, т. к. остаётся непонятным, что делать с rowspan.

Возможно, избежать двойного учёта «несуществующих» ячеек можно избежать за счёт какого-нибудь хитрого алгоритма перебора, мне как непрограммисту не известного.

Так что жду ваших писем, дорогие друзья.

Дополнение, присланное одним из посетителей сайта

Здравствуйте, Андрей.

Я заинтересовался Вашей задачей по переводу таблицы MS Word в HTML в части работы с объединенными ячейками. Изначально я усомнился в неработоспособности примера кода Виталия Сизова с www.microsoft.ru и доказал себе, что он действительно неработоспособен. После детального исследования примера кода я установил, что проблемы начинаются при еще изначальном зондировании таблицы в поисках пустых ячеек и заполнении массива. Иными словами, проблемы имеют начало при приведении таблицы к регулярному виду. Поясню проблему на следующем примере, предположим, что имеем следующую таблицу с двумя объединенными ячейками:

1,1 1,2;1,3 1,4 1,5
2,1 2,2 2,3 2,4 2,5
3,1 3,2 3,3 3,4 3,5

По логике Виталия Сизова при зондировании ячейки с координатами 1,3 должна возникнуть ошибка, т.е. ожидается runtime error в строке: Set oCell = oTbl.Cell(iRow, iCol). Но ожидаемой ошибки не возникает, поскольку объектная модель Worda вернет в качестве запрошенной ячейки с координатами 1,3 ячейку 1,4. Ошибка возникает при зондировании ячейки с координатами 1,5. Очевидно, что Word считает количество столбцов по отношению к текущей строке, а не по отношению ко всей таблице в целом. В рассматриваемом примере первая строка содержит 4 столбца, тогда как вся таблица содержит 5 столбцов. Я заметил, что статья была опубликована еще в 2002-м году, соответственно, полагаю, что автор работал с более ранними версиями MS Office, чем ныне используемая мною MS Office 2003. Вполне возможно, что в прежних версиях оно так и работало, т. е. объектная модель Wordа возвращала ссылку по отношению ко всей таблице в целом, а не по отношению к текущей строке.

Резюмируя, скажу, что, в целом, мои изыскания не решили проблему. Но могу порекомендовать попробовать исследовать работоспособность кода Виталия Сизова на MS Office 2000 или даже 97, вполне возможно, что там оно работает. У меня у самого уже не сохранились прежние версии офисных пакетов.

С уважением,
Руслан Шайдуллин

Продолжение — и, видимо, окончание

Хороший человек по имени Stanislav использовал этот сценарий для написания своей версии решения, которая носит говорящее название TableAgony и которая, судя по всему, абсолютно работоспособна. Загрузите файл HTMLTables.doc, в нём находятся несколько тестовых таблиц (это нечто, уверяю вас) и сам проект, который запускается как Project.TableAgony.Test из списка макросов MS Word. HTML-файл с результатами конвертирования появится в папке My Documents.

Спасибо! :-)

Макросы к статье

setTable (адаптированный макрос Виталия Сизова)
HTMLTables (тестовый файл с макросом Stanislavа)

Новости раздела

4 августа 2008 г.
Copy Editing: последняя часть

Ещё на сайте

Библиотека
Языки
Друзья
Канада
Авторский угол

Интернет

CPAN
Citforum
W3C.org
useit.com
Типомания
Code Charts
ру/ководство
Лаборатория dk
WebReference.com
Спецификация Perl
Заметки HTML-кодера
Анатомия Adobe Photoshop
The Apache Software Foundation


Рейтинг@Mail.ru

wordpress statistics

Рейтинг@Mail.ru