diff --git a/src/calibre/ebooks/metadata/opf3.py b/src/calibre/ebooks/metadata/opf3.py
index 6283a8d594..6339ba32f4 100644
--- a/src/calibre/ebooks/metadata/opf3.py
+++ b/src/calibre/ebooks/metadata/opf3.py
@@ -10,7 +10,7 @@ import re
from lxml import etree
-from calibre.ebooks.metadata import check_isbn, authors_to_string
+from calibre.ebooks.metadata import check_isbn, authors_to_string, string_to_authors
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.utils import parse_opf, pretty_print_opf, ensure_unique, normalize_languages
from calibre.ebooks.oeb.base import OPF2_NSMAP, OPF, DC
@@ -93,7 +93,15 @@ def properties_for_id_with_scheme(item_id, prefixes, refines):
ans[key] = (scheme_ns, scheme, val)
return ans
-def ensure_id(root, elem):
+def getroot(elem):
+ while True:
+ q = elem.getparent()
+ if q is None:
+ return elem
+ elem = q
+
+def ensure_id(elem):
+ root = getroot(elem)
eid = elem.get('id')
if not eid:
eid = ensure_unique('id', frozenset(XPath('//*/@id')(root)))
@@ -124,6 +132,15 @@ def read_prefixes(root):
def expand_prefix(raw, prefixes):
return regex(r'(\S+)\s*:\s*(\S+)').sub(lambda m:(prefixes.get(m.group(1), m.group(1)) + ':' + m.group(2)), raw)
+
+def ensure_prefix(root, prefixes, prefix, value):
+ prefixes[prefix] = value
+ prefixes = {k:v for k, v in prefixes.iteritems() if reserved_prefixes.get(k) != v}
+ if prefixes:
+ root.set('prefix', ' '.join('%s: %s' % (k, v) for k, v in prefixes.iteritems()))
+ else:
+ root.attrib.pop('prefix', None)
+
# }}}
# Refines {{{
@@ -139,7 +156,7 @@ def refdef(prop, val, scheme=None):
return (prop, val, scheme)
def set_refines(elem, existing_refines, *new_refines):
- eid = ensure_id(elem.getroottree().getroot(), elem)
+ eid = ensure_id(elem)
remove_refines(elem, existing_refines)
for ref in reversed(new_refines):
prop, val, scheme = ref
@@ -362,6 +379,28 @@ def read_authors(root, prefixes, refines):
return uniq(roled_authors or unroled_authors)
+def set_authors(root, prefixes, refines, authors):
+ ensure_prefix(root, prefixes, 'marc', reserved_prefixes['marc'])
+ for item in XPath('./opf:metadata/dc:creator')(root):
+ props = properties_for_id_with_scheme(item.get('id'), prefixes, refines)
+ role = props.get('role')
+ opf_role = item.get(OPF('role'))
+ if (role and role.lower() != 'aut') or (opf_role and opf_role.lower() != 'aut'):
+ continue
+ remove_element(item, refines)
+ metadata = XPath('./opf:metadata')(root)[0]
+ for author in authors:
+ a = metadata.makeelement(DC('creator'))
+ aid = ensure_id(a)
+ a.text = author.name
+ metadata.append(a)
+ m = metadata.makeelement(OPF('meta'), attrib={'refines':'#'+aid, 'property':'role', 'scheme':'marc:relators'})
+ m.text = 'aut'
+ metadata.append(m)
+ if author.sort:
+ m = metadata.makeelement(OPF('meta'), attrib={'refines':'#'+aid, 'property':'file-as'})
+ m.text = author.sort
+ metadata.append(m)
# }}}
def read_metadata(root):
@@ -394,6 +433,11 @@ def apply_metadata(root, mi, cover_prefix='', cover_data=None, apply_null=False,
set_identifiers(root, prefixes, refines, mi.identifiers, force_identifiers=force_identifiers)
set_title(root, prefixes, refines, mi.title, mi.title_sort)
set_languages(root, prefixes, refines, mi.languages)
+ aus = string_to_authors(mi.author_sort or '')
+ authors = []
+ for i, aut in enumerate(mi.authors):
+ authors.append(Author(aut, aus[i] if i < len(aus) else None))
+ set_authors(root, prefixes, refines, authors)
pretty_print_opf(root)
diff --git a/src/calibre/ebooks/metadata/opf3_test.py b/src/calibre/ebooks/metadata/opf3_test.py
index 2f2397275e..2db9b7fca6 100644
--- a/src/calibre/ebooks/metadata/opf3_test.py
+++ b/src/calibre/ebooks/metadata/opf3_test.py
@@ -13,7 +13,7 @@ from calibre.ebooks.metadata.opf3 import (
parse_prefixes, reserved_prefixes, expand_prefix, read_identifiers,
read_metadata, set_identifiers, XPath, set_application_id, read_title,
read_refines, set_title, read_title_sort, read_languages, set_languages,
- read_authors, Author
+ read_authors, Author, set_authors
)
TEMPLATE = '''{metadata}''' # noqa
@@ -107,8 +107,8 @@ class TestOPF3(unittest.TestCase):
def test_authors(self): # {{{
def rl(root):
return read_authors(root, reserved_prefixes, read_refines(root))
- def st(root, languages):
- set_languages(root, reserved_prefixes, read_refines(root), languages)
+ def st(root, authors):
+ set_authors(root, reserved_prefixes, read_refines(root), authors)
return rl(root)
root = self.get_opf('''a b''')
self.ae([Author('a b', None)], rl(root))
@@ -121,6 +121,9 @@ class TestOPF3(unittest.TestCase):
root = self.get_opf('''a bc d
d, c''')
self.ae([Author('a b', 'b, a'), Author('c d', 'd, c')], rl(root))
+ authors = [Author('x y', 'y, x'), Author('u i', None)]
+ self.ae(authors, st(root, authors))
+ self.assertIsNone(root.get('prefix'))
# }}}
# Run tests {{{