FB2 Input: Implement handling of stylesheets and style attributes on <p> tags. Fixes #7219 (FB2 → EPUB without styles)

This commit is contained in:
Kovid Goyal 2010-10-29 11:36:09 -06:00
parent 7603f5b51c
commit 58863d0880
2 changed files with 70 additions and 26 deletions

View File

@ -30,23 +30,40 @@
<title> <title>
<xsl:value-of select="fb:description/fb:title-info/fb:book-title"/> <xsl:value-of select="fb:description/fb:title-info/fb:book-title"/>
</title> </title>
<style type="text/x-oeb1-css"> <style type="text/css">
A { color : #0002CC } a { color : #0002CC }
A:HOVER { color : #BF0000 }
BODY { background-color : #FEFEFE; color : #000000; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; text-align : justify } a:hover { color : #BF0000 }
H1{ font-size : 160%; font-style : normal; font-weight : bold; text-align : left; border : 1px solid Black; background-color : #E7E7E7; margin-left : 0px; page-break-before : always; }
H2{ font-size : 130%; font-style : normal; font-weight : bold; text-align : left; background-color : #EEEEEE; border : 1px solid Gray; page-break-before : always; } body { background-color : #FEFEFE; color : #000000; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; text-align : justify }
H3{ font-size : 110%; font-style : normal; font-weight : bold; text-align : left; background-color : #F1F1F1; border : 1px solid Silver;}
H4{ font-size : 100%; font-style : normal; font-weight : bold; text-align : left; border : 1px solid Gray; background-color : #F4F4F4;} h1{ font-size : 160%; font-style : normal; font-weight : bold; text-align : left; border : 1px solid Black; background-color : #E7E7E7; margin-left : 0px; page-break-before : always; }
H5{ font-size : 100%; font-style : italic; font-weight : bold; text-align : left; border : 1px solid Gray; background-color : #F4F4F4;}
H6{ font-size : 100%; font-style : italic; font-weight : normal; text-align : left; border : 1px solid Gray; background-color : #F4F4F4;} h2{ font-size : 130%; font-style : normal; font-weight : bold; text-align : left; background-color : #EEEEEE; border : 1px solid Gray; page-break-before : always; }
SMALL{ font-size : 80% }
BLOCKQUOTE{ margin-left :4em; margin-top:1em; margin-right:0.2em;} h3{ font-size : 110%; font-style : normal; font-weight : bold; text-align : left; background-color : #F1F1F1; border : 1px solid Silver;}
HR{ color : Black }
DIV{font-family : "Times New Roman", Times, serif; text-align : justify} h4{ font-size : 100%; font-style : normal; font-weight : bold; text-align : left; border : 1px solid Gray; background-color : #F4F4F4;}
UL{margin-left: 0}
.epigraph{width:50%; margin-left : 35%;} h5{ font-size : 100%; font-style : italic; font-weight : bold; text-align : left; border : 1px solid Gray; background-color : #F4F4F4;}
h6{ font-size : 100%; font-style : italic; font-weight : normal; text-align : left; border : 1px solid Gray; background-color : #F4F4F4;}
small { font-size : 80% }
blockquote { margin-left :4em; margin-top:1em; margin-right:0.2em;}
hr { color : Black }
div {font-family : "Times New Roman", Times, serif; text-align : justify}
ul {margin-left: 0}
.epigraph{width:50%; margin-left : 35%;}
div.paragraph { text-align: justify; text-indent: 2em; }
</style> </style>
<link rel="stylesheet" type="text/css" href="inline-styles.css" />
</head> </head>
<body> <body>
<xsl:for-each select="fb:description/fb:title-info/fb:annotation"> <xsl:for-each select="fb:description/fb:title-info/fb:annotation">
@ -136,12 +153,13 @@
</xsl:choose> </xsl:choose>
</xsl:variable> </xsl:variable>
<xsl:if test="$section_has_title = 'None'"> <xsl:if test="$section_has_title = 'None'">
<a name="TOC_{generate-id()}" /> <div id="TOC_{generate-id()}">
<xsl:if test="@id"> <xsl:if test="@id">
<xsl:element name="a"> <xsl:element name="a">
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute> <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
</xsl:element> </xsl:element>
</xsl:if> </xsl:if>
</div>
</xsl:if> </xsl:if>
<xsl:apply-templates> <xsl:apply-templates>
<xsl:with-param name="section_toc_id" select="$section_has_title" /> <xsl:with-param name="section_toc_id" select="$section_has_title" />
@ -207,11 +225,18 @@
</xsl:template> </xsl:template>
<!-- p --> <!-- p -->
<xsl:template match="fb:p"> <xsl:template match="fb:p">
<div align="justify"><xsl:if test="@id"> <xsl:element name="div">
<xsl:attribute name="class">paragraph</xsl:attribute>
<xsl:if test="@id">
<xsl:element name="a"> <xsl:element name="a">
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute> <xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</xsl:element> </xsl:element>
</xsl:if> &#160;&#160;&#160;<xsl:apply-templates/></div> </xsl:if>
<xsl:if test="@style">
<xsl:attribute name="style"><xsl:value-of select="@style"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</xsl:element>
</xsl:template> </xsl:template>
<!-- strong --> <!-- strong -->
<xsl:template match="fb:strong"> <xsl:template match="fb:strong">

View File

@ -40,7 +40,7 @@ class FB2Input(InputFormatPlugin):
accelerators): accelerators):
from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.metadata.opf2 import OPFCreator
from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.oeb.base import XLINK_NS from calibre.ebooks.oeb.base import XLINK_NS, XHTML_NS
NAMESPACES = {'f':FB2NS, 'l':XLINK_NS} NAMESPACES = {'f':FB2NS, 'l':XLINK_NS}
log.debug('Parsing XML...') log.debug('Parsing XML...')
raw = stream.read() raw = stream.read()
@ -48,6 +48,23 @@ class FB2Input(InputFormatPlugin):
doc = etree.fromstring(raw.replace('\0', '')) doc = etree.fromstring(raw.replace('\0', ''))
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
doc = etree.fromstring(raw.replace('& ', '&amp;')) doc = etree.fromstring(raw.replace('& ', '&amp;'))
stylesheets = doc.xpath('//*[local-name() = "stylesheet" and @type="text/css"]')
css = ''
for s in stylesheets:
css += etree.tostring(s, encoding=unicode, method='text',
with_tail=False) + '\n\n'
if css:
import cssutils, logging
parser = cssutils.CSSParser(fetcher=None,
log=logging.getLogger('calibre.css'))
XHTML_CSS_NAMESPACE = '@namespace "%s";\n' % XHTML_NS
text = XHTML_CSS_NAMESPACE + css
log.debug('Parsing stylesheet...')
stylesheet = parser.parseString(text)
stylesheet.namespaces['h'] = XHTML_NS
css = unicode(stylesheet.cssText).replace('h|style', 'h|span')
css = re.sub(r'name\s*=\s*', 'class=', css)
self.extract_embedded_content(doc) self.extract_embedded_content(doc)
log.debug('Converting XML to HTML...') log.debug('Converting XML to HTML...')
ss = open(P('templates/fb2.xsl'), 'rb').read() ss = open(P('templates/fb2.xsl'), 'rb').read()
@ -63,7 +80,9 @@ class FB2Input(InputFormatPlugin):
for img in result.xpath('//img[@src]'): for img in result.xpath('//img[@src]'):
src = img.get('src') src = img.get('src')
img.set('src', self.binary_map.get(src, src)) img.set('src', self.binary_map.get(src, src))
open('index.xhtml', 'wb').write(transform.tostring(result)) index = transform.tostring(result)
open('index.xhtml', 'wb').write(index)
open('inline-styles.css', 'wb').write(css)
stream.seek(0) stream.seek(0)
mi = get_metadata(stream, 'fb2') mi = get_metadata(stream, 'fb2')
if not mi.title: if not mi.title: