← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~meths/openlp/testing into lp:openlp

 

Jon Tibble has proposed merging lp:~meths/openlp/testing into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)


I think I'm looking for comments at this stage unless everyone thinks it's okay.
Two questions:
1 - Is the code okay to merge at the moment or do people want it refactored in one rather than stages?
2 - Should it go into trunk or go to Martin's branch first?

What it does:
* Enforce the plugin isolation
  * Songs and custom now each control their own XML
* Move code to more logical areas for what it does
* Remove some unused code
* Start refactoring songs (objectify) so it doesn't get confused with xml modules
-- 
https://code.launchpad.net/~meths/openlp/testing/+merge/29151
Your team OpenLP Core is requested to review the proposed merge of lp:~meths/openlp/testing into lp:openlp.
=== modified file 'documentation/source/core/lib.rst'
--- documentation/source/core/lib.rst	2010-05-01 20:00:01 +0000
+++ documentation/source/core/lib.rst	2010-07-03 18:02:24 +0000
@@ -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:
-

=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2010-06-25 00:30:26 +0000
+++ openlp/core/lib/__init__.py	2010-07-03 18:02:24 +0000
@@ -202,28 +202,17 @@
         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

=== renamed file 'openlp/core/lib/themexmlhandler.py' => 'openlp/core/lib/theme.py'
--- openlp/core/lib/themexmlhandler.py	2010-06-25 00:24:56 +0000
+++ openlp/core/lib/theme.py	2010-07-03 18:02:24 +0000
@@ -79,6 +79,14 @@
  </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 @@
         element.appendChild(value)
         background.appendChild(element)
 
-
     def child_element(self, element, tag, value):
         """
         Generic child element creator.
@@ -414,4 +421,3 @@
             if key[0:1] != u'_':
                 theme_strings.append(u'%30s: %s' % (key, getattr(self, key)))
         return u'\n'.join(theme_strings)
-

=== removed file 'openlp/core/lib/xmlrootclass.py'
--- openlp/core/lib/xmlrootclass.py	2010-06-12 20:22:58 +0000
+++ openlp/core/lib/xmlrootclass.py	1970-01-01 00:00:00 +0000
@@ -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
-

=== modified file 'openlp/plugins/custom/forms/editcustomform.py'
--- openlp/plugins/custom/forms/editcustomform.py	2010-06-28 13:38:29 +0000
+++ openlp/plugins/custom/forms/editcustomform.py	2010-07-03 18:02:24 +0000
@@ -28,7 +28,8 @@
 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 @@
             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 @@
                 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

=== modified file 'openlp/plugins/custom/lib/__init__.py'
--- openlp/plugins/custom/lib/__init__.py	2010-06-15 02:08:22 +0000
+++ openlp/plugins/custom/lib/__init__.py	2010-07-03 18:02:24 +0000
@@ -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

=== added file 'openlp/plugins/custom/lib/customxmlhandler.py'
--- openlp/plugins/custom/lib/customxmlhandler.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/custom/lib/customxmlhandler.py	2010-07-03 18:02:24 +0000
@@ -0,0 +1,156 @@
+# -*- 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                          #
+###############################################################################
+"""
+The :mod:`customxmlhandler` module provides the XML functionality for custom
+slides
+
+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 xml.dom.minidom import Document
+from xml.etree.ElementTree import ElementTree, XML, dump
+from xml.parsers.expat import ExpatError
+
+log = logging.getLogger(__name__)
+
+class CustomXMLBuilder(object):
+    """
+    This class builds the XML used to describe songs.
+    """
+    log.info(u'CustomXMLBuilder Loaded')
+
+    def __init__(self):
+        """
+        Set up the song builder.
+        """
+        # Create the minidom document
+        self.song_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.setAttribute(u'version', u'1.0')
+
+    def add_lyrics_to_song(self):
+        """
+        Set up and add a ``<lyrics>`` tag which contains the lyrics of the
+        song.
+        """
+        # Create the main <lyrics> element
+        self.lyrics = self.song_xml.createElement(u'lyrics')
+        self.lyrics.setAttribute(u'language', u'en')
+        self.song.appendChild(self.lyrics)
+
+    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 = self.song_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)
+        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'  ')
+
+    def extract_xml(self):
+        """
+        Extract our newly created XML song.
+        """
+        return self.song_xml.toxml(u'utf-8')
+
+
+class CustomXMLParser(object):
+    """
+    A class to read in and parse a song's XML.
+    """
+    log.info(u'CustomXMLParser 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 = ElementTree(
+                element=XML(unicode(xml).encode('unicode-escape')))
+        except ExpatError:
+            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 dump(self.song_xml)

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2010-07-02 17:00:23 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2010-07-03 18:02:24 +0000
@@ -27,8 +27,9 @@
 
 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 @@
         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

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2010-07-02 18:21:45 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2010-07-03 18:02:24 +0000
@@ -28,9 +28,9 @@
 
 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 @@
         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()):

