Рубрики
Без рубрики

Помощь Pandoc генерировать правильную оглавление от HTML-ввод

TL; DR: PANDOC ожидает, что заголовки глада будут размещены непосредственно внутри узла тела. Нет

wr … Помечено Pandoc, Python.

TL; DR:

  • PandOC ожидает, что заголовки главы должны быть размещены непосредственно внутри тело узел. Нет
    обертки разрешены.
  • Pandoc устанавливает название книги после прошлой Тег, который он видит (например, последний файл в командной строке).

Прошло долгое время, так как я в последний раз должен был преобразовать электронную книгу HTML в EPUB. В прошлый раз я сделал, я не мог сделать калибр поставить главы в правильном порядке 1 и так злился, что пытался передать файл с Баш и куча Regexen . Это было, безусловно, интересный эксперимент, и я многому научился о внутренних ценах в процессе. Я также узнал, что пока Это нормально для анализа ограниченного, известного набора HTML с Regex , гораздо удобнее использовать фактический анализатор HTML.

С тех пор я влюбился в Pandoc и использовали его широко для различных проектов 2 Отказ Так когда я недавно хотел прочитать F # Программирование Wikibook На мойку я знал, что буду использовать Pandoc для преобразования.

Мой энтузиазм несколько упал, когда я изучил полученный файл и обнаружил, что сгенерированная оглавление состояла из одной записи, названной в честь последней главы книги. И это была не только проблема сломанной навигации.

Файл EPUB – это, по сути, архив ZIP с главами, хранящимися в отдельных файлах HTML. Благодаря этому, читатели электронных книг могут откройте их один за другим, что означает более быструю загрузку и нижнюю часть памяти. Поскольку Pandoc не знал, как разделить книгу в главы, она поместила их все в один файл, чтобы мой читатель должен был подсказать и отформатировать весь текст, прежде чем отображать что-либо – измельчать его, чтобы остановиться на минуту каждый раз, когда книга была открыл.

Для HTML-ввода Pandoc должен автоматически генерировать TOC из

,

разметки. После некоторых экспериментов оказалось, что Pandoc ожидает, что заголовки глада будут размещены непосредственно внутри тело узел . Хотя это имеет смысл для документов, написанных для единственной цели быть упакованным в качестве EPUB, это редко бывает в случае с HTML-страницами в Интернете, где вы часто найдете фактический контент, завернутый в несколько слоев Div S (или таблицы, если вы неудачно бродить такими опасными, бого-забытыми местами).

Вот тестовый случай. Скажем, у нас есть книга под названием Книга , который состоит из четырех глав:

seq 1 4 | while read idx; do
    > "ch$idx.html" <
    
        Chapter $idx - The Book
    
    
        

Chapter $idx

Lorem ipsum, dolor sit amet.

EOF done

Когда мы кормите их в Pandoc, мы получаем сломанный TOC с титульной страницей и одной главой, охватывая все входные файлы:

pandoc -o the_book.epub ch*.html

Чтобы исправить оглавление, мы должны немного помочь Pandoc и переместить

S до дерева, пока они не являются детьми тело . Вот как мы можем сделать это с Python и Красивый суп :

fix.py:

import bs4

filenames = [
    'ch1.html', 'ch2.html', 'ch3.html', 'ch4.html'
]

for filename in filenames:
    with open(filename, 'r') as f:
        soup = bs4.BeautifulSoup(f, 'lxml')

    current = soup.find(id='content')
    while current.name != 'body':
        parent = current.parent
        current.unwrap()
        current = parent

    out_filename = filename.replace('.', '-flat.')
    with open(out_filename, 'w') as f:
        f.write(soup.prettify())

Для каждого указанного файла скрипт создает DOM и находит узел с фактическим контентом – в этом случае, тот, с помощью Содержание ID (если у вашего DIV нет назначенного идентификатора, но у него есть определенный класс, вы можете получить его с SUP.find (Class _ = '...') вместо). Призыв к развернуть Метод заменяет узел своими детьми, и мы перемещаемся вверх по дереву на родитель удаленного узла. Код повторяется до тех пор, пока Тело Узел достигнут. Наконец, DOM сохраняется в файл с -FLAT прилагается к его названию.

python fix.py

pandoc \
    -o the_book.epub \
    ch1-flat.html \
    ch2-flat.html \
    ch3-flat.html \
    ch4-flat.html

Так-то лучше. Главы были обнаружены и разделить правильно, но топ-две записи, которые должны быть названным книгой, неверно подписаны Глава 4 – книга . Возможно, вы заметили, что это текст в <название> последнего файла в командной строке.

Pandoc устанавливает название книги после содержания <название> узел. При вызове с несколькими входными файлами и есть более одного <название> Тег, Pandoc использует последний увиденный. Но для электронных книг охватывает несколько HTML-документов, <название> S обычно обозначает названия главы и не должно влиять на название книги.

Чтобы исправить это, мы должны погружаться в HTML еще раз 3 убедитесь, что есть только один <название> Тег на наших входных файлах, и это установлено на нужное название книги:

actual_title = 'The Book'

title_node = soup.find('title')
if filename == filenames[0]:
    title_node.string = actual_title
else:
    title_node.extract()

Наконец, оглавление выглядит как ожидалось:

pandoc \
    -o the_book.epub \
    ch1-flat.html \
    ch2-flat.html \
    ch3-flat.html \
    ch4-flat.html

Это было предположительно контролировалось Внутренний переключатель первого порядка в предпочтениях → Плагины → HTML к плагину ZIP Но настроить его, казалось, вообще не влиял. ↩

Мой тезис является очевидным, но и статическим поколением сайта – и этот блог, так и ninjastyles.tznvy.eu Бегите на Pandoc и немного питона. ↩

Это на самом деле звучит как хорошее использование для регеляции. Или $ Редактор Если есть только несколько файлов. Но давайте сделаем это в Python, просто чтобы быть последовательным. ↩

Этот пост был первоначально опубликован на blog.tznvy.eu

Оригинал: “https://dev.to/brthanmathwoag/helping-pandoc-generate-a-correct-table-of-contents-from-html-input-27im”