forked from openlp/openlp
Start XML refactoring
bzr-revno: 914
This commit is contained in:
commit
a3f562e356
@ -60,18 +60,6 @@
|
||||
.. autoclass:: openlp.core.lib.settingstab.SettingsTab
|
||||
:members:
|
||||
|
||||
:mod:`SongXMLBuilder`
|
||||
---------------------
|
||||
|
||||
.. autoclass:: openlp.core.lib.songxmlhandler.SongXMLBuilder
|
||||
:members:
|
||||
|
||||
:mod:`SongXMLParser`
|
||||
--------------------
|
||||
|
||||
.. autoclass:: openlp.core.lib.songxmlhandler.SongXMLParser
|
||||
:members:
|
||||
|
||||
:mod:`ThemeXML`
|
||||
---------------
|
||||
|
||||
@ -83,10 +71,3 @@
|
||||
|
||||
.. autoclass:: openlp.core.lib.toolbar.OpenLPToolbar
|
||||
:members:
|
||||
|
||||
:mod:`XmlRootClass`
|
||||
-------------------
|
||||
|
||||
.. autoclass:: openlp.core.lib.xmlrootclass.XmlRootClass
|
||||
:members:
|
||||
|
||||
|
@ -202,28 +202,17 @@ def check_item_selected(list_widget, message):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class ThemeLevel(object):
|
||||
"""
|
||||
Provides an enumeration for the level a theme applies to
|
||||
"""
|
||||
Global = 1
|
||||
Service = 2
|
||||
Song = 3
|
||||
|
||||
from eventreceiver import Receiver
|
||||
from settingsmanager import SettingsManager
|
||||
from plugin import PluginStatus, Plugin
|
||||
from pluginmanager import PluginManager
|
||||
from settingstab import SettingsTab
|
||||
from xmlrootclass import XmlRootClass
|
||||
from serviceitem import ServiceItem
|
||||
from serviceitem import ServiceItemType
|
||||
from serviceitem import ItemCapabilities
|
||||
from toolbar import OpenLPToolbar
|
||||
from dockwidget import OpenLPDockWidget
|
||||
from songxmlhandler import SongXMLBuilder, SongXMLParser
|
||||
from themexmlhandler import ThemeXML
|
||||
from theme import ThemeLevel, ThemeXML
|
||||
from renderer import Renderer
|
||||
from rendermanager import RenderManager
|
||||
from mediamanageritem import MediaManagerItem
|
||||
|
@ -79,6 +79,14 @@ BLANK_THEME_XML = \
|
||||
</theme>
|
||||
'''
|
||||
|
||||
class ThemeLevel(object):
|
||||
"""
|
||||
Provides an enumeration for the level a theme applies to
|
||||
"""
|
||||
Global = 1
|
||||
Service = 2
|
||||
Song = 3
|
||||
|
||||
class ThemeXML(object):
|
||||
"""
|
||||
A class to encapsulate the Theme XML.
|
||||
@ -313,7 +321,6 @@ class ThemeXML(object):
|
||||
element.appendChild(value)
|
||||
background.appendChild(element)
|
||||
|
||||
|
||||
def child_element(self, element, tag, value):
|
||||
"""
|
||||
Generic child element creator.
|
||||
@ -414,4 +421,3 @@ class ThemeXML(object):
|
||||
if key[0:1] != u'_':
|
||||
theme_strings.append(u'%30s: %s' % (key, getattr(self, key)))
|
||||
return u'\n'.join(theme_strings)
|
||||
|
@ -1,104 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
|
||||
# Thompson, Jon Tibble, Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from xml.etree.ElementTree import ElementTree, XML
|
||||
|
||||
sys.path.append(os.path.abspath(os.path.join(u'.', u'..', u'..')))
|
||||
|
||||
class XmlRootClass(object):
|
||||
"""
|
||||
Root class for themes, songs etc
|
||||
|
||||
This class provides interface for parsing xml files into object attributes.
|
||||
|
||||
If you overload this class and provide a function called `post_tag_hook`,
|
||||
it will be called thusly for each `tag, value` pair::
|
||||
|
||||
(element.tag, val) = self.post_tag_hook(element.tag, val)
|
||||
"""
|
||||
def _set_from_xml(self, xml, root_tag):
|
||||
"""
|
||||
Set song properties from given xml content.
|
||||
|
||||
``xml``
|
||||
Formatted xml tags and values.
|
||||
``root_tag``
|
||||
The root tag of the xml.
|
||||
"""
|
||||
root = ElementTree(element=XML(xml))
|
||||
xml_iter = root.getiterator()
|
||||
for element in xml_iter:
|
||||
if element.tag != root_tag:
|
||||
text = element.text
|
||||
if text is None:
|
||||
val = text
|
||||
elif isinstance(text, basestring):
|
||||
# Strings need special handling to sort the colours out
|
||||
if text[0] == u'$':
|
||||
# This might be a hex number, let's try to convert it.
|
||||
try:
|
||||
val = int(text[1:], 16)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
# Let's just see if it's a integer.
|
||||
try:
|
||||
val = int(text)
|
||||
except ValueError:
|
||||
# Ok, it seems to be a string.
|
||||
val = text
|
||||
if hasattr(self, u'post_tag_hook'):
|
||||
(element.tag, val) = \
|
||||
self.post_tag_hook(element.tag, val)
|
||||
setattr(self, element.tag, val)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Return string with all public attributes
|
||||
|
||||
The string is formatted with one attribute per line
|
||||
If the string is split on newline then the length of the
|
||||
list is equal to the number of attributes
|
||||
"""
|
||||
attributes = []
|
||||
for attrib in dir(self):
|
||||
if not attrib.startswith(u'_'):
|
||||
attributes.append(
|
||||
u'%30s : %s' % (attrib, getattr(self, attrib)))
|
||||
return u'\n'.join(attributes)
|
||||
|
||||
def _get_as_string(self):
|
||||
"""
|
||||
Return one string with all public attributes
|
||||
"""
|
||||
result = u''
|
||||
for attrib in dir(self):
|
||||
if not attrib.startswith(u'_'):
|
||||
result += u'_%s_' % getattr(self, attrib)
|
||||
return result
|
||||
|
@ -222,4 +222,3 @@ class Theme(object):
|
||||
if key[0:1] != u'_':
|
||||
theme_strings.append(u'%30s : %s' % (key, getattr(self, key)))
|
||||
return u'\n'.join(theme_strings)
|
||||
|
||||
|
@ -28,7 +28,8 @@ import logging
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from editcustomdialog import Ui_customEditDialog
|
||||
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate
|
||||
from openlp.core.lib import Receiver, translate
|
||||
from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser
|
||||
from openlp.plugins.custom.lib.db import CustomSlide
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -119,8 +120,8 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
|
||||
self.customSlide = self.custommanager.get_object(CustomSlide, id)
|
||||
self.TitleEdit.setText(self.customSlide.title)
|
||||
self.CreditEdit.setText(self.customSlide.credits)
|
||||
songXML = SongXMLParser(self.customSlide.text)
|
||||
verseList = songXML.get_verses()
|
||||
customXML = CustomXMLParser(self.customSlide.text)
|
||||
verseList = customXML.get_verses()
|
||||
for verse in verseList:
|
||||
self.VerseListView.addItem(verse[1])
|
||||
theme = self.customSlide.theme_name
|
||||
@ -152,7 +153,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
|
||||
translate('CustomPlugin.EditCustomForm', 'Error'), message,
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
return False
|
||||
sxml = SongXMLBuilder()
|
||||
sxml = CustomXMLBuilder()
|
||||
sxml.new_document()
|
||||
sxml.add_lyrics_to_song()
|
||||
count = 1
|
||||
|
@ -23,5 +23,6 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from customxmlhandler import CustomXMLBuilder, CustomXMLParser
|
||||
from mediaitem import CustomMediaItem
|
||||
from customtab import CustomTab
|
||||
|
@ -23,7 +23,8 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`songxmlhandler` module provides the XML functionality for songs
|
||||
The :mod:`customxmlhandler` module provides the XML functionality for custom
|
||||
slides
|
||||
|
||||
The basic XML is of the format::
|
||||
|
||||
@ -45,26 +46,26 @@ from xml.parsers.expat import ExpatError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SongXMLBuilder(object):
|
||||
class CustomXMLBuilder(object):
|
||||
"""
|
||||
This class builds the XML used to describe songs.
|
||||
"""
|
||||
log.info(u'SongXMLBuilder Loaded')
|
||||
log.info(u'CustomXMLBuilder Loaded')
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Set up the song builder.
|
||||
"""
|
||||
# Create the minidom document
|
||||
self.song_xml = Document()
|
||||
self.custom_xml = Document()
|
||||
|
||||
def new_document(self):
|
||||
"""
|
||||
Create a new song XML document.
|
||||
"""
|
||||
# Create the <song> base element
|
||||
self.song = self.song_xml.createElement(u'song')
|
||||
self.song_xml.appendChild(self.song)
|
||||
self.song = self.custom_xml.createElement(u'song')
|
||||
self.custom_xml.appendChild(self.song)
|
||||
self.song.setAttribute(u'version', u'1.0')
|
||||
|
||||
def add_lyrics_to_song(self):
|
||||
@ -73,7 +74,7 @@ class SongXMLBuilder(object):
|
||||
song.
|
||||
"""
|
||||
# Create the main <lyrics> element
|
||||
self.lyrics = self.song_xml.createElement(u'lyrics')
|
||||
self.lyrics = self.custom_xml.createElement(u'lyrics')
|
||||
self.lyrics.setAttribute(u'language', u'en')
|
||||
self.song.appendChild(self.lyrics)
|
||||
|
||||
@ -92,32 +93,32 @@ class SongXMLBuilder(object):
|
||||
The actual text of the verse to be stored.
|
||||
"""
|
||||
#log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content))
|
||||
verse = self.song_xml.createElement(u'verse')
|
||||
verse = self.custom_xml.createElement(u'verse')
|
||||
verse.setAttribute(u'type', type)
|
||||
verse.setAttribute(u'label', number)
|
||||
self.lyrics.appendChild(verse)
|
||||
# add data as a CDATA section to protect the XML from special chars
|
||||
cds = self.song_xml.createCDATASection(content)
|
||||
cds = self.custom_xml.createCDATASection(content)
|
||||
verse.appendChild(cds)
|
||||
|
||||
def dump_xml(self):
|
||||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
return self.song_xml.toprettyxml(indent=u' ')
|
||||
return self.custom_xml.toprettyxml(indent=u' ')
|
||||
|
||||
def extract_xml(self):
|
||||
"""
|
||||
Extract our newly created XML song.
|
||||
"""
|
||||
return self.song_xml.toxml(u'utf-8')
|
||||
return self.custom_xml.toxml(u'utf-8')
|
||||
|
||||
|
||||
class SongXMLParser(object):
|
||||
class CustomXMLParser(object):
|
||||
"""
|
||||
A class to read in and parse a song's XML.
|
||||
"""
|
||||
log.info(u'SongXMLParser Loaded')
|
||||
log.info(u'CustomXMLParser Loaded')
|
||||
|
||||
def __init__(self, xml):
|
||||
"""
|
||||
@ -126,9 +127,9 @@ class SongXMLParser(object):
|
||||
``xml``
|
||||
The XML of the song to be parsed.
|
||||
"""
|
||||
self.song_xml = None
|
||||
self.custom_xml = None
|
||||
try:
|
||||
self.song_xml = ElementTree(
|
||||
self.custom_xml = ElementTree(
|
||||
element=XML(unicode(xml).encode('unicode-escape')))
|
||||
except ExpatError:
|
||||
log.exception(u'Invalid xml %s', xml)
|
||||
@ -138,7 +139,7 @@ class SongXMLParser(object):
|
||||
Iterates through the verses in the XML and returns a list of verses
|
||||
and their attributes.
|
||||
"""
|
||||
xml_iter = self.song_xml.getiterator()
|
||||
xml_iter = self.custom_xml.getiterator()
|
||||
verse_list = []
|
||||
for element in xml_iter:
|
||||
if element.tag == u'verse':
|
||||
@ -152,4 +153,4 @@ class SongXMLParser(object):
|
||||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
return dump(self.song_xml)
|
||||
return dump(self.custom_xml)
|
@ -27,8 +27,9 @@ import logging
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import MediaManagerItem, SongXMLParser, BaseListWithDnD, \
|
||||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, \
|
||||
Receiver, ItemCapabilities, translate, check_item_selected
|
||||
from openlp.plugins.custom.lib import CustomXMLParser
|
||||
from openlp.plugins.custom.lib.db import CustomSlide
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -170,8 +171,8 @@ class CustomMediaItem(MediaManagerItem):
|
||||
theme = customSlide.theme_name
|
||||
if theme:
|
||||
service_item.theme = theme
|
||||
songXML = SongXMLParser(customSlide.text)
|
||||
verseList = songXML.get_verses()
|
||||
customXML = CustomXMLParser(customSlide.text)
|
||||
verseList = customXML.get_verses()
|
||||
for verse in verseList:
|
||||
raw_slides.append(verse[1])
|
||||
service_item.title = title
|
||||
|
@ -28,9 +28,9 @@ import re
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate
|
||||
from openlp.core.lib import Receiver, translate
|
||||
from openlp.plugins.songs.forms import EditVerseForm
|
||||
from openlp.plugins.songs.lib import VerseType
|
||||
from openlp.plugins.songs.lib import SongXMLBuilder, SongXMLParser, VerseType
|
||||
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic
|
||||
from editsongdialog import Ui_EditSongDialog
|
||||
|
||||
@ -639,8 +639,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
log.debug(u'processLyrics')
|
||||
try:
|
||||
sxml = SongXMLBuilder()
|
||||
sxml.new_document()
|
||||
sxml.add_lyrics_to_song()
|
||||
text = u''
|
||||
multiple = []
|
||||
for i in range (0, self.VerseListWidget.rowCount()):
|
||||
@ -666,4 +664,3 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
log.debug(u'processTitle')
|
||||
self.song.search_title = \
|
||||
re.sub(r'[\'"`,;:(){}?]+', u'', unicode(self.song.search_title))
|
||||
|
||||
|
@ -137,6 +137,7 @@ class VerseType(object):
|
||||
unicode(VerseType.to_string(VerseType.Other)).lower():
|
||||
return VerseType.Other
|
||||
|
||||
from xml import LyricsXML, SongXMLBuilder, SongXMLParser
|
||||
from songstab import SongsTab
|
||||
from mediaitem import SongMediaItem
|
||||
from songimport import SongImport
|
||||
@ -145,4 +146,3 @@ try:
|
||||
from oooimport import OooImport
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
@ -27,10 +27,11 @@ import logging
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import MediaManagerItem, SongXMLParser, Receiver, \
|
||||
BaseListWithDnD, ItemCapabilities, translate, check_item_selected
|
||||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \
|
||||
ItemCapabilities, translate, check_item_selected
|
||||
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
|
||||
ImportWizardForm
|
||||
from openlp.plugins.songs.lib import SongXMLParser
|
||||
from openlp.plugins.songs.lib.db import Author, Song
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
import re
|
||||
|
||||
from openlp.core.lib import SongXMLBuilder, translate
|
||||
from openlp.plugins.songs.lib import VerseType
|
||||
from openlp.core.lib import translate
|
||||
from openlp.plugins.songs.lib import SongXMLBuilder, VerseType
|
||||
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book
|
||||
|
||||
class SongImport(object):
|
||||
@ -276,8 +276,6 @@ class SongImport(object):
|
||||
song.song_number = self.song_number
|
||||
song.search_lyrics = u''
|
||||
sxml = SongXMLBuilder()
|
||||
sxml.new_document()
|
||||
sxml.add_lyrics_to_song()
|
||||
for (versetag, versetext) in self.verses:
|
||||
if versetag[0] == u'C':
|
||||
versetype = VerseType.to_string(VerseType.Chorus)
|
||||
|
@ -24,18 +24,18 @@
|
||||
###############################################################################
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
#import sys
|
||||
#import os
|
||||
|
||||
from types import ListType
|
||||
from xml.etree.ElementTree import ElementTree, XML
|
||||
|
||||
sys.path.append(os.path.abspath(u'./../../../..'))
|
||||
|
||||
from openlp.core.lib import XmlRootClass
|
||||
# Do we need these two lines?
|
||||
#sys.path.append(os.path.abspath(u'./../../../..'))
|
||||
#sys.path.append(os.path.abspath(os.path.join(u'.', u'..', u'..')))
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SongException(Exception):
|
||||
pass
|
||||
|
||||
@ -74,23 +74,78 @@ _BLANK_OPENSONG_XML = \
|
||||
</song>
|
||||
'''
|
||||
|
||||
class _OpenSong(XmlRootClass):
|
||||
"""Class for import of OpenSong"""
|
||||
|
||||
class _OpenSong(object):
|
||||
"""
|
||||
Class for import of OpenSong
|
||||
"""
|
||||
def __init__(self, xmlContent = None):
|
||||
"""Initialize from given xml content"""
|
||||
super(_OpenSong, self).__init__()
|
||||
self.from_buffer(xmlContent)
|
||||
|
||||
def _reset(self):
|
||||
"""Reset all song attributes"""
|
||||
self._setFromXml(_BLANK_OPENSONG_XML, 'song')
|
||||
|
||||
def from_buffer(self, xmlContent):
|
||||
"""Initialize from buffer(string) with xml content"""
|
||||
self._reset()
|
||||
"""
|
||||
Initialize from given xml content
|
||||
"""
|
||||
self._set_from_xml(_BLANK_OPENSONG_XML, 'song')
|
||||
if xmlContent:
|
||||
self._setFromXml(xmlContent, 'song')
|
||||
self._set_from_xml(xmlContent, 'song')
|
||||
|
||||
def _set_from_xml(self, xml, root_tag):
|
||||
"""
|
||||
Set song properties from given xml content.
|
||||
|
||||
``xml``
|
||||
Formatted xml tags and values.
|
||||
``root_tag``
|
||||
The root tag of the xml.
|
||||
"""
|
||||
root = ElementTree(element=XML(xml))
|
||||
xml_iter = root.getiterator()
|
||||
for element in xml_iter:
|
||||
if element.tag != root_tag:
|
||||
text = element.text
|
||||
if text is None:
|
||||
val = text
|
||||
elif isinstance(text, basestring):
|
||||
# Strings need special handling to sort the colours out
|
||||
if text[0] == u'$':
|
||||
# This might be a hex number, let's try to convert it.
|
||||
try:
|
||||
val = int(text[1:], 16)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
# Let's just see if it's a integer.
|
||||
try:
|
||||
val = int(text)
|
||||
except ValueError:
|
||||
# Ok, it seems to be a string.
|
||||
val = text
|
||||
if hasattr(self, u'post_tag_hook'):
|
||||
(element.tag, val) = \
|
||||
self.post_tag_hook(element.tag, val)
|
||||
setattr(self, element.tag, val)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Return string with all public attributes
|
||||
|
||||
The string is formatted with one attribute per line
|
||||
If the string is split on newline then the length of the
|
||||
list is equal to the number of attributes
|
||||
"""
|
||||
attributes = []
|
||||
for attrib in dir(self):
|
||||
if not attrib.startswith(u'_'):
|
||||
attributes.append(
|
||||
u'%30s : %s' % (attrib, getattr(self, attrib)))
|
||||
return u'\n'.join(attributes)
|
||||
|
||||
def _get_as_string(self):
|
||||
"""
|
||||
Return one string with all public attributes
|
||||
"""
|
||||
result = u''
|
||||
for attrib in dir(self):
|
||||
if not attrib.startswith(u'_'):
|
||||
result += u'_%s_' % getattr(self, attrib)
|
||||
return result
|
||||
|
||||
def get_author_list(self):
|
||||
"""Convert author field to an authorlist
|
||||
@ -252,14 +307,6 @@ class Song(object):
|
||||
self.set_lyrics(u'')
|
||||
return
|
||||
|
||||
def set_songid(self, songid):
|
||||
"""Set the songid for the database"""
|
||||
self.songid = songid
|
||||
|
||||
def get_songid(self):
|
||||
"""Return the songid for the database"""
|
||||
return self.songid
|
||||
|
||||
def from_opensong_buffer(self, xmlcontent):
|
||||
"""Initialize from buffer(string) of xml lines in opensong format"""
|
||||
self._reset()
|
||||
@ -323,10 +370,6 @@ class Song(object):
|
||||
"""Return title value"""
|
||||
return self.title
|
||||
|
||||
def get_search_title(self):
|
||||
"""Return search_title"""
|
||||
return self.search_title
|
||||
|
||||
def from_ccli_text_buffer(self, textList):
|
||||
"""
|
||||
Create song from a list of texts (strings) - CCLI text format expected
|
||||
|
@ -22,24 +22,123 @@
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`xml` module provides the XML functionality for songs
|
||||
|
||||
The basic XML is of the format::
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<song version="1.0">
|
||||
<lyrics language="en">
|
||||
<verse type="chorus" label="1">
|
||||
<![CDATA[ ... ]]>
|
||||
</verse>
|
||||
</lyrics>
|
||||
</song>
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from lxml import etree, objectify
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SongXMLBuilder(object):
|
||||
"""
|
||||
This class builds the XML used to describe songs.
|
||||
"""
|
||||
log.info(u'SongXMLBuilder Loaded')
|
||||
|
||||
def __init__(self, song_language=None):
|
||||
"""
|
||||
Set up the song builder.
|
||||
|
||||
``song_language``
|
||||
The language used in this song
|
||||
"""
|
||||
lang = u'en'
|
||||
if song_language:
|
||||
lang = song_language
|
||||
self.song_xml = objectify.fromstring(u'<song version="1.0" />')
|
||||
self.lyrics = etree.SubElement(self.song_xml, u'lyrics', language=lang)
|
||||
|
||||
def add_verse_to_lyrics(self, type, number, content):
|
||||
"""
|
||||
Add a verse to the ``<lyrics>`` tag.
|
||||
|
||||
``type``
|
||||
A string denoting the type of verse. Possible values are "Chorus",
|
||||
"Verse", "Bridge", and "Custom".
|
||||
|
||||
``number``
|
||||
An integer denoting the number of the item, for example: verse 1.
|
||||
|
||||
``content``
|
||||
The actual text of the verse to be stored.
|
||||
"""
|
||||
#log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content))
|
||||
verse = etree.SubElement(self.lyrics, u'verse', type=type, label=number)
|
||||
verse.text = etree.CDATA(content)
|
||||
|
||||
def dump_xml(self):
|
||||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
return etree.tostring(self.song_xml, encoding=u'UTF-8',
|
||||
xml_declaration=True, pretty_print=True)
|
||||
|
||||
def extract_xml(self):
|
||||
"""
|
||||
Extract our newly created XML song.
|
||||
"""
|
||||
return etree.tostring(self.song_xml, encoding=u'UTF-8',
|
||||
xml_declaration=True)
|
||||
|
||||
|
||||
class SongXMLParser(object):
|
||||
"""
|
||||
A class to read in and parse a song's XML.
|
||||
"""
|
||||
log.info(u'SongXMLParser Loaded')
|
||||
|
||||
def __init__(self, xml):
|
||||
"""
|
||||
Set up our song XML parser.
|
||||
|
||||
``xml``
|
||||
The XML of the song to be parsed.
|
||||
"""
|
||||
self.song_xml = None
|
||||
try:
|
||||
self.song_xml = objectify.fromstring(str(xml))
|
||||
except etree.XMLSyntaxError:
|
||||
log.exception(u'Invalid xml %s', xml)
|
||||
|
||||
def get_verses(self):
|
||||
"""
|
||||
Iterates through the verses in the XML and returns a list of verses
|
||||
and their attributes.
|
||||
"""
|
||||
xml_iter = self.song_xml.getiterator()
|
||||
verse_list = []
|
||||
for element in xml_iter:
|
||||
if element.tag == u'verse':
|
||||
if element.text is None:
|
||||
element.text = u''
|
||||
verse_list.append([element.attrib,
|
||||
unicode(element.text).decode('unicode-escape')])
|
||||
return verse_list
|
||||
|
||||
def dump_xml(self):
|
||||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
return etree.dump(self.song_xml)
|
||||
|
||||
from lxml import objectify
|
||||
from lxml.etree import XMLSyntaxError
|
||||
|
||||
class LyricsXML(object):
|
||||
"""
|
||||
This class represents the XML in the ``lyrics`` field of a song.
|
||||
|
||||
The basic XML looks like this::
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<song version="1.0">
|
||||
<lyrics language="en">
|
||||
<verse type="chorus" label="1">
|
||||
<![CDATA[ ... ]]>
|
||||
</verse>
|
||||
</lyrics>
|
||||
</song>
|
||||
"""
|
||||
def __init__(self, song=None):
|
||||
if song:
|
||||
@ -74,7 +173,7 @@ class LyricsXML(object):
|
||||
})
|
||||
self.lyrics.append(language)
|
||||
return True
|
||||
except XMLSyntaxError:
|
||||
except etree.XMLSyntaxError:
|
||||
return False
|
||||
|
||||
def extract(self, text):
|
||||
@ -136,4 +235,3 @@ class LyricsXML(object):
|
||||
song_output = u'<?xml version="1.0" encoding="UTF-8"?>' + \
|
||||
u'<song version="1.0">%s</song>' % lyrics_output
|
||||
return song_output
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user