Pull to refresh

Преобразование FB2 в XHTML с сохранением вложенных рисунков

Reading time 4 min
Views 8.7K
Возникла у меня небольшая необходимость преобразовать книги в формате FB в xhtml.
Ну ясное дело я полез на www.gribuser.ru/xml/fictionbook/2.0/xsl/export где и взял файл
FB2_2_xhtml.xsl (заодно захватил FB2_2_txt.xsl мало ли в текстовом виде понадобится книжку получить )
Попробовал сконвертировать книжку, и заметил маленькую проблемку, рисунки то пропали. :(
В принципе рисунки не главное в книжке, но все равно немного обидно. Поэтому полезем разбираться в чем проблема.

По стандарту FB2 внедренные рисунки описываются в тегах binary.А ссылаются на них с указанием якоря в ссылке, то есть
<img src='#cover.jpg'/>



Сначала возникла мысль просто вытащить рисунки, и положить их в папку с преобразоваемым файлом. Получилось нечто вроде
<?php
$path='book'; //путь к папке куда будем складывать рисунки
$doc=new DOMDocument();
$doc->load($xml_filename);    
$nodes=$doc->getElementsByTagName('binary');
foreach ($nodes as $node)
{
    $value=base64_decode($node->nodeValue);
    $fname= $node->attributes->getNamedItem('id')->nodeValue;
    $fh=fopen($path.'/'.$fname,'w+');
    fwrite($fh,$value);
    fclose($fh);
}


Затем делаем xslt преобразование файлов взятым с офф сайта и радуемся жизнь, рисунки появились. Вот только объем, если делатаь небольшую библиотечку то надо хранить txt файлы, fb2 файлы, xhtml'ку, да и рисунки еще, накладно получается. В принципе можно хранить одну fb2'шку а по обращению получать файл, задержка небольшая, пару секунд и подождать можно (это на нетбуке, на десктопе преобразование выполняется только влет). И тут мне вспомнилось что существует такая вещь как Data Uri, так почему бы не использовать ее и не встроить рисунки прямо в итоговую xhtml'ку. Конечно размер вырастет, но ведь мы получаем xhtml'ку только посмотреть когда нужно, к тому же если такой xsl файл получить то можно будет fb2'ки нормально в браузере читать.
И вот я начал копаться в FB2_2_xhtml.xsl файле.
Сразу видно причину почему пропали рисунки
<xsl:template match="fb:image">
    <div align="center">
        <img border="1">
            <xsl:choose>
                <xsl:when test="starts-with(@xlink:href,'#')">
                    <xsl:attribute name="src"><xsl:value-of select="substring-after(@xlink:href,'#')"/></xsl:attribute>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:attribute name="src"><xsl:value-of select="@xlink:href"/></xsl:attribute>
                </xsl:otherwise>
            </xsl:choose>
        </img>
    </div>
</xsl:template>


в данном случае просто вырезается # перед рисунком. И предполагается что рисунки будут лежать рядом.
После некоторого шаманства получился следующий код

<xsl:when test="starts-with(@xlink:href,'#')">
    <xsl:attribute name="src">
        <xsl:text>data:</xsl:text>
        <xsl:variable name="href" select="substring-after(@xlink:href,'#')" />
        <set variable="href" expression="substring-after(@xlink:href,'#')"/>
        <xsl:value-of select="//fb:binary[@id=$href]/@content-type" disable-output-escaping="yes" />
        <xsl:text>;base64,</xsl:text>
        <xsl:value-of select="//fb:binary[@id=$href]" disable-output-escaping="yes"/>
    </xsl:attribute>
</xsl:when>


Почему то простая конструкция
<xsl:variable name="href" select="substring-after(@xlink:href,'#')" />


у меня не захотела задавать переменную, она не виделась в xpath выражении, после дополнительного определения
<set variable="href" expression="substring-after(@xlink:href,'#')"/>
все заработало как нужно.

Также внес небольшие изменения касающие вывода названия книги сверху
<h4 align="center">
    <xsl:value-of select="fb:description/fb:title-info/fb:book-title"/>
</h4>

А также вывода обложки

<xsl:for-each select="fb:description/fb:title-info/fb:coverpage/fb:image">
    <xsl:call-template name="image"/>
</xsl:for-each>


предварительно исправив <xsl:template match="fb:image"> на <xsl:template match="fb:image" name="image">
Возможно стоит перенести содержание в конец, но в принципе меня и так все устраивает.

Получившийся файл можно взять здесь bit.ly/1JOIvz

P.S. пока искал в нете подходящее решение наткнулся на rusec.livejournal.com/11740.html :)

Ну и касательно fb2 читалки под линуксом не могу процитировать сообщение на которое наткнулся на лоре
Нашел для себя отличный ридер для fictonbook:
«zcat book.fb2.zip|xsltproc FB2_2_txt.xsl -|less -s»
;)

juick.com/demyan/70753



P.P.S. надеюсь это кому нибудь пригодилось. :)
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+36
Comments 5
Comments Comments 5

Articles