This commit is contained in:
Kovid Goyal 2009-01-29 22:46:07 -08:00
commit 00820d24f4
2 changed files with 48 additions and 31 deletions

View File

@ -16,9 +16,9 @@
<dc:description py:if="mi.comments">${mi.comments}</dc:description> <dc:description py:if="mi.comments">${mi.comments}</dc:description>
<dc:publisher py:if="mi.publisher">${mi.publisher}</dc:publisher> <dc:publisher py:if="mi.publisher">${mi.publisher}</dc:publisher>
<dc:identifier opf:scheme="ISBN" py:if="mi.isbn">${mi.isbn}</dc:identifier> <dc:identifier opf:scheme="ISBN" py:if="mi.isbn">${mi.isbn}</dc:identifier>
<series py:if="mi.series">${mi.series}</series> <meta py:if="mi.series is not None" name="series" content="${mi.series}"/>
<series_index py:if="mi.series_index is not None">${mi.series_index}</series_index> <meta py:if="mi.series_index is not None" name="series_index" content="${mi.series_index}"/>
<rating py:if="mi.rating is not None">${mi.rating}</rating> <meta py:if="mi.rating is not None" name="rating" content="${mi.rating}"/>
<py:for each="tag in mi.tags"> <py:for each="tag in mi.tags">
<dc:subject py:if="mi.tags is not None">${tag}</dc:subject> <dc:subject py:if="mi.tags is not None">${tag}</dc:subject>
</py:for> </py:for>

View File

@ -392,8 +392,8 @@ class MetadataField(object):
def __set__(self, obj, val): def __set__(self, obj, val):
elem = obj.get_metadata_element(self.name) elem = obj.get_metadata_element(self.name)
if elem is None: if elem is None:
elem = obj.create_metadata_element(self.name, ns='dc' if self.is_dc else 'opf') elem = obj.create_metadata_element(self.name, is_dc=self.is_dc)
elem.text = unicode(val) obj.set_text(elem, unicode(val))
class OPF(object): class OPF(object):
MIMETYPE = 'application/oebps-package+xml' MIMETYPE = 'application/oebps-package+xml'
@ -403,16 +403,18 @@ class OPF(object):
'dc' : "http://purl.org/dc/elements/1.1/", 'dc' : "http://purl.org/dc/elements/1.1/",
'opf' : "http://www.idpf.org/2007/opf", 'opf' : "http://www.idpf.org/2007/opf",
} }
META = '{%s}meta' % NAMESPACES['opf']
xpn = NAMESPACES.copy() xpn = NAMESPACES.copy()
xpn.pop(None) xpn.pop(None)
xpn['re'] = 'http://exslt.org/regular-expressions' xpn['re'] = 'http://exslt.org/regular-expressions'
XPath = functools.partial(etree.XPath, namespaces=xpn) XPath = functools.partial(etree.XPath, namespaces=xpn)
CONTENT = XPath('self::*[re:match(name(), "meta$", "i")]/@content')
TEXT = XPath('string()') TEXT = XPath('string()')
metadata_path = XPath('descendant::*[re:match(name(), "metadata", "i")]') metadata_path = XPath('descendant::*[re:match(name(), "metadata", "i")]')
metadata_elem_path = XPath('descendant::*[re:match(name(), $name, "i")]') metadata_elem_path = XPath('descendant::*[re:match(name(), $name, "i") or (re:match(name(), "^meta$", "i") and re:match(@name, $name, "i"))]')
series_path = XPath('descendant::*[re:match(name(), "series$", "i")]') series_path = XPath('descendant::*[re:match(name(), "series$", "i") or (re:match(name(), "^meta$", "i") and re:match(@name, "series$", "i"))]')
authors_path = XPath('descendant::*[re:match(name(), "creator", "i") and (@role="aut" or @opf:role="aut" or (not(@role) and not(@opf:role)))]') authors_path = XPath('descendant::*[re:match(name(), "creator", "i") and (@role="aut" or @opf:role="aut" or (not(@role) and not(@opf:role)))]')
bkp_path = XPath('descendant::*[re:match(name(), "contributor", "i") and (@role="bkp" or @opf:role="bkp")]') bkp_path = XPath('descendant::*[re:match(name(), "contributor", "i") and (@role="bkp" or @opf:role="bkp")]')
tags_path = XPath('descendant::*[re:match(name(), "subject", "i")]') tags_path = XPath('descendant::*[re:match(name(), "subject", "i")]')
@ -497,7 +499,13 @@ class OPF(object):
def get_text(self, elem): def get_text(self, elem):
return u''.join(self.TEXT(elem)) return u''.join(self.CONTENT(elem) or self.TEXT(elem))
def set_text(self, elem, content):
if elem.tag == self.META:
elem.attib['content'] = content
else:
elem.text = content
def itermanifest(self): def itermanifest(self):
return self.manifest_path(self.root) return self.manifest_path(self.root)
@ -611,9 +619,9 @@ class OPF(object):
for elem in remove: for elem in remove:
self.metadata.remove(elem) self.metadata.remove(elem)
for author in val: for author in val:
elem = self.create_metadata_element('creator', ns='dc', attrib = {'{%s}role'%self.NAMESPACES['opf']: 'aut'}
attrib={'{%s}role'%self.NAMESPACES['opf']:'aut'}) elem = self.create_metadata_element('creator', attrib=attrib)
elem.text = author self.set_text(elem, author)
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@ -650,8 +658,8 @@ class OPF(object):
for tag in list(self.tags_path(self.metadata)): for tag in list(self.tags_path(self.metadata)):
self.metadata.remove(tag) self.metadata.remove(tag)
for tag in val: for tag in val:
elem = self.create_metadata_element('subject', ns='dc') elem = self.create_metadata_element('subject')
elem.text = unicode(tag) self.set_text(elem, unicode(tag))
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@ -660,14 +668,15 @@ class OPF(object):
def fget(self): def fget(self):
for match in self.isbn_path(self.metadata): for match in self.isbn_path(self.metadata):
return match.text if match.text else None return self.get_text(match) or None
def fset(self, val): def fset(self, val):
matches = self.isbn_path(self.metadata) matches = self.isbn_path(self.metadata)
if not matches: if not matches:
matches = [self.create_metadata_element('identifier', ns='dc', attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'ISBN'}
attrib={'{%s}scheme'%self.NAMESPACES['opf']:'ISBN'})] matches = [self.create_metadata_element('identifier',
matches[0].text = unicode(val) attrib=attrib)]
self.set_text(matches[0], unicode(val))
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@ -676,14 +685,15 @@ class OPF(object):
def fget(self): def fget(self):
for match in self.application_id_path(self.metadata): for match in self.application_id_path(self.metadata):
return match.text if match.text else None return self.get_text(match) or None
def fset(self, val): def fset(self, val):
matches = self.application_id_path(self.metadata) matches = self.application_id_path(self.metadata)
if not matches: if not matches:
matches = [self.create_metadata_element('identifier', ns='dc', attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'calibre'}
attrib={'{%s}scheme'%self.NAMESPACES['opf']:'calibre'})] matches = [self.create_metadata_element('identifier',
matches[0].text = unicode(val) attrib=attrib)]
self.set_text(matches[0], unicode(val))
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@ -693,13 +703,13 @@ class OPF(object):
def fget(self): def fget(self):
for match in self.series_path(self.metadata): for match in self.series_path(self.metadata):
return match.text if match.text else None return self.get_text(match) or None
def fset(self, val): def fset(self, val):
matches = self.series_path(self.metadata) matches = self.series_path(self.metadata)
if not matches: if not matches:
matches = [self.create_metadata_element('series')] matches = [self.create_metadata_element('series', is_dc=False)]
matches[0].text = unicode(val) self.set_text(matches[0], unicode(val))
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@ -710,14 +720,15 @@ class OPF(object):
def fget(self): def fget(self):
for match in self.bkp_path(self.metadata): for match in self.bkp_path(self.metadata):
return match.text if match.text else None return self.get_text(match) or None
def fset(self, val): def fset(self, val):
matches = self.bkp_path(self.metadata) matches = self.bkp_path(self.metadata)
if not matches: if not matches:
matches = [self.create_metadata_element('contributor', ns='dc', attrib = {'{%s}role'%self.NAMESPACES['opf']: 'bkp'}
attrib={'{%s}role'%self.NAMESPACES['opf']:'bkp'})] matches = [self.create_metadata_element('contributor',
matches[0].text = unicode(val) attrib=attrib)]
self.set_text(matches[0], unicode(val))
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@ -783,9 +794,15 @@ class OPF(object):
if matches: if matches:
return matches[-1] return matches[-1]
def create_metadata_element(self, name, attrib=None, ns='opf'): def create_metadata_element(self, name, attrib=None, is_dc=True):
elem = etree.SubElement(self.metadata, '{%s}%s'%(self.NAMESPACES[ns], name), if is_dc:
attrib=attrib, nsmap=self.NAMESPACES) name = '{%s}%s' % (self.NAMESPACES['dc'], name)
else:
attrib = attrib or {}
attrib['name'] = name
name = '{%s}%s' % (self.NAMESPACES['opf'], 'meta')
elem = etree.SubElement(self.metadata, name, attrib=attrib,
nsmap=self.NAMESPACES)
elem.tail = '\n' elem.tail = '\n'
return elem return elem