=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py	2010-06-30 22:05:51 +0000
+++ openlp/plugins/songs/lib/__init__.py	2010-07-03 18:02:24 +0000
@@ -137,6 +137,7 @@
             unicode(VerseType.to_string(VerseType.Other)).lower():
             return VerseType.Other
 
+from songxmlhandler import SongXMLBuilder, SongXMLParser
 from songstab import SongsTab
 from mediaitem import SongMediaItem
 from songimport import SongImport

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2010-07-02 12:13:46 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2010-07-03 18:02:24 +0000
@@ -27,10 +27,11 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import MediaManagerItem, SongXMLParser, \
-    BaseListWithDnD, Receiver, 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 Song
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/plugins/songs/lib/songimport.py'
--- openlp/plugins/songs/lib/songimport.py	2010-06-30 22:05:51 +0000
+++ openlp/plugins/songs/lib/songimport.py	2010-07-03 18:02:24 +0000
@@ -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 @@
         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)

=== modified file 'openlp/plugins/songs/lib/songxml.py'
--- openlp/plugins/songs/lib/songxml.py	2010-06-09 17:09:32 +0000
+++ openlp/plugins/songs/lib/songxml.py	2010-07-03 18:02:24 +0000
@@ -24,18 +24,18 @@
 ###############################################################################
 
 import logging
-import sys
-import os
+#import sys
+#import os
 
 from types import ListType
-
-sys.path.append(os.path.abspath(u'./../../../..'))
-
-from openlp.core.lib import XmlRootClass
+from xml.etree.ElementTree import ElementTree, XML
+
+# 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 @@
 </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 @@
         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 @@
         """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

=== renamed file 'openlp/core/lib/songxmlhandler.py' => 'openlp/plugins/songs/lib/songxmlhandler.py'
--- openlp/core/lib/songxmlhandler.py	2010-06-10 21:30:50 +0000
+++ openlp/plugins/songs/lib/songxmlhandler.py	2010-07-03 18:02:24 +0000
@@ -38,10 +38,10 @@
 """
 
 import logging
+import StringIO
 
-from xml.dom.minidom import Document
-from xml.etree.ElementTree import ElementTree, XML, dump
-from xml.parsers.expat import ExpatError
+from lxml import etree, objectify
+#from lxml.etree import SubElement, XMLSyntaxError, dump
 
 log = logging.getLogger(__name__)
 
@@ -51,31 +51,18 @@
     """
     log.info(u'SongXMLBuilder Loaded')
 
-    def __init__(self):
+    def __init__(self, song_language=None):
         """
         Set up the song builder.
-        """
-        # Create the minidom document
-        self.song_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.setAttribute(u'version', u'1.0')
-
-    def add_lyrics_to_song(self):
-        """
-        Set up and add a ``<lyrics>`` tag which contains the lyrics of the
-        song.
-        """
-        # Create the main <lyrics> element
-        self.lyrics = self.song_xml.createElement(u'lyrics')
-        self.lyrics.setAttribute(u'language', u'en')
-        self.song.appendChild(self.lyrics)
+
+        ``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):
         """
@@ -92,25 +79,20 @@
             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.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)
-        verse.appendChild(cds)
+        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 self.song_xml.toprettyxml(indent=u'  ')
+        return etree.tostring(self.song_xml, pretty_print=True)
 
     def extract_xml(self):
         """
         Extract our newly created XML song.
         """
-        return self.song_xml.toxml(u'utf-8')
+        return etree.tostring(self.song_xml, encoding=u'utf-8')
 
 
 class SongXMLParser(object):
@@ -128,9 +110,8 @@
         """
         self.song_xml = None
         try:
-            self.song_xml = ElementTree(
-                element=XML(unicode(xml).encode('unicode-escape')))
-        except ExpatError:
+            self.song_xml = objectify.fromstring(str(xml))
+        except etree.XMLSyntaxError:
             log.exception(u'Invalid xml %s', xml)
 
     def get_verses(self):

=== modified file 'openlp/plugins/songs/lib/xml.py'
--- openlp/plugins/songs/lib/xml.py	2010-05-29 19:50:50 +0000
+++ openlp/plugins/songs/lib/xml.py	2010-07-03 18:02:24 +0000
@@ -136,4 +136,3 @@
         song_output = u'<?xml version="1.0" encoding="UTF-8"?>' + \
             u'<song version="1.0">%s</song>' % lyrics_output
         return song_output
-


Follow ups