143
143
self.song_xml = None
145
if not xml.startswith(u'<?xml') and not xml.startswith(u'<song'):
145
if not xml.startswith('<?xml') and not xml.startswith('<song'):
146
146
# This is an old style song, without XML. Let's handle it correctly
147
147
# by iterating through the verses, and then recreating the internal
148
148
# xml object as well.
149
self.song_xml = objectify.fromstring(u'<song version="1.0" />')
150
self.lyrics = etree.SubElement(self.song_xml, u'lyrics')
151
verses = xml.split(u'\n\n')
149
self.song_xml = objectify.fromstring('<song version="1.0" />')
150
self.lyrics = etree.SubElement(self.song_xml, 'lyrics')
151
verses = xml.split('\n\n')
152
152
for count, verse in enumerate(verses):
153
verse_list.append([{u'type': u'v', u'label': unicode(count)}, unicode(verse)])
154
self.add_verse_to_lyrics(u'v', unicode(count), verse)
153
verse_list.append([{'type': 'v', 'label': str(count)}, str(verse)])
154
self.add_verse_to_lyrics('v', str(count), verse)
155
155
return verse_list
156
elif xml.startswith(u'<?xml'):
156
elif xml.startswith('<?xml'):
159
159
self.song_xml = objectify.fromstring(xml)
160
160
except etree.XMLSyntaxError:
161
log.exception(u'Invalid xml %s', xml)
161
log.exception('Invalid xml %s', xml)
162
162
xml_iter = self.song_xml.getiterator()
163
163
for element in xml_iter:
164
if element.tag == u'verse':
164
if element.tag == 'verse':
165
165
if element.text is None:
167
verse_list.append([element.attrib, unicode(element.text)])
167
verse_list.append([element.attrib, str(element.text)])
168
168
return verse_list
170
170
def dump_xml(self):
270
270
Convert the song to OpenLyrics Format.
273
song_xml = objectify.fromstring(u'<song/>')
273
song_xml = objectify.fromstring('<song/>')
274
274
# Append the necessary meta data to the song.
275
song_xml.set(u'xmlns', NAMESPACE)
276
song_xml.set(u'version', OpenLyrics.IMPLEMENTED_VERSION)
277
application_name = u'OpenLP ' + get_application_version()[u'version']
278
song_xml.set(u'createdIn', application_name)
279
song_xml.set(u'modifiedIn', application_name)
275
song_xml.set('xmlns', NAMESPACE)
276
song_xml.set('version', OpenLyrics.IMPLEMENTED_VERSION)
277
application_name = 'OpenLP ' + get_application_version()['version']
278
song_xml.set('createdIn', application_name)
279
song_xml.set('modifiedIn', application_name)
280
280
# "Convert" 2012-08-27 11:49:15 to 2012-08-27T11:49:15.
281
song_xml.set(u'modifiedDate', unicode(song.last_modified).replace(u' ', u'T'))
282
properties = etree.SubElement(song_xml, u'properties')
283
titles = etree.SubElement(properties, u'titles')
284
self._add_text_to_element(u'title', titles, song.title)
281
song_xml.set('modifiedDate', str(song.last_modified).replace(' ', 'T'))
282
properties = etree.SubElement(song_xml, 'properties')
283
titles = etree.SubElement(properties, 'titles')
284
self._add_text_to_element('title', titles, song.title)
285
285
if song.alternate_title:
286
self._add_text_to_element(u'title', titles, song.alternate_title)
286
self._add_text_to_element('title', titles, song.alternate_title)
287
287
if song.comments:
288
comments = etree.SubElement(properties, u'comments')
289
self._add_text_to_element(u'comment', comments, song.comments)
288
comments = etree.SubElement(properties, 'comments')
289
self._add_text_to_element('comment', comments, song.comments)
290
290
if song.copyright:
291
self._add_text_to_element(u'copyright', properties, song.copyright)
291
self._add_text_to_element('copyright', properties, song.copyright)
292
292
if song.verse_order:
293
293
self._add_text_to_element(
294
u'verseOrder', properties, song.verse_order.lower())
294
'verseOrder', properties, song.verse_order.lower())
295
295
if song.ccli_number:
296
self._add_text_to_element(u'ccliNo', properties, song.ccli_number)
296
self._add_text_to_element('ccliNo', properties, song.ccli_number)
298
authors = etree.SubElement(properties, u'authors')
298
authors = etree.SubElement(properties, 'authors')
299
299
for author in song.authors:
300
self._add_text_to_element(u'author', authors, author.display_name)
300
self._add_text_to_element('author', authors, author.display_name)
301
301
book = self.manager.get_object_filtered(Book, Book.id == song.song_book_id)
302
302
if book is not None:
304
songbooks = etree.SubElement(properties, u'songbooks')
305
element = self._add_text_to_element(u'songbook', songbooks, None, book)
304
songbooks = etree.SubElement(properties, 'songbooks')
305
element = self._add_text_to_element('songbook', songbooks, None, book)
306
306
if song.song_number:
307
element.set(u'entry', song.song_number)
307
element.set('entry', song.song_number)
309
themes = etree.SubElement(properties, u'themes')
309
themes = etree.SubElement(properties, 'themes')
310
310
for topic in song.topics:
311
self._add_text_to_element(u'theme', themes, topic.name)
311
self._add_text_to_element('theme', themes, topic.name)
312
312
# Process the formatting tags.
313
313
# Have we any tags in song lyrics?
314
314
tags_element = None
315
match = re.search(u'\{/?\w+\}', song.lyrics, re.UNICODE)
315
match = re.search('\{/?\w+\}', song.lyrics, re.UNICODE)
317
317
# Named 'format_' - 'format' is built-in fuction in Python.
318
format_ = etree.SubElement(song_xml, u'format')
319
tags_element = etree.SubElement(format_, u'tags')
320
tags_element.set(u'application', u'OpenLP')
318
format_ = etree.SubElement(song_xml, 'format')
319
tags_element = etree.SubElement(format_, 'tags')
320
tags_element.set('application', 'OpenLP')
321
321
# Process the song's lyrics.
322
lyrics = etree.SubElement(song_xml, u'lyrics')
322
lyrics = etree.SubElement(song_xml, 'lyrics')
323
323
verse_list = sxml.get_verses(song.lyrics)
324
324
# Add a suffix letter to each verse
326
326
for verse in verse_list:
327
verse_tag = verse[0][u'type'][0].lower()
328
verse_number = verse[0][u'label']
327
verse_tag = verse[0]['type'][0].lower()
328
verse_number = verse[0]['label']
329
329
verse_def = verse_tag + verse_number
330
330
verse_tags.append(verse_def)
331
331
# Create the letter from the number of duplicates
332
verse[0][u'suffix'] = chr(96 + verse_tags.count(verse_def))
332
verse[0]['suffix'] = chr(96 + verse_tags.count(verse_def))
333
333
# If the verse tag is a duplicate use the suffix letter
334
334
for verse in verse_list:
335
verse_tag = verse[0][u'type'][0].lower()
336
verse_number = verse[0][u'label']
335
verse_tag = verse[0]['type'][0].lower()
336
verse_number = verse[0]['label']
337
337
verse_def = verse_tag + verse_number
338
338
if verse_tags.count(verse_def) > 1:
339
verse_def += verse[0][u'suffix']
340
verse_element = self._add_text_to_element(u'verse', lyrics, None, verse_def)
341
if u'lang' in verse[0]:
342
verse_element.set(u'lang', verse[0][u'lang'])
339
verse_def += verse[0]['suffix']
340
verse_element = self._add_text_to_element('verse', lyrics, None, verse_def)
341
if 'lang' in verse[0]:
342
verse_element.set('lang', verse[0]['lang'])
343
343
# Create a list with all "optional" verses.
344
344
optional_verses = cgi.escape(verse[1])
345
optional_verses = optional_verses.split(u'\n[---]\n')
345
optional_verses = optional_verses.split('\n[---]\n')
348
348
for index, optional_verse in enumerate(optional_verses):
349
349
# Fix up missing end and start tags such as {r} or {/r}.
350
350
optional_verse = start_tags + optional_verse
454
454
available_tags = FormattingTags.get_html_tags()
455
455
start_tag = '{%s}' % tag_name
456
456
for tag in available_tags:
457
if tag[u'start tag'] == start_tag:
457
if tag['start tag'] == start_tag:
458
458
# Create new formatting tag in openlyrics xml.
459
element = self._add_text_to_element(u'tag', tags_element)
460
element.set(u'name', tag_name)
461
element_open = self._add_text_to_element(u'open', element)
462
element_open.text = etree.CDATA(tag[u'start html'])
459
element = self._add_text_to_element('tag', tags_element)
460
element.set('name', tag_name)
461
element_open = self._add_text_to_element('open', element)
462
element_open.text = etree.CDATA(tag['start html'])
463
463
# Check if formatting tag contains end tag. Some formatting
464
464
# tags e.g. {br} has only start tag. If no end tag is present
465
465
# <close> element has not to be in OpenLyrics xml.
466
466
if tag['end tag']:
467
element_close = self._add_text_to_element(u'close', element)
468
element_close.text = etree.CDATA(tag[u'end html'])
467
element_close = self._add_text_to_element('close', element)
468
element_close.text = etree.CDATA(tag['end html'])
470
470
def _add_text_with_tags_to_lines(self, verse_element, text, tags_element):
589
589
Process the formatting tags from the song and either add missing tags
590
590
temporary or permanently to the formatting tag list.
592
if not hasattr(song_xml, u'format'):
592
if not hasattr(song_xml, 'format'):
595
595
for tag in song_xml.format.tags.getchildren():
596
name = tag.get(u'name')
596
name = tag.get('name')
599
start_tag = u'{%s}' % name[:5]
599
start_tag = '{%s}' % name[:5]
600
600
# Some tags have only start tag e.g. {br}
601
end_tag = u'{/' + name[:5] + u'}' if hasattr(tag, 'close') else u''
601
end_tag = '{/' + name[:5] + '}' if hasattr(tag, 'close') else ''
604
u'start tag': start_tag,
606
u'start html': tag.open.text,
604
'start tag': start_tag,
606
'start html': tag.open.text,
607
607
# Some tags have only start html e.g. {br}
608
u'end html': tag.close.text if hasattr(tag, 'close') else u'',
608
'end html': tag.close.text if hasattr(tag, 'close') else '',
611
611
# Add 'temporary' key in case the formatting tag should not be
612
612
# saved otherwise it is supposed that formatting tag is permanent.
614
openlp_tag[u'temporary'] = temporary
614
openlp_tag['temporary'] = temporary
615
615
found_tags.append(openlp_tag)
616
existing_tag_ids = [tag[u'start tag'] for tag in FormattingTags.get_html_tags()]
617
new_tags = [tag for tag in found_tags if tag[u'start tag'] not in existing_tag_ids]
616
existing_tag_ids = [tag['start tag'] for tag in FormattingTags.get_html_tags()]
617
new_tags = [tag for tag in found_tags if tag['start tag'] not in existing_tag_ids]
618
618
FormattingTags.add_html_tags(new_tags)
619
619
FormattingTags.save_html_tags()
729
729
translate('OpenLP.OpenLyricsImportError', '<verse> tag is missing.'))
730
730
# Loop over the "verse" elements.
731
731
for verse in verse_list:
733
733
# Loop over the "lines" elements.
734
734
for lines in verse.lines:
737
737
# Append text from "lines" element to verse text.
738
738
text += self._process_verse_lines(lines,
739
version=song_xml.get(u'version'))
739
version=song_xml.get('version'))
740
740
# Add an optional split to the verse text.
741
if lines.get(u'break') is not None:
743
verse_def = verse.get(u'name', u' ').lower()
741
if lines.get('break') is not None:
743
verse_def = verse.get('name', ' ').lower()
744
744
verse_tag, verse_number, verse_part = OpenLyrics.VERSE_TAG_SPLITTER.search(verse_def).groups()
745
745
if verse_tag not in VerseType.Tags:
746
746
verse_tag = VerseType.Tags[VerseType.Other]
747
747
# OpenLyrics allows e. g. "c", but we need "c1". However, this does
748
748
# not correct the verse order.
749
749
if not verse_number:
751
lang = verse.get(u'lang')
752
translit = verse.get(u'translit')
751
lang = verse.get('lang')
752
translit = verse.get('translit')
753
753
# In OpenLP 1.9.6 we used v1a, v1b ... to represent visual slide
754
754
# breaks. In OpenLyrics 0.7 an attribute has been added.
755
if song_xml.get(u'modifiedIn') in (u'1.9.6', u'OpenLP 1.9.6') and \
756
song_xml.get(u'version') == u'0.7' and (verse_tag, verse_number, lang, translit) in verses:
757
verses[(verse_tag, verse_number, lang, translit, None)] += u'\n[---]\n' + text
755
if song_xml.get('modifiedIn') in ('1.9.6', 'OpenLP 1.9.6') and \
756
song_xml.get('version') == '0.7' and (verse_tag, verse_number, lang, translit) in verses:
757
verses[(verse_tag, verse_number, lang, translit, None)] += '\n[---]\n' + text
758
758
# Merge v1a, v1b, .... to v1.
759
759
elif (verse_tag, verse_number, lang, translit, verse_part) in verses:
760
verses[(verse_tag, verse_number, lang, translit, verse_part)] += u'\n' + text
760
verses[(verse_tag, verse_number, lang, translit, verse_part)] += '\n' + text
762
762
verses[(verse_tag, verse_number, lang, translit, verse_part)] = text
763
763
verse_def_list.append((verse_tag, verse_number, lang, translit, verse_part))
764
764
# We have to use a list to keep the order, as dicts are not sorted.
765
765
for verse in verse_def_list:
766
766
sxml.add_verse_to_lyrics(verse[0], verse[1], verses[verse], verse[2])
767
song_obj.lyrics = unicode(sxml.extract_xml(), u'utf-8')
767
song_obj.lyrics = str(sxml.extract_xml(), 'utf-8')
768
768
# Process verse order
769
if hasattr(properties, u'verseOrder'):
769
if hasattr(properties, 'verseOrder'):
770
770
song_obj.verse_order = self._text(properties.verseOrder)
772
772
def _process_songbooks(self, properties, song):