[⇐ К полному списку статей / Content] ID: 20141117_0415-html2xhtml

Преобразование HTML в XHTML на С и C++

Задача преобразования HTML-форматированного текста в XHTML появилась в связи с тем, что нужно было вставлять в XML блоки форматированного текста. (Про чтение таких блоков при SAX-разборе я написал статью: «C++/Qt: Получение полного содержимого XML-тега (со вложенными) при SAX-разборе» ). Эти вставки писались вручную и часто содержали ошибки форматирования, невидные при просмотре в браузерах, но неприемлимые для строгих парсеров XML. Кроме того в исходных текстах часто были непарные теги, вроде <BR>, которые каждый раз приходилось отыскивать и исправлять вручную.

Для выполнения этой задачи на C++ я успешно приминил бесплатную библиотку Tidy. К сожалению разработка её остановилась в начале 2009, но для моей задачи она сгодилась.

Я использовал MinGW, компилировал из коммандной строки-консоли Qt 4.8.3 под Windows 7.
Так как исходники уже довольно древние, при компиляции возникают небольшие загвоздки. Вот пошаговая инструкция, как я делал:
1. Использовал последний tarbar-архив из CSV (март 2009).
2. После распаковки надо создать вручную директории obj (где Makefile) и bin c lib (в директории tidy) (сами они не создаются)
3. Я использовал Makefile для gmake, но его пришлось изрядно поправить. Также для компиляции в MinGW пришлось поправить директиву выбора блока в файле src/mappedio.c. Исправленные файлы я выложил в архив tidy-changes.7z [здесь].
4. Для сборки библиотеки запустите make из директории build\gmake.

Вот код, обеспечивающий конвертацию (он написан для C++, но легко может быть переписан для чистого C):

// Convert HTML to XHTML and clean up using libTidy
#include <tidy.h>
#include <buffio.h>
string CleanHTML(const char *html)
{

// Initialize a Tidy document
TidyDoc tidyDoc = tidyCreate();
TidyBuffer tidyOutputBuffer = {0};

// Configure Tidy
// The flags tell Tidy to output XML and disable showing warnings
bool configSuccess = tidyOptSetBool(tidyDoc, TidyXmlOut, yes)
&&
tidyOptSetBool(tidyDoc, TidyQuiet, yes)
&&
tidyOptSetBool(tidyDoc, TidyNumEntities, yes)
&&
tidyOptSetBool(tidyDoc, TidyShowWarnings, yes) // no
;//&& tidyOptSetValue(tidyDoc,TidyCharEncoding, "utf8");

int
tidyResponseCode = -1;

// Parse input
if (configSuccess)
tidyResponseCode = tidyParseString(tidyDoc, html);

// Process HTML
if (tidyResponseCode >= 0)
tidyResponseCode = tidyCleanAndRepair(tidyDoc);

// Output the HTML to our buffer
if (tidyResponseCode >= 0)
tidyResponseCode = tidySaveBuffer(tidyDoc, &tidyOutputBuffer);

// Any errors from Tidy?
if (tidyResponseCode < 0) // Tidy encountered an error while parsing an HTML
throw tidyResponseCode;

// Grab the result from the buffer and then free Tidy's memory
std::string tidyResult = (char*)tidyOutputBuffer.bp;
tidyBufFree(&tidyOutputBuffer);
tidyRelease(tidyDoc);

return
tidyResult;
}

// ................

// Convert HTML to XHTML and clean it
// see also: https://bugs.webkit.org/show_bug.cgi?id=44876
string xhtml;
try

{

xhtml = CleanHTML( html );
}

catch
(int e)
{

cerr << "Clean HTML error (from libTidy): " << e << endl;
}
Добавлю, что в моём случае обработка UTF-8 символов (кирилицы) в приложении, запущенном под Windows 7 x64 происходила не правильно (они конвертировались в кодовые &-представления побайтно). Так как мне это не было нужно в тот момент, я не стал разбираться в чём там дело, возможно просто в системных настройках локалей или в каких-то параметрах запуска библиотечных функций или компиляции. Вроде бы Tidy поддерживает UTF-8. Для обработки кириличных HTML-текстов также можно перевести их в однобайтовую кодировку, например в CP-1251.

Для C++ также существует специальная обёртка Tidy-библиотеки TidyPP: http://code.google.com/p/tidypp
С применением уже этой бублиотеки я написал GUI-приложение на Qt для удобства конвертации. Вот код рабочего метода из этого приложения:

void MainWindow::convert()
{
    QString msg = tr("Convertion passed.");

    QString source = m_pHTML->document()->toPlainText();
    if (m_pCheckBox->isChecked())
    {
        source.replace("\n", "<br />\n");
    }

    tidypp::document doc; // tidy html document
    tidypp::buffer html, xhtml;
    tidypp::buffer errbuf; // will store the warnings and errors encountered by html tidy

    // let's append our html code to our buffer
    html.append(const_cast<char *>(source.toUtf8().data()), source.toUtf8().size() +1);
    // +1 because of the endstring character

    try
    {
        doc.seterrorbuffer(errbuf); // assign error buffer
        doc.optsetbool( TidyForceOutput, true ); // output document even if errors were found
        doc.optsetbool( TidyXhtmlOut,    true );
        doc.optsetvalue(TidyBodyOnly,    "yes" );
        //doc.optsetbool( TidyQuiet,       true );
        doc.optsetvalue(TidyCharEncoding, "UTF8"); // ?


        doc.optsetint(TidyWrapLen, 4096); // wrap margin
        doc.parsebuffer( html ); // parse the html in our buffer
        doc.cleanandrepair(); // cleans up and repairs errors

        doc.savebuffer( xhtml );

        m_pButtonCheck->setDisabled( false );

    }
    catch (const tidypp::exception &e) // catch exceptions and print the error on screen
    {
        std::cerr << e.what() << std::endl;
        msg += " ";
        msg += e.what();
    }

    QByteArray result = (const char*)xhtml.ptr();
    m_pXHTML->document()->setPlainText( QString::fromUtf8(result) );

    m_pMessages->setText( msg );
}
Готовое к работе приложение, откомпилированное как испольняемый модуль под Windows, со статической сборкой Qt (без внешних DLL) можно скачать тут: http://netdat.ru/files/2014/html2xhtml-static.7z
Ради статической линковки мне пришлось отказаться от модуля WebKit (я использовал QWebView для окна "чернового просмотра" результата в XHTML). Кроме того компилятор MinGW не может обойтись без динамической mingwm10.dll, при включенной поддержка исключений C++ (exceptions). Это сделано ради поддержки MS Windows 95/98/ME. Существует патч для "лечения" этого недоразумения: http://gcc.gnu.org/ml/gcc-patches/2008-08/msg01207.html. Однако я решил что проще будет пожертвовать исключениями (и в месте с ними диагностикой ошибок в исходном HTML. В опубликованном приложении исключения и диагностика вырезаны.

Original: http://lj.rossia.org/users/shestero/142631.html
Tags: c++, html, it, xhtml
[⇐ К полному списку статей / Content]


© http://netdat.ru — Bulletin Publishing System, 2011-2016.