Как я могу использовать сценарий для изменения текста в файле epub?

Я недавно купил Nook Simple Touch. Я использую Caliber для управления своими электронными книгами и для переноса их в Nook.

Из-за нестандартной реализации спецификации epub со стороны B&N Nook ST не отображает изображения обложек, когда они получены из многих источников. Проблема описана здесь: http://john.nachtimwald.com/2011/08/21/nook-covers-not-showing-up/ Обычно Nook ST требует, чтобы атрибут XML для обложки был в формате:

<meta name="cover" content="id5" />

Но у многих создателей epub они примерно такие:

<meta content="id5" name="cover" />

Затем Nook ST полностью игнорирует изображение обложки.

Я вручную редактировал файл content.opf в своих файлах epub. До сих пор у всех была мета изображения, но она всегда была «неправильной» (неправильной, согласно Nook).

Недавно я играл с REGEX, в основном чтобы попытаться автоматизировать очистку файлов epub, преобразованных Caliber из файлов PDF. Я все еще новичок в REGEX.

Мне было интересно, как я могу автоматизировать замену атрибутов «имя» и «содержимое»? Я полагаю, что это можно сделать с помощью комбинации REGEX и сценариев. Я знаю, что некоторые из других скриптов, связанных с epub, у меня есть на Python. Я использую Mac (OS X), и они, кажется, работают нормально. AppleScript тоже может быть хорошим вариантом, хотя я бы хотел, чтобы люди могли запускать что-то на любой платформе, поскольку я уверен, что другие сочтут это полезным.

Вот шаги, которые я предвижу:

~ Извлечь файл epub

~ Используйте REGEX для поиска:

<meta content="???" name="cover">

~ Если найдено, используйте REGEX, чтобы изменить его на:

<meta name="cover" content="???">

~ Заархивируйте извлеченные файлы обратно в epub, используя правильный процесс архивирования.

Я нашел информацию здесь: http://www.mobileread.com/forums/showthread.php?t=55681, объясняющий, как правильно заархивировать файл epub. В основном для этого требуются эти две команды:

zip -X0 "full path to new epub file" mimetype
zip -rDX9 "full path to new epub file" * -x "*.DS_Store" -x mimetype

Я хотел бы опубликовать получившийся скрипт в Интернете, где бы он ни был найден и использовался (пока B&N не разрешит их плохую реализацию epub / XML). На ум приходит размещение его на форумах Caliber и форумах mobileread (поскольку это два, с которыми я знаком, и видел, как люди обсуждали ручные исправления этой проблемы).

Есть ли кто-нибудь, кто может объяснить мне, как создать такой сценарий? В идеале мне бы хотелось знать, как создать сценарий, чтобы со временем я мог сам начать разбираться в подобных вещах (особенно в части REGEX, поскольку я все больше и больше вижу, насколько это полезно).

Спасибо.

Джонатан

@Haldean: ДОБАВЛЕНО, чтобы проиллюстрировать, что я имею в виду в комментарии к Haldean относительно того, как заставить его скрипт рекурсивно работать со всеми файлами content.opf во всех подпапках.

> My_expanded_epubs
- -> epub_one_expanded
- - - -> content.opf
- -> epub_two_expanded
- - - -> content.opf
- -> epub_three_expanded
- - - -> content.opf
etc.

person inspirednz    schedule 17.02.2012    source источник
comment
У вас есть регулярное выражение, которое может правильно определять метатеги, которые вы ищете?   -  person Marcin    schedule 17.02.2012
comment
Также стоит пожаловаться в B&N. Нет никакого оправдания наличию процессора XML, который требует, чтобы атрибуты располагались в каком-либо определенном порядке.   -  person Marcin    schedule 17.02.2012
comment
Спасибо, Марчин. Посылаю сообщение B&N по этому поводу.   -  person inspirednz    schedule 17.02.2012
comment
Я искал в Stackoverflow и Google для распаковки файла epub python, но ничего полезного не нашел. Я лаю не на то дерево с этой идеей? Я нашел много вещей об удалении DRM из epub с помощью python, но не о простой распаковке epub (и его переупаковке). Я знаю, что, скорее всего, смогу использовать AppleScript для объединения различных шагов, но на самом деле хочу, чтобы это не зависело от платформы.   -  person inspirednz    schedule 18.02.2012


Ответы (4)


Если вы хотите использовать сценарий оболочки (который, я думаю, является лучшим вариантом), вы можете использовать однострочник sed:

sed 's/<meta content="\(.*\)" name="cover" \/>/<meta name="cover" content="\1" \/>/' [your-file]

Это должно заменить все мета-строки, где атрибут content идет первым, на строку с правильным порядком. Эквивалентный перевод на Python:

import re
import sys
with open(sys.argv[1]) as f:
  for line in f:
    # Match this line to the wrong-way-around meta tag, put the content in group 1
    m = re.match(r'<meta content="(.*)" name="cover" />', line)
    if not m:
      print line
    else:
      print '<meta name="cover" content="%s" />' % m.group(1)
person Haldean Brown    schedule 17.02.2012
comment
Обратите внимание, что ваши регулярные выражения не устойчивы к любым вариациям интервалов. - person Marcin; 17.02.2012
comment
Спасибо, Холдин. Python выглядит относительно простым языком для понимания. Напоминает мне Basic ... с которым я играл, наверное, 25 лет назад. Я попробую это, возможно, с предоставленным регулярным выражением Marcin по причинам, которые он упомянул. - person inspirednz; 18.02.2012
comment
@Haldean: Вы случайно не знаете, как использовать Python для распаковки и перепаковки файла epub? Кажется, я нигде не могу найти эту информацию. Это нужно сделать так, как указано в моем исходном посте. - person inspirednz; 18.02.2012
comment
@Haldean Хорошо, я возился с Python, но так и не смог понять (или код), как реализовать немного другое регулярное выражение, предложенное Марчином. Я также был бы признателен за то, чтобы узнать, как заставить этот скрипт рекурсивно проверять файл content.opf во всех папках (расширенные файлы epub). Я попытался разместить здесь пример, но в комментариях не распознаются разрывы строк, поэтому я добавил его в конец своего исходного сообщения. - person inspirednz; 22.02.2012

Я бы посоветовал вам использовать sed для работы с распакованным файлом и сделать что-то вроде:

sed -e 's/<[ ]*meta[ ]*content[ ]*=[ ]*"\(.*\)"[ ]*name[ ]*=[ ]*"cover"[ ]*\/*[ ]*>/<meta name="cover" content="\1" \/>/g'

Обратите внимание, что эта версия справится с лишним или отсутствующим пробелом или косой чертой.

Вы можете впоследствии использовать xml-процессор (я бы предложил сценарий python, использующий lxml), чтобы убедиться, что ваше редактирование не создало какой-либо недопустимой разметки.

Использование любого инструмента XML для выполнения манипуляции крайне непривлекательно, потому что полностью совместимый процессор XML может вносить другие изменения, которые полностью законны, а также вызывать другие ошибки в вашем укромном уголке. Использование sed позволяет редактировать только те части документа, которые вы хотите.

person Marcin    schedule 17.02.2012
comment
Спасибо за то, что вы так тщательно обдумали это. Я опробую ваше предложение в ближайшее время (был офлайн весь день, отсюда и задержка с ответом). Если все манипуляции с тегами в порядке, другой шаг, который я хотел бы решить, - это как позаботиться о других шагах. Например, распаковать epub, запустить проверку регулярного выражения, перепаковать epub. Если у кого-то есть много файлов epub, которые они хотят загрузить в свой Nook ST, большая часть времени будет потрачена просто на распаковку и переупаковку. Было бы неплохо просто запустить сценарий для файла, рекурсивно обрабатывая все файлы epub в нем. - person inspirednz; 18.02.2012
comment
Я могу довольно легко проверить сами файлы epub с помощью Caliber (насколько я помню). Было бы неплохо. Спасибо. - person inspirednz; 18.02.2012
comment
@inspiredlife: Если у вас возникли проблемы с распаковкой и т. д., я предлагаю вам задать отдельный вопрос. - person Marcin; 19.02.2012

Лично я бы не стал делать это с регулярным выражением (это неправильный инструмент). Не могли бы вы использовать XSLT?


РЕДАКТИРОВАТЬ:

Вот демо. http://www.xsltcake.com/slices/nvLRJ6

Существует ряд библиотек XSLT для python.


РЕДАКТИРОВАТЬ:

Если вы настаиваете на использовании регулярного выражения, вам понадобится такой шаблон:
<meta content="([^"]+)" name="([^"]+)" \/>

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

http://regexr.com?301uq

person Sam Greenhalgh    schedule 17.02.2012
comment
Хорошо. Спасибо за предложение. Я просмотрел предоставленную вами ссылку. Мне непонятно, как использовать XSLT (то, о чем я никогда не слышал до сих пор) как часть автоматизации текущей задачи. Какие-либо предложения? Я также прочитал страницу, на которую ссылалась та, на которую вы указали. Я не нашел ничего, что мог бы понять, как двигаться дальше. - person inspirednz; 17.02.2012
comment
Итак, я узнал больше о том, почему регулярное выражение может не подходить для поиска рассматриваемого атрибута XML. Хотя я еще не уверен, что нельзя использовать регулярное выражение для поиска чего-то настолько простого. Это может быть связано с моим незнанием ограничений регулярного выражения. - person inspirednz; 17.02.2012
comment
@inspiredlife: я бы сказал, что регулярные выражения здесь являются правильным инструментом, потому что не может быть способа заставить соответствующий XML-синтаксический анализатор выводить свойства в желаемом порядке, и любое решение, которое включает в себя синтаксический анализ всего документа, рискует вызвать другие ошибки в затронутых выполнение. Напротив, такой инструмент, как sed, позволит вам редактировать только те части документа, которые вы хотите изменить. - person Marcin; 17.02.2012

Я согласен с ответом zapthedingbat: это проблема XML, поэтому давайте использовать инструменты, специально разработанные для XML, а именно XSLT.

Поскольку вы новичок в XSLT, вам понадобится процессор XSLT, чтобы опробовать это решение. Если вы используете * nix, xsltproc является процессором командной строки и почти наверняка установлен по умолчанию, и вы можете принять это решение за чистую монету. Если нет, вам нужно будет проверить, есть ли у вашего выбранного языка API для выполнения XSL-преобразований.

Вот очень простое общее решение для изменения порядка атрибутов:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="@*|node()">
  <!-- copy everything as is -->
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="meta">
    <!-- except for the <meta/> element, reverse the attribute order -->
    <meta name="{@name}" content="{@content}"/>
  </xsl:template>
</xsl:stylesheet>

Вот ваш пример:

<root>
  <meta content="id5" name="cover" />
</root>

Запуск XSLT с xsltproc:

$ xsltproc so.xsl so.xml

и результат:

<root>
  <meta name="cover" content="id5"/>
</root>
person Zach Young    schedule 17.02.2012
comment
Почему голос против? Этот ответ полностью отвечает на вопрос Как я могу использовать сценарий для изменения некоторого текста в файле epub? - person Zach Young; 17.02.2012
comment
Использование любого вида обработки XML крайне непривлекательно, поскольку вы не знаете, какая допустимая разметка вызовет другие ошибки в этом укромном уголке. Здесь требуется целевое редактирование текста. - person Marcin; 17.02.2012
comment
@Marcin Можно ли назвать непривлекательным? - person Zach Young; 17.02.2012
comment
Прочтите оставшуюся часть моего предложения. - person Marcin; 17.02.2012
comment
@Marcin Можете ли вы доказать, что это не сработает? Отмечать ответ, потому что он может вызвать проблемы, кажется несправедливым. Я за то, чтобы узнать что-то новое и занять иную позицию, когда я представляю факты, но, насколько я могу видеть, это всего лишь предположения. - person Zach Young; 17.02.2012
comment
Вот факты: есть ошибочный процессор XML; известно, что как минимум в одном случае он не справляется с действующей разметкой; кроме этого, документы в форме, полученной OP, похоже, не содержат ошибок. Также фактом является то, что соответствующему процессору XSLT разрешено изменять поток символов, который он получает, способом, который не указан в XSLT, если эти изменения приводят к XML с точно таким же значением. Соответственно, вы рискуете внести нежелательные изменения во входной документ. Ваше решение принципиально небезопасно. - person Marcin; 17.02.2012