Version 1.2.1.
authorMarek Stępniowski <marek@stepniowski.com>
Fri, 19 Mar 2010 16:00:19 +0000 (17:00 +0100)
committerŁukasz Rekucki <lrekucki@gmail.com>
Fri, 19 Mar 2010 16:17:06 +0000 (17:17 +0100)
53 files changed:
.gitignore
MANIFEST.in
README.txt [new file with mode: 0644]
librarian/__init__.py
librarian/__init__.pyc [deleted file]
librarian/book2txt.xslt
librarian/dcparser.py
librarian/dcparser.pyc [deleted file]
librarian/html.py
librarian/html.pyc [deleted file]
librarian/parser.py [new file with mode: 0644]
librarian/tests/__init__.py [deleted file]
librarian/tests/files/dcparser/.DS_Store [deleted file]
librarian/tests/files/dcparser/andersen_brzydkie_kaczatko.xml [deleted file]
librarian/tests/files/dcparser/biedrzycki_akslop.xml [deleted file]
librarian/tests/files/dcparser/kochanowski_piesn7.xml [deleted file]
librarian/tests/files/dcparser/mickiewicz_rybka.xml [deleted file]
librarian/tests/files/dcparser/sofokles_antygona.xml [deleted file]
librarian/tests/files/erroneous/asnyk_miedzy_nami.html [deleted file]
librarian/tests/files/erroneous/asnyk_miedzy_nami.xml [deleted file]
librarian/text.py
librarian/text.pyc [deleted file]
scripts/book2html
scripts/book2txt
setup.py [changed mode: 0644->0755]
tests/__init__.py [new file with mode: 0644]
tests/files/dcparser/andersen_brzydkie_kaczatko.out [new file with mode: 0644]
tests/files/dcparser/andersen_brzydkie_kaczatko.xml [new file with mode: 0644]
tests/files/dcparser/biedrzycki_akslop.out [new file with mode: 0644]
tests/files/dcparser/biedrzycki_akslop.xml [new file with mode: 0644]
tests/files/dcparser/kochanowski_piesn7.out [new file with mode: 0644]
tests/files/dcparser/kochanowski_piesn7.xml [new file with mode: 0644]
tests/files/dcparser/mickiewicz_rybka.out [new file with mode: 0644]
tests/files/dcparser/mickiewicz_rybka.xml [new file with mode: 0644]
tests/files/dcparser/sofokles_antygona.out [new file with mode: 0644]
tests/files/dcparser/sofokles_antygona.xml [new file with mode: 0644]
tests/files/dcserialize/andersen_brzydkie_kaczatko.out [new file with mode: 0644]
tests/files/dcserialize/andersen_brzydkie_kaczatko.xml [new file with mode: 0644]
tests/files/dcserialize/biedrzycki_akslop.out [new file with mode: 0644]
tests/files/dcserialize/biedrzycki_akslop.xml [new file with mode: 0644]
tests/files/dcserialize/kochanowski_piesn7.out [new file with mode: 0644]
tests/files/dcserialize/kochanowski_piesn7.xml [new file with mode: 0644]
tests/files/dcserialize/mickiewicz_rybka.out [new file with mode: 0644]
tests/files/dcserialize/mickiewicz_rybka.xml [new file with mode: 0644]
tests/files/dcserialize/sofokles_antygona.out [new file with mode: 0644]
tests/files/dcserialize/sofokles_antygona.xml [new file with mode: 0644]
tests/files/erroneous/asnyk_miedzy_nami.html [new file with mode: 0644]
tests/files/erroneous/asnyk_miedzy_nami.xml [new file with mode: 0644]
tests/files/text/asnyk_miedzy_nami.txt [new file with mode: 0644]
tests/files/text/asnyk_miedzy_nami.xml [new file with mode: 0644]
tests/test_dcparser.py [new file with mode: 0755]
tests/test_text.py [new file with mode: 0755]
tests/utils.py [new file with mode: 0644]

index 7189e7b..bfdc1af 100644 (file)
@@ -2,3 +2,6 @@
 *.pyc
 MANIFEST
 dist
+build
+nbproject
+nbproject/*
index 4c76fc3..9b7ec3d 100644 (file)
@@ -1,2 +1,2 @@
 include librarian/*.xslt
-recursive-include librarian/tests/files/ *.xml
+recursive-include tests/files/ *.xml
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..3debf76
--- /dev/null
@@ -0,0 +1,49 @@
+Librarian
+=========
+Librarian (*ang. bibliotekarz*) to biblioteka służąca do konwersji języka składu książek opartego na XML opracowanego przez Fundację Nowoczesna Polska na inne formaty.
+
+Obecnie obsługiwane są formaty:
+
+ * XML
+ * TXT
+Biblioteka librarian potrafi również parsować metadane opisane przez DublinCore oraz wyciągać fragmenty motywów z lektur.
+
+
+Wymagania
+---------
+
+ * [lxml 2.2](http://codespeak.net/lxml/)
+
+Instalacja
+----------
+Zainstaluj biblioteki z sekcji *Wymagania* powyżej. Następnie rozpakuj archiwum z biblioteką librarian, przejdź w terminalu do rozpakowanego katalogu i wpisz:
+
+<pre>python setup.py install</pre>
+
+Na Linuxie i OSX mogą być wymagane uprawnienia administratora. W takim wypadku wpisz:
+
+<pre>sudo python setup.py install</pre>
+
+Alternatywnie możesz zainstalować bibliotekę librarian w wybranym przez siebie katalogu. W takim wypadku należy użyć argumentu *prefix* do *setup.py*:
+
+<pre>python setup.py install --prefix=ŚCIEŻKA_DO_WYBRANEGO_KATALOGU</pre> 
+
+W takim wypadku będzie jednak potrzebne własnoręczne edytowanie zmiennych systemowych *PATH* i *PYTHONPATH*.
+
+
+Sposób użycia
+-------------
+Konwersja plików lektur do XHTML:
+
+<pre>book2html LEKTURA1 LEKTURA2...</pre>
+
+Konwersja plików lektur do TXT:
+
+<pre>book2txt LEKTURA1 LEKTURA2...</pre>
+
+Wyciągnięcie wszystkich fragmentów motywów z wygenerowanych plików XHTML:
+
+<pre>bookfragments PLIK1 PLIK2...</pre>
+
index e69de29..9132f5c 100644 (file)
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# exception classes
+
+class ParseError(Exception):
+    pass
+
+class ValidationError(Exception):
+    pass
+
+class NoDublinCore(ValidationError):
+    pass
diff --git a/librarian/__init__.pyc b/librarian/__init__.pyc
deleted file mode 100644 (file)
index 3d4eb13..0000000
Binary files a/librarian/__init__.pyc and /dev/null differ
index cd98524..72f193d 100644 (file)
@@ -3,22 +3,13 @@
 
 <xsl:output encoding="utf-8" method="text" />
 
+<xsl:param name="wrapping" select="0" />
+
 <!-- ============================================================================== -->
 <!-- = MASTER TAG                                                                 = -->
 <!-- = (can contain block tags, paragraph tags, standalone tags and special tags) = -->
 <!-- ============================================================================== -->
 <xsl:template match="powiesc|opowiadanie|liryka_l|liryka_lp|dramat_wierszowany_l|dramat_wierszowany_lp|dramat_wspolczesny">
-<xsl:text>Kodowanie znaków w dokumencie: UTF-8.
------
-Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl/). Reprodukcja cyfrowa wykonana przez
-Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN. Ten utwór nie jest chroniony prawem autorskim i znajduje
-się w domenie publicznej, co oznacza, że możesz go swobodnie wykorzystywać, publikować i rozpowszechniać.
-
-Wersja lektury w opracowaniu merytorycznym i krytycznym (przypisy i motywy) dostępna jest na stronie %s.
------
-
-
-</xsl:text>
 <xsl:if test="nazwa_utworu"><xsl:apply-templates select="autor_utworu|dzielo_nadrzedne|nazwa_utworu|podtytul" mode="header" /></xsl:if>
 <xsl:text>
 
@@ -150,8 +141,8 @@ Wersja lektury w opracowaniu merytorycznym i krytycznym (przypisy i motywy) dost
     <xsl:apply-templates select="*|text()" mode="inline" />
 </xsl:variable>
 <xsl:text>
-
-/ </xsl:text><xsl:value-of select="wl:wrap_words(wl:strip($content))" /><xsl:text> /</xsl:text>
+    
+/ </xsl:text><xsl:value-of select="wl:wrap_words(wl:strip($content), $wrapping)" /><xsl:text> /</xsl:text>
 </xsl:template>
 
 <xsl:template match="lista_osoba">
@@ -167,7 +158,7 @@ Wersja lektury w opracowaniu merytorycznym i krytycznym (przypisy i motywy) dost
 <xsl:text>
 
 </xsl:text>
-<xsl:value-of select="wl:wrap_words(wl:strip($content))" />
+<xsl:value-of select="wl:wrap_words(wl:strip($content), $wrapping)" />
 </xsl:template>
 
 <xsl:template match="strofa">
index 557509c..830b089 100644 (file)
@@ -3,14 +3,10 @@ from xml.parsers.expat import ExpatError
 from datetime import date
 import time
 
-# Import ElementTree from anywhere
-try:
-    import xml.etree.ElementTree as etree # Python >= 2.5
-except ImportError:
-    try:
-        import elementtree.ElementTree as etree # effbot's pure Python module
-    except ImportError:
-        import lxml.etree as etree # ElementTree API using libxml2
+from librarian import ValidationError, NoDublinCore
+
+import lxml.etree as etree # ElementTree API using libxml2
+from lxml.etree import XMLSyntaxError
 
 
 # ==============
@@ -21,7 +17,22 @@ class Person(object):
     def __init__(self, last_name, *first_names):
         self.last_name = last_name
         self.first_names = first_names
-    
+        
+    @classmethod
+    def from_text(cls, text):
+        parts = [ token.strip() for token in text.split(',') ]
+        if len(parts) == 1:
+            surname = parts[0]
+            names = []
+        elif len(parts) != 2:
+            raise ValueError("Invalid person name. There should be at most one comma: \"%s\"." % text)
+        else:
+            surname = parts[0]
+            if len(parts[1]) == 0:
+                # there is no non-whitespace data after the comma
+                raise ValueError("Found a comma, but no names given: \"%s\" -> %r." % (text, parts))
+            names = [ name for name in parts[1].split() if len(name) ] # all non-whitespace tokens
+        return cls(surname, *names)
     
     def __eq__(self, right):
         return self.last_name == right.last_name and self.first_names == right.first_names
@@ -32,52 +43,71 @@ class Person(object):
             return '%s, %s' % (self.last_name, ' '.join(self.first_names))
         else:
             return self.last_name
-    
-    
+        
     def __repr__(self):
         return 'Person(last_name=%r, first_names=*%r)' % (self.last_name, self.first_names)
 
+def as_date(text):
+    try:
+        try:
+            t = time.strptime(text, '%Y-%m-%d')
+        except ValueError:
+            t = time.strptime(text, '%Y')
+        return date(t[0], t[1], t[2])
+    except ValueError, e:
+        raise ValueError("Unrecognized date format. Try YYYY-MM-DD or YYYY.")
 
-def str_to_unicode(value, previous):
-    return unicode(value)
-
+def as_person(text):
+    return Person.from_text(text)
 
-def str_to_unicode_list(value, previous):
-    if previous is None:
-        previous = []
-    previous.append(str_to_unicode(value, None))
-    return previous
+def as_unicode(text):
+    if isinstance(text, unicode):
+        return text
+    else:
+        return text.decode('utf-8')
 
+class Field(object):
+    def __init__(self, uri, attr_name, type=as_unicode, multiple=False, salias=None, **kwargs):
+        self.uri = uri
+        self.name = attr_name
+        self.validator = type
+        self.multiple = multiple
+        self.salias = salias
 
-def str_to_person(value, previous):
-    comma_count = value.count(',')
-    
-    if comma_count == 0:
-        last_name, first_names = value, []
-    elif comma_count == 1:
-        last_name, first_names = value.split(',')
-        first_names = [name for name in first_names.split(' ') if len(name)]
-    else:
-        raise ValueError("value contains more than one comma: %r" % value)
-    
-    return Person(last_name.strip(), *first_names)
+        self.required = kwargs.get('required', True) and not kwargs.has_key('default')
+        self.default = kwargs.get('default', [] if multiple else [None])
 
+    def validate_value(self, val):
+        try:
+            if self.multiple:
+                if self.validator is None:
+                    return val
+                return [ self.validator(v) if v is not None else v for v in val ]
+            elif len(val) > 1:
+                raise ValidationError("Mulitply values not allowed for field '%s'" % self.uri)
+            elif len(val) == 0:
+                raise ValidationError("Field %s has no value to assign. Check your defaults." % self.uri)
+            else:
+                if self.validator is None or val[0] is None:
+                    return val[0]
+                return self.validator(val[0])
+        except ValueError, e:
+            raise ValidationError("Field '%s' - invald value: %s" % (self.uri, e.message))
 
-def str_to_date(value, previous):
-    try:
-        t = time.strptime(value, '%Y-%m-%d')
-    except ValueError:
-        t = time.strptime(value, '%Y')
-    return date(t[0], t[1], t[2])
+    def validate(self, fdict):
+        if not fdict.has_key(self.uri):
+            if not self.required:
+                f = self.default
+            else:
+                raise ValidationError("Required field %s not found" % self.uri)
+        else:
+            f = fdict[self.uri]
 
+        return self.validate_value(f)
 
 # ==========
 # = Parser =
 # ==========
-class ParseError(Exception):
-    def __init__(self, message):
-        super(ParseError, self).__init__(message)
-
 
 class XMLNamespace(object):
     '''Represents XML namespace.'''
@@ -102,96 +132,175 @@ class BookInfo(object):
     RDF = XMLNamespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
     DC = XMLNamespace('http://purl.org/dc/elements/1.1/')
     
-    mapping = {
-        DC('creator')        : ('author', str_to_person),
-        DC('title')          : ('title', str_to_unicode),
-        DC('subject.period') : ('epoch', str_to_unicode),
-        DC('subject.type')   : ('kind', str_to_unicode),
-        DC('subject.genre')  : ('genre', str_to_unicode),
-        DC('date')           : ('created_at', str_to_date),
-        DC('date.pd')        : ('released_to_public_domain_at', str_to_date),
-        DC('contributor.translator') : ('translator', str_to_person),
-        DC('contributor.technical_editor') : ('technical_editor', str_to_person),
-        DC('publisher')      : ('publisher', str_to_unicode),
-        DC('source')         : ('source_name', str_to_unicode),
-        DC('source.URL')     : ('source_url', str_to_unicode),
-        DC('identifier.url') : ('url', str_to_unicode),
-        DC('relation.hasPart') : ('parts', str_to_unicode_list),
-        DC('rights.license') : ('license', str_to_unicode),
-        DC('rights')         : ('license_description', str_to_unicode), 
-    }
+    FIELDS = (
+        Field( DC('creator'), 'author', as_person),
+        Field( DC('title'), 'title'),
+        Field( DC('subject.period'), 'epoches', salias='epoch', multiple=True),
+        Field( DC('subject.type'), 'kinds', salias='kind', multiple=True),
+        Field( DC('subject.genre'), 'genres', salias='genre', multiple=True),
+        Field( DC('date'), 'created_at', as_date),
+        Field( DC('date.pd'), 'released_to_public_domain_at', as_date, required=False),
+        Field( DC('contributor.editor'), 'editors', \
+            as_person, salias='editor', multiple=True, default=[]),
+        Field( DC('contributor.translator'), 'translators', \
+            as_person,  salias='translator', multiple=True, default=[]),
+        Field( DC('contributor.technical_editor'), 'technical_editors',
+            as_person, salias='technical_editor', multiple=True, default=[]),
+        Field( DC('publisher'), 'publisher'),
+        Field( DC('source'), 'source_name', required=False),
+        Field( DC('source.URL'), 'source_url', required=False),
+        Field( DC('identifier.url'), 'url'),
+        Field( DC('relation.hasPart'), 'parts', multiple=True, required=False),
+        Field( DC('rights.license'), 'license', required=False),
+        Field( DC('rights'), 'license_description'), 
+    )
 
     @classmethod
     def from_string(cls, xml):
         from StringIO import StringIO
         return cls.from_file(StringIO(xml))
-    
+   
     @classmethod
-    def from_file(cls, xml_file):
-        book_info = cls()
-        
+    def from_file(cls, xmlfile):
+        desc_tag = None        
         try:
-            tree = etree.parse(xml_file)
+            iter = etree.iterparse(xmlfile, ['start', 'end'])            
+            for (event, element) in iter:
+                if element.tag == cls.RDF('RDF') and event == 'start':
+                    desc_tag = element
+                    break
+
+            if desc_tag is None:
+                raise NoDublinCore("DublinCore section not found. \
+                    Check if there are rdf:RDF and rdf:Description tags.")
+
+            # continue 'till the end of RDF section
+            for (event, element) in iter:
+                if element.tag == cls.RDF('RDF') and event == 'end':
+                    break
+
+            # if there is no end, Expat should yell at us with an ExpatError
+            
+            # extract data from the element and make the info
+            return cls.from_element(desc_tag)
+        except XMLSyntaxError, e:
+            raise ParseError(e)
         except ExpatError, e:
             raise ParseError(e)
 
-        description = tree.find('//' + book_info.RDF('Description'))
-        book_info.wiki_url = description.get(cls.RDF('about'), None)
-        
-        if description is None:
-            raise ParseError('no Description tag found in document')
-        
-        for element in description.findall('*'):
-            book_info.parse_element(element) 
+    @classmethod
+    def from_element(cls, rdf_tag):
+        # the tree is already parsed, so we don't need to worry about Expat errors
+        field_dict = {}
+        desc = rdf_tag.find(".//" + cls.RDF('Description') )        
         
-        return book_info
+        if desc is None:
+            raise NoDublinCore("No DublinCore section found.")
+
+        for e in desc.getchildren():
+            fv = field_dict.get(e.tag, [])
+            fv.append(e.text)
+            field_dict[e.tag] = fv
+                
+        return cls( desc.attrib, field_dict )        
+
+    def __init__(self, rdf_attrs, dc_fields):
+        """rdf_attrs should be a dictionary-like object with any attributes of the RDF:Description.
+        dc_fields - dictionary mapping DC fields (with namespace) to list of text values for the 
+        given field. """
+
+        self.about = rdf_attrs.get(self.RDF('about'))
+        self.fmap = {}
+
+        for field in self.FIELDS:
+            value = field.validate( dc_fields )
+            setattr(self, 'prop_' + field.name, value)
+            self.fmap[field.name] = field
+            if field.salias: self.fmap[field.salias] = field
+
+    def __getattribute__(self, name):
+        try:
+            field = object.__getattribute__(self, 'fmap')[name]
+            value = object.__getattribute__(self, 'prop_'+field.name)
+            if field.name == name:
+                return value
+            else: # singular alias
+                if not field.multiple:
+                    raise "OUCH!! for field %s" % name
+                
+                return value[0]
+        except (KeyError, AttributeError):
+            return object.__getattribute__(self, name)
 
-    def parse_element(self, element):
+    def __setattr__(self, name, newvalue):
         try:
-            attribute, converter = self.mapping[element.tag]
-            setattr(self, attribute, converter(element.text, getattr(self, attribute, None)))
-        except KeyError:
-            pass
+            field = object.__getattribute__(self, 'fmap')[name]
+            if field.name == name:
+                object.__setattr__(self, 'prop_'+field.name, newvalue)
+            else: # singular alias
+                if not field.multiple:
+                    raise "OUCH! while setting field %s" % name
 
-    def to_xml(self):
+                object.__setattr__(self, 'prop_'+field.name, [newvalue])
+        except (KeyError, AttributeError):
+            return object.__setattr__(self, name, newvalue)
+
+    def update(self, field_dict):
+        """Update using field_dict. Verify correctness, but don't check if all 
+        required fields are present."""
+        for field in self.FIELDS:
+            if field_dict.has_key(field.name):
+                setattr(self, field.name, field_dict[field.name])
+
+    def to_etree(self, parent = None):
         """XML representation of this object."""
-        etree._namespace_map[str(self.RDF)] = 'rdf'
-        etree._namespace_map[str(self.DC)] = 'dc'
+        #etree._namespace_map[str(self.RDF)] = 'rdf'
+        #etree._namespace_map[str(self.DC)] = 'dc'
         
-        root = etree.Element(self.RDF('RDF'))
+        if parent is None:
+            root = etree.Element(self.RDF('RDF'))
+        else:
+            root = parent.makeelement(self.RDF('RDF'))
+
         description = etree.SubElement(root, self.RDF('Description'))
         
-        if self.wiki_url:
-            description.set(self.RDF('about'), self.wiki_url)
+        if self.about:
+            description.set(self.RDF('about'), self.about)
         
-        for tag, (attribute, converter) in self.mapping.iteritems():
-            if hasattr(self, attribute):
-                e = etree.Element(tag)
-                e.text = unicode(getattr(self, attribute))
-                description.append(e)
+        for field in self.FIELDS:
+            v = getattr(self, field.name, None)
+            if v is not None:
+                if field.multiple:
+                    if len(v) == 0: continue
+                    for x in v:
+                        e = etree.Element(field.uri)
+                        e.text = unicode(x)
+                        description.append(e)
+                else:
+                    e = etree.Element(field.uri)
+                    e.text = unicode(v)
+                    description.append(e)
         
-        return unicode(etree.tostring(root, 'utf-8'), 'utf-8')
+        return root
 
     def to_dict(self):
-        etree._namespace_map[str(self.RDF)] = 'rdf'
-        etree._namespace_map[str(self.DC)] = 'dc'
-        
-        result = {'about': self.wiki_url}
-        for tag, (attribute, converter) in self.mapping.iteritems():
-            if hasattr(self, attribute):
-                result[attribute] = unicode(getattr(self, attribute))
+        result = {'about': self.about}
+        for field in self.FIELDS:
+            v = getattr(self, field.name, None)
+
+            if v is not None:
+                if field.multiple:
+                    if len(v) == 0: continue
+                    v = [ unicode(x) for x in v ]
+                else:
+                    v = unicode(v)
+                result[field.name] = v
+
+            if field.salias:
+                v = getattr(self, field.salias)
+                if v is not None: result[field.salias] = v
         
         return result
 
-
 def parse(file_name):
     return BookInfo.from_file(file_name)
-
-
-if __name__ == '__main__':
-    import sys
-    
-    info = parse(sys.argv[1])
-    for attribute, _ in BookInfo.mapping.values():
-        print '%s: %r' % (attribute, getattr(info, attribute, None))
-
diff --git a/librarian/dcparser.pyc b/librarian/dcparser.pyc
deleted file mode 100644 (file)
index 0e911b8..0000000
Binary files a/librarian/dcparser.pyc and /dev/null differ
index b279e5d..4edbf33 100644 (file)
@@ -3,9 +3,9 @@ import os
 import cStringIO
 import re
 import copy
-import pkgutil
 
 from lxml import etree
+from librarian.parser import WLDocument
 
 
 ENTITY_SUBSTITUTIONS = [
@@ -31,32 +31,28 @@ ns = etree.FunctionNamespace('http://wolnelektury.pl/functions')
 ns['substitute_entities'] = substitute_entities
 
 
-def transform(input_filename, output_filename):
+def transform(input, output_filename=None, is_file=True):
     """Transforms file input_filename in XML to output_filename in XHTML."""
     # Parse XSLT
     style_filename = os.path.join(os.path.dirname(__file__), 'book2html.xslt')
     style = etree.parse(style_filename)
 
-    doc_file = cStringIO.StringIO()
-    expr = re.compile(r'/\s', re.MULTILINE | re.UNICODE);
-
-    f = open(input_filename, 'r')
-    for line in f:
-        line = line.decode('utf-8')
-        line = expr.sub(u'<br/>\n', line)
-        doc_file.write(line.encode('utf-8'))
-    f.close()
-
-    doc_file.seek(0);
+    if is_file:
+        document = WLDocument.from_file(input, True)
+    else:
+        document = WLDocument.from_string(input, True)
 
-    parser = etree.XMLParser(remove_blank_text=True)
-    doc = etree.parse(doc_file, parser)
+    result = document.transform(style)
+    del document # no longer needed large object :)
 
-    result = doc.xslt(style)
     if result.find('//p') is not None:
         add_anchors(result.getroot())
         add_table_of_contents(result.getroot())
-        result.write(output_filename, xml_declaration=False, pretty_print=True, encoding='utf-8')
+        
+        if output_filename is not None:
+            result.write(output_filename, xml_declaration=False, pretty_print=True, encoding='utf-8')
+        else:
+            return result
         return True
     else:
         return False
diff --git a/librarian/html.pyc b/librarian/html.pyc
deleted file mode 100644 (file)
index dfb837d..0000000
Binary files a/librarian/html.pyc and /dev/null differ
diff --git a/librarian/parser.py b/librarian/parser.py
new file mode 100644 (file)
index 0000000..595dd97
--- /dev/null
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+from librarian import ValidationError, NoDublinCore, dcparser, ParseError
+from xml.parsers.expat import ExpatError
+from lxml import etree
+from lxml.etree import XMLSyntaxError
+
+import re
+from StringIO import StringIO
+
+class WLDocument(object):
+    LINE_SWAP_EXPR = re.compile(r'/\s', re.MULTILINE | re.UNICODE);
+
+    def __init__(self, edoc):
+        self.edoc = edoc
+
+        root_elem = edoc.getroot()
+        rdf_ns = dcparser.BookInfo.RDF
+        dc_path = './/' + rdf_ns('RDF')
+        
+        if root_elem.tag != 'utwor':
+            raise ValidationError("Invalid root element. Found '%s', should be 'utwor'" % root_elem.tag)
+
+        self.rdf_elem = root_elem.find(dc_path)
+
+        if self.rdf_elem is None:
+            raise NoDublinCore('Document has no DublinCore - which is required.')
+
+        self.book_info = dcparser.BookInfo.from_element(self.rdf_elem)
+
+    @classmethod
+    def from_string(cls, xml, swap_endlines=False):
+        return cls.from_file(StringIO(xml), swap_endlines)
+
+    @classmethod
+    def from_file(cls, xmlfile, swap_endlines=False):
+
+        # first, prepare for parsing
+        if isinstance(xmlfile, basestring):
+            file = open(xmlfile, 'rb')
+            try:
+                data = file.read()
+            finally:
+                file.close()
+        else:
+            data = xmlfile.read()
+
+        if not isinstance(data, unicode):
+            data = data.decode('utf-8')
+
+        if swap_endlines:
+            data = cls.LINE_SWAP_EXPR.sub(u'<br />\n', data)
+    
+        try:
+            parser = etree.XMLParser(remove_blank_text=True)
+            return cls( etree.parse(StringIO(data), parser) )
+        except XMLSyntaxError, e:
+             raise ParseError(e.message)            
+        except ExpatError, e:
+            raise ParseError(e.message)            
+
+    def transform(self, stylesheet, **options):
+        return self.edoc.xslt(stylesheet, **options)
+
+    def update_dc(self):
+        parent = self.rdf_elem.getparent()
+        parent.replace( self.rdf_elem, self.book_info.to_etree(parent) )
+
+    def serialize(self):
+        self.update_dc()
+        return etree.tostring(self.edoc, encoding=unicode, pretty_print=True)
diff --git a/librarian/tests/__init__.py b/librarian/tests/__init__.py
deleted file mode 100644 (file)
index 3f02541..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-# -*- coding: utf-8 -*-
-import unittest
-from os.path import dirname, join, realpath
-
-from lxml import etree
-from librarian import dcparser, html
-
-
-def test_file_path(dir_name, file_name):
-    return realpath(join(dirname(__file__), 'files', dir_name, file_name))
-
-
-class TestDCParser(unittest.TestCase):
-    KNOWN_RESULTS = (
-        ('dcparser', 'andersen_brzydkie_kaczatko.xml', {
-            'publisher': u'Fundacja Nowoczesna Polska',
-            'about': u'http://wiki.wolnepodreczniki.pl/Lektury:Andersen/Brzydkie_kaczątko',
-            'source_name': u'Andersen, Hans Christian (1805-1875), Baśnie, Gebethner i Wolff, wyd. 7, Kraków, 1925',
-            'author': u'Andersen, Hans Christian',
-            'url': u'http://wolnelektury.pl/katalog/lektura/brzydkie-kaczatko',
-            'created_at': u'2007-08-14',
-            'title': u'Brzydkie kaczątko',
-            'kind': u'Epika',
-            'source_url': u'http://www.polona.pl/dlibra/doccontent2?id=3563&dirids=4',
-            'translator': u'Niewiadomska, Cecylia',
-            'released_to_public_domain_at': u'1925-01-01',
-            'epoch': u'Romantyzm',
-            'genre': u'Baśń',
-            'technical_editor': u'Gałecki, Dariusz',
-            'license_description': u'Domena publiczna - tłumacz Cecylia Niewiadomska zm. 1925',
-        }),
-        ('dcparser', 'kochanowski_piesn7.xml', {
-            'publisher': u'Fundacja Nowoczesna Polska',
-            'about': u'http://wiki.wolnepodreczniki.pl/Lektury:Kochanowski/Pieśni/Pieśń_VII_(1)',
-            'source_name': u'Kochanowski, Jan (1530-1584), Dzieła polskie, tom 1, oprac. Julian Krzyżanowski, wyd. 8, Państwowy Instytut Wydawniczy, Warszawa, 1976',
-            'author': u'Kochanowski, Jan',
-            'url': u'http://wolnelektury.pl/katalog/lektura/piesni-ksiegi-pierwsze-piesn-vii-trudna-rada-w-tej-mierze-pr',
-            'created_at': u'2007-08-31',
-            'title': u'Pieśń VII (Trudna rada w tej mierze: przyjdzie się rozjechać...)',
-            'kind': u'Liryka',
-            'source_url': u'http://www.polona.pl/Content/1499',
-            'released_to_public_domain_at': u'1584-01-01',
-            'epoch': u'Renesans',
-            'genre': u'Pieśń',
-            'technical_editor': u'Gałecki, Dariusz',
-            'license_description': u'Domena publiczna - Jan Kochanowski zm. 1584 ',
-        }),
-        ('dcparser', 'mickiewicz_rybka.xml', {
-            'publisher': u'Fundacja Nowoczesna Polska',
-            'about': 'http://wiki.wolnepodreczniki.pl/Lektury:Mickiewicz/Ballady/Rybka',
-            'source_name': u'Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922',
-            'author': u'Mickiewicz, Adam',
-            'url': u'http://wolnelektury.pl/katalog/lektura/ballady-i-romanse-rybka',
-            'created_at': u'2007-09-06',
-            'title': u'Rybka',
-            'kind': u'Liryka',
-            'source_url': u'http://www.polona.pl/Content/2222',
-            'released_to_public_domain_at': u'1855-01-01',
-            'epoch': u'Romantyzm',
-            'genre': u'Ballada',
-            'technical_editor': u'Sutkowska, Olga',
-            'license_description': u'Domena publiczna - Adam Mickiewicz zm. 1855',
-        }),
-        ('dcparser', 'sofokles_antygona.xml', {
-            'publisher': u'Fundacja Nowoczesna Polska',
-            'about': 'http://wiki.wolnepodreczniki.pl/Lektury:Sofokles/Antygona',
-            'source_name': u'Sofokles (496-406 a.C.), Antygona, Zakład Narodowy im. Ossolińskich, wyd. 7, Lwów, 1939',
-            'author': u'Sofokles',
-            'url': u'http://wolnelektury.pl/katalog/lektura/antygona',
-            'created_at': u'2007-08-30',
-            'title': u'Antygona',
-            'kind': u'Dramat',
-            'source_url': u'http://www.polona.pl/Content/3768',
-            'translator': u'Morawski, Kazimierz',
-            'released_to_public_domain_at': u'1925-01-01',
-            'epoch': u'Starożytność',
-            'genre': u'Tragedia',
-            'technical_editor': u'Gałecki, Dariusz',
-            'license_description': u'Domena publiczna - tłumacz Kazimierz Morawski zm. 1925',
-        }),
-        ('dcparser', 'biedrzycki_akslop.xml', {
-            'publisher': u'Fundacja Nowoczesna Polska',
-            'about': 'http://wiki.wolnepodreczniki.pl/Lektury:Biedrzycki/Akslop',
-            'source_name': u'Miłosz Biedrzycki, * ("Gwiazdka"), Fundacja "brulion", Kraków-Warszawa, 1993',
-            'author': u'Biedrzycki, Miłosz',
-            'url': u'http://wolnelektury.pl/katalog/lektura/akslop',
-            'created_at': u'2009-06-04',
-            'title': u'Akslop',
-            'kind': u'Liryka',
-            'source_url': u'http://free.art.pl/mlb/gwiazdka.html#t1',
-            'epoch': u'Współczesność',
-            'genre': u'Wiersz',
-            'technical_editor': u'Sutkowska, Olga',
-            'license': u'http://creativecommons.org/licenses/by-sa/3.0/',
-            'license_description': u'Creative Commons Uznanie Autorstwa - Na Tych Samych Warunkach 3.0.PL'
-        }),
-    )
-    
-    def test_parse(self):
-        for dir_name, file_name, result in self.KNOWN_RESULTS:
-            self.assertEqual(dcparser.parse(test_file_path(dir_name, file_name)).to_dict(), result)
-
-
-class TestParserErrors(unittest.TestCase):
-    def test_error(self):
-        try:
-            html.transform(test_file_path('erroneous', 'asnyk_miedzy_nami.xml'),
-                           test_file_path('erroneous', 'asnyk_miedzy_nami.html'))
-            self.fail()
-        except etree.XMLSyntaxError, e:
-            self.assertEqual(e.position, (25, 13))
-
-
-if __name__ == '__main__':
-    unittest.main()
\ No newline at end of file
diff --git a/librarian/tests/files/dcparser/.DS_Store b/librarian/tests/files/dcparser/.DS_Store
deleted file mode 100644 (file)
index 8817fe6..0000000
Binary files a/librarian/tests/files/dcparser/.DS_Store and /dev/null differ
diff --git a/librarian/tests/files/dcparser/andersen_brzydkie_kaczatko.xml b/librarian/tests/files/dcparser/andersen_brzydkie_kaczatko.xml
deleted file mode 100644 (file)
index d653a9b..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
-    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Andersen/Brzydkie_kaczątko">
-        <dc:creator xml:lang="pl">Andersen, Hans Christian</dc:creator>
-        <dc:title xml:lang="pl">Brzydkie kaczątko</dc:title>
-        <dc:contributor.translator xml:lang="pl">Niewiadomska, Cecylia</dc:contributor.translator>
-        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
-        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
-        <dc:subject.period xml:lang="pl">Romantyzm</dc:subject.period>
-        <dc:subject.type xml:lang="pl">Epika</dc:subject.type>
-        <dc:subject.genre xml:lang="pl">Baśń</dc:subject.genre>
-        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
-        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/brzydkie-kaczatko</dc:identifier.url>
-        <dc:source.URL xml:lang="pl">http://www.polona.pl/dlibra/doccontent2?id=3563&amp;dirids=4</dc:source.URL>
-        <dc:source xml:lang="pl">Andersen, Hans Christian (1805-1875), Baśnie, Gebethner i Wolff, wyd. 7, Kraków, 1925</dc:source>
-        <dc:rights xml:lang="pl">Domena publiczna - tłumacz Cecylia Niewiadomska zm. 1925</dc:rights>
-        <dc:date.pd xml:lang="pl">1925</dc:date.pd>
-        <dc:format xml:lang="pl">xml</dc:format>
-        <dc:type xml:lang="pl">text</dc:type>
-        <dc:type xml:lang="en">text</dc:type>
-        <dc:date xml:lang="pl">2007-08-14</dc:date>
-        <dc:audience xml:lang="pl">SP1</dc:audience>
-        <dc:language xml:lang="pl">pol</dc:language>
-    </rdf:Description>
-</rdf:RDF>
\ No newline at end of file
diff --git a/librarian/tests/files/dcparser/biedrzycki_akslop.xml b/librarian/tests/files/dcparser/biedrzycki_akslop.xml
deleted file mode 100644 (file)
index da0cd9f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-xmlns:dc="http://purl.org/dc/elements/1.1/">
-    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Biedrzycki/Akslop">
-        <dc:creator xml:lang="pl">Biedrzycki, Miłosz</dc:creator>
-        <dc:title xml:lang="pl">Akslop</dc:title>
-        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
-        <dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
-        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
-        <dc:subject.period xml:lang="pl">Współczesność</dc:subject.period>
-        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
-        <dc:subject.genre xml:lang="pl">Wiersz</dc:subject.genre>
-        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl).</dc:description>
-        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/akslop</dc:identifier.url>
-        <dc:source.URL xml:lang="pl">http://free.art.pl/mlb/gwiazdka.html#t1</dc:source.URL>
-        <dc:source xml:lang="pl">Miłosz Biedrzycki, * ("Gwiazdka"), Fundacja "brulion", Kraków-Warszawa, 1993</dc:source>
-        <dc:rights xml:lang="pl">Creative Commons Uznanie Autorstwa - Na Tych Samych Warunkach 3.0.PL</dc:rights>
-        <dc:rights.license>http://creativecommons.org/licenses/by-sa/3.0/</dc:rights.license>
-        <dc:format xml:lang="pl">xml</dc:format>
-        <dc:type xml:lang="pl">text</dc:type>
-        <dc:type xml:lang="en">text</dc:type>
-        <dc:date xml:lang="pl">2009-06-04</dc:date>
-        <dc:audience xml:lang="pl">L</dc:audience>
-        <dc:language xml:lang="pl">pol</dc:language>
-    </rdf:Description>
-</rdf:RDF>
\ No newline at end of file
diff --git a/librarian/tests/files/dcparser/kochanowski_piesn7.xml b/librarian/tests/files/dcparser/kochanowski_piesn7.xml
deleted file mode 100644 (file)
index 96be1ae..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
-    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Kochanowski/Pieśni/Pieśń_VII_(1)">
-        <dc:creator xml:lang="pl">Kochanowski, Jan</dc:creator>
-        <dc:title xml:lang="pl">Pieśń VII (Trudna rada w tej mierze: przyjdzie się rozjechać...)</dc:title>
-        <dc:relation.isPartOf xml:lang="pl">http://www.wolnelektury.pl/lektura/piesni-ksiegi-pierwsze</dc:relation.isPartOf>
-        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
-        <dc:contributor.editor xml:lang="pl">Krzyżanowski, Julian</dc:contributor.editor>
-        <dc:contributor.editor xml:lang="pl">Otwinowska, Barbara</dc:contributor.editor>
-        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
-        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
-        <dc:subject.period xml:lang="pl">Renesans</dc:subject.period>
-        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
-        <dc:subject.genre xml:lang="pl">Pieśń</dc:subject.genre>
-        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
-        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/piesni-ksiegi-pierwsze-piesn-vii-trudna-rada-w-tej-mierze-pr</dc:identifier.url>
-        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/1499</dc:source.URL>
-        <dc:source xml:lang="pl">Kochanowski, Jan (1530-1584), Dzieła polskie, tom 1, oprac. Julian Krzyżanowski, wyd. 8, Państwowy Instytut Wydawniczy, Warszawa, 1976</dc:source>
-        <dc:rights xml:lang="pl">Domena publiczna - Jan Kochanowski zm. 1584 </dc:rights>
-        <dc:date.pd xml:lang="pl">1584</dc:date.pd>
-        <dc:format xml:lang="pl">xml</dc:format>
-        <dc:type xml:lang="pl">text</dc:type>
-        <dc:type xml:lang="en">text</dc:type>
-        <dc:date xml:lang="pl">2007-08-31</dc:date>
-        <dc:audience xml:lang="pl">L</dc:audience>
-        <dc:language xml:lang="pl">pol</dc:language>
-    </rdf:Description>
-</rdf:RDF>
\ No newline at end of file
diff --git a/librarian/tests/files/dcparser/mickiewicz_rybka.xml b/librarian/tests/files/dcparser/mickiewicz_rybka.xml
deleted file mode 100644 (file)
index 0796a5b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
-    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Mickiewicz/Ballady/Rybka">
-        <dc:creator xml:lang="pl">Mickiewicz, Adam</dc:creator>
-        <dc:title xml:lang="pl">Rybka</dc:title>
-        <dc:relation.isPartOf xml:lang="pl">http://www.wolnelektury.pl/lektura/ballady-i-romanse</dc:relation.isPartOf>
-        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
-        <dc:contributor.editor xml:lang="pl">Kallenbach, Józef</dc:contributor.editor>
-        <dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
-        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
-        <dc:subject.period xml:lang="pl">Romantyzm</dc:subject.period>
-        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
-        <dc:subject.genre xml:lang="pl">Ballada</dc:subject.genre>
-        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
-        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/ballady-i-romanse-rybka</dc:identifier.url>
-        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/2222</dc:source.URL>
-        <dc:source xml:lang="pl">Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922</dc:source>
-        <dc:rights xml:lang="pl">Domena publiczna - Adam Mickiewicz zm. 1855</dc:rights>
-        <dc:date.pd xml:lang="pl">1855</dc:date.pd>
-        <dc:format xml:lang="pl">xml</dc:format>
-        <dc:type xml:lang="pl">text</dc:type>
-        <dc:type xml:lang="en">text</dc:type>
-        <dc:date xml:lang="pl">2007-09-06</dc:date>
-        <dc:audience xml:lang="pl">SP2</dc:audience>
-        <dc:audience xml:lang="pl">G</dc:audience>
-        <dc:audience xml:lang="pl">L</dc:audience>
-        <dc:language xml:lang="pl">pol</dc:language>
-    </rdf:Description>
-</rdf:RDF>
\ No newline at end of file
diff --git a/librarian/tests/files/dcparser/sofokles_antygona.xml b/librarian/tests/files/dcparser/sofokles_antygona.xml
deleted file mode 100644 (file)
index 4acb2d4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
-    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Sofokles/Antygona">
-        <dc:creator xml:lang="pl">Sofokles</dc:creator>
-        <dc:title xml:lang="pl">Antygona</dc:title>
-        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
-        <dc:contributor.translator xml:lang="pl">Morawski, Kazimierz</dc:contributor.translator>
-        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
-        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
-        <dc:subject.period xml:lang="pl">Starożytność</dc:subject.period>
-        <dc:subject.type xml:lang="pl">Dramat</dc:subject.type>
-        <dc:subject.genre xml:lang="pl">Tragedia</dc:subject.genre>
-        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
-        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/antygona</dc:identifier.url>
-        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/3768</dc:source.URL>
-        <dc:source xml:lang="pl">Sofokles (496-406 a.C.), Antygona, Zakład Narodowy im. Ossolińskich, wyd. 7, Lwów, 1939</dc:source>
-        <dc:rights xml:lang="pl">Domena publiczna - tłumacz Kazimierz Morawski zm. 1925</dc:rights>
-        <dc:date.pd xml:lang="pl">1925</dc:date.pd>
-        <dc:format xml:lang="pl">xml</dc:format>
-        <dc:type xml:lang="pl">text</dc:type>
-        <dc:type xml:lang="en">text</dc:type>
-        <dc:date xml:lang="pl">2007-08-30</dc:date>
-        <dc:audience xml:lang="pl">G</dc:audience>
-        <dc:language xml:lang="pl">pol</dc:language>
-    </rdf:Description>
-</rdf:RDF>
\ No newline at end of file
diff --git a/librarian/tests/files/erroneous/asnyk_miedzy_nami.html b/librarian/tests/files/erroneous/asnyk_miedzy_nami.html
deleted file mode 100644 (file)
index 1d7e17f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<div xmlns:wl="http://wolnelektury.pl/functions" id="book-text">
-  <div id="toc">
-    <h2>Spis treści</h2>
-    <ol/>
-  </div>
-  <h1>
-    <span class="author">Adam Asnyk</span>
-    <span class="title">Między nami nic nie było</span>
-  </h1>
-  <div class="stanza">
-    <p class="verse"><a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a>Między nami nic nie było!</p>
-    <p class="verse">
-    Żadnych zwierzeń, wyznań żadnych!</p>
-    <p class="verse">
-    Nic nas z sobą nie łączyło —</p>
-    <p class="verse">
-    Prócz wiosennych marzeń zdradnych;</p>
-  </div>
-  <div class="stanza">
-    <p class="verse"><a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a>Prócz tych woni, barw i blasków,</p>
-    <p class="verse">
-    Unoszących się w przestrzeni;</p>
-    <p class="verse">
-    Prócz szumiących śpiewem lasków</p>
-    <p class="verse">
-    I tej świeżej łąk zieleni;</p>
-  </div>
-  <div class="stanza">
-    <p class="verse">Prócz tych kaskad i potoków,</p>
-    <p class="verse"><a name="f10" class="target"> </a><a href="#f10" class="anchor">10</a>
-    Zraszających każdy parów,</p>
-    <p class="verse">
-    Prócz girlandy tęcz, obłoków,</p>
-    <p class="verse">
-    Prócz natury słodkich czarów;</p>
-  </div>
-  <div class="stanza">
-    <p class="verse">Prócz tych wspólnych, jasnych zdrojów,</p>
-    <p class="verse">
-    Z których serce zachwyt piło;</p>
-    <p class="verse"><a name="f15" class="target"> </a><a href="#f15" class="anchor">15</a>
-    Prócz pierwiosnków i powojów,—</p>
-    <p class="verse">
-    Między nami nic nie było!</p>
-  </div>
-</div>
diff --git a/librarian/tests/files/erroneous/asnyk_miedzy_nami.xml b/librarian/tests/files/erroneous/asnyk_miedzy_nami.xml
deleted file mode 100644 (file)
index aa5ef17..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<utwor><liryka_lp>
-    <autor_utworu>Adam Asnyk</autor_utworu>
-    <nazwa_utworu>Między nami nic nie było</nazwa_utworu>
-
-    <strofa>Między nami nic nie było!/
-    Żadnych zwierzeń, wyznań żadnych!/
-    Nic nas z sobą nie łączyło ---/
-    Prócz wiosennych marzeń zdradnych;</strofa>
-
-    <strofa>Prócz tych woni, barw i blasków,/
-    Unoszących się w przestrzeni;/
-    Prócz szumiących śpiewem lasków/
-    I tej świeżej łąk zieleni;
-
-    <strofa>Prócz tych kaskad i potoków,/
-    Zraszających każdy parów,/
-    Prócz girlandy tęcz, obłoków,/
-    Prócz natury słodkich czarów;</strofa>
-
-    <strofa>Prócz tych wspólnych, jasnych zdrojów,/
-    Z których serce zachwyt piło;/
-    Prócz pierwiosnków i powojów,---/
-    Między nami nic nie było!</strofa>
-</liryka_lp></utwor>
index db0d2b2..0754a99 100644 (file)
@@ -18,7 +18,20 @@ ENTITY_SUBSTITUTIONS = [
 ]
 
 
-MAX_LINE_LENGTH = 80
+TEMPLATE = u"""\
+Kodowanie znaków w dokumencie: UTF-8.
+-----
+Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl/). Reprodukcja cyfrowa wykonana przez
+Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN. Ten utwór nie jest chroniony prawem autorskim i znajduje
+się w domenie publicznej, co oznacza, że możesz go swobodnie wykorzystywać, publikować i rozpowszechniać.
+
+Wersja lektury w opracowaniu merytorycznym i krytycznym (przypisy i motywy) dostępna jest na stronie %(url)s.
+-----
+
+
+
+%(text)s
+"""
 
 
 def strip(context, text):
@@ -37,17 +50,20 @@ def substitute_entities(context, text):
     return text
 
 
-def wrap_words(context, text):
+def wrap_words(context, text, wrapping):
     """XPath extension function automatically wrapping words in passed text"""
     if isinstance(text, list):
         text = ''.join(text)
+    if not wrapping:
+        return text
+    
     words = re.split(r'\s', text)
     
     line_length = 0
     lines = [[]]
     for word in words:
         line_length += len(word) + 1
-        if line_length > MAX_LINE_LENGTH:
+        if line_length > wrapping:
             # Max line length was exceeded. We create new line
             lines.append([])
             line_length = len(word)
@@ -62,28 +78,22 @@ ns['substitute_entities'] = substitute_entities
 ns['wrap_words'] = wrap_words
 
 
-def transform(input_filename, output_filename):
+def transform(input_filename, output_filename, **options):
     """Transforms file input_filename in XML to output_filename in TXT."""
     # Parse XSLT
     style_filename = os.path.join(os.path.dirname(__file__), 'book2txt.xslt')
     style = etree.parse(style_filename)
 
-    doc_file = cStringIO.StringIO()
-    expr = re.compile(r'/\s', re.MULTILINE | re.UNICODE);
-    
-    f = open(input_filename, 'r')
-    for line in f:
-        line = line.decode('utf-8')
-        line = expr.sub(u'<br/>\n', line)
-        doc_file.write(line.encode('utf-8'))
-    f.close()
+    if is_file:
+        document = WLDocument.from_file(input, True)
+    else:
+        document = WLDocument.from_string(input, True)
 
-    doc_file.seek(0)
+    result = document.transform(style, **options)
 
-    parser = etree.XMLParser(remove_blank_text=True)
-    doc = etree.parse(doc_file, parser)
-    
-    result = doc.xslt(style)
     output_file = codecs.open(output_filename, 'wb', encoding='utf-8')
-    output_file.write(unicode(result) % dcparser.parse(input_filename).url)
+    output_file.write(TEMPLATE % {
+        'url': dcparser.parse(input_filename).url,
+        'text': unicode(result),
+    })
 
diff --git a/librarian/text.pyc b/librarian/text.pyc
deleted file mode 100644 (file)
index 6c6eb91..0000000
Binary files a/librarian/text.pyc and /dev/null differ
index a0229bb..02f2fa7 100755 (executable)
@@ -2,7 +2,7 @@
 import os
 import optparse
 
-from librarian import html
+from librarian import html, ParseError
 
 
 if __name__ == '__main__':
@@ -27,5 +27,25 @@ if __name__ == '__main__':
             print input_filename
         
         output_filename = os.path.splitext(input_filename)[0] + '.html'
-        html.transform(input_filename, output_filename)
+        try:
+            html.transform(input_filename, output_filename)
+        except ParseError, e:
+            print '%(file)s:%(name)s:%(message)s' % {
+                'file': input_filename,
+                'name': e.__class__.__name__,
+                'message': e.message
+            }
+        except IOError, e:
+            print '%(file)s:%(name)s:%(message)s' % {
+                'file': input_filename,
+                'name': e.__class__.__name__,
+                'message': e.strerror,
+            }
+        except BaseException, e:
+            print '%(file)s:%(etype)s:%(message)s' % {
+                'file': input_filename,
+                'etype': e.__class__.__name__,
+                'message': e.message,
+            }
+            raise e
 
index 1ca4623..41a3978 100755 (executable)
@@ -3,6 +3,7 @@ import os
 import optparse
 
 from librarian import text
+from librarian import dcparser, ParseError
 
 
 if __name__ == '__main__':
@@ -14,9 +15,11 @@ if __name__ == '__main__':
 
     parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
         help='print status messages to stdout')
-
+    parser.add_option('-w', '--wrap', action='store', type='int', dest='wrapping', default=0,
+        help='set line wrap column')
+    
     options, input_filenames = parser.parse_args()
-
+    
     if len(input_filenames) < 1:
         parser.print_help()
         exit(1)
@@ -27,5 +30,24 @@ if __name__ == '__main__':
             print input_filename
         
         output_filename = os.path.splitext(input_filename)[0] + '.txt'
-        text.transform(input_filename, output_filename)
-
+        try:
+            text.transform(input_filename, output_filename, wrapping=str(options.wrapping))
+        except ParseError, e:
+            print '%(file)s:%(name)s:%(message)s' % {
+                'file': input_filename,
+                'name': e.__class__.__name__,
+                'message': e.message
+            }
+        except IOError, e:
+            print '%(file)s:%(name)s:%(message)s' % {
+                'file': input_filename,
+                'name': e.__class__.__name__,
+                'message': e.strerror,
+            }
+        except BaseException, e:
+            print '%(file)s:%(etype)s:%(message)s' % {
+                'file': input_filename,
+                'etype': e.__class__.__name__,
+                'message': e.message,
+            }
+            raise e
old mode 100644 (file)
new mode 100755 (executable)
index 0988321..09bb42b
--- a/setup.py
+++ b/setup.py
@@ -1,19 +1,21 @@
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 from distutils.core import setup
-
+from tests.utils import TestCommand
 
 setup(
     name='librarian',
-    version='1.1',
+    version='1.2.1',
     description='Converter from WolneLektury.pl XML-based language to XHTML, TXT and other formats',
     author='Marek Stępniowski',
     author_email='marek@stepniowski.com',
     url='http://redmine.nowoczesnapolska.org.pl/',
-    packages=['librarian', 'librarian.tests'],
-    package_dir={'librarian': 'librarian'},
+    packages=['librarian', 'tests'],
+    package_dir={'librarian': 'librarian', 'tests': 'tests'},
     package_data={
         'librarian': ['*.xslt'],
-        'librarian.tests': ['files/dcparser/*.xml', 'files/erroneous/*.xml'],
+        'tests': ['files/dcparser/*.xml', 'files/erroneous/*.xml'],
     },
     scripts=['scripts/book2html', 'scripts/book2txt', 'scripts/bookfragments', 'scripts/genslugs'],
+    cmdclass={'test': TestCommand},
 )
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/dcparser/andersen_brzydkie_kaczatko.out b/tests/files/dcparser/andersen_brzydkie_kaczatko.out
new file mode 100644 (file)
index 0000000..fda83eb
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    'publisher': u'Fundacja Nowoczesna Polska',
+    'about': u'http://wiki.wolnepodreczniki.pl/Lektury:Andersen/Brzydkie_kaczątko',
+    'source_name': u'Andersen, Hans Christian (1805-1875), Baśnie, Gebethner i Wolff, wyd. 7, Kraków, 1925',
+    'author': u'Andersen, Hans Christian',
+    'url': u'http://wolnelektury.pl/katalog/lektura/brzydkie-kaczatko',
+    'created_at': u'2007-08-14',
+    'title': u'Brzydkie kaczątko',
+    'kind': u'Epika',
+    'source_url': u'http://www.polona.pl/dlibra/doccontent2?id=3563&dirids=4',
+    'translators': [u'Niewiadomska, Cecylia'],
+    'released_to_public_domain_at': u'1925-01-01',
+    'epoch': u'Romantyzm',
+    'genre': u'Baśń',
+    'technical_editors': [u'Gałecki, Dariusz'],
+    'license_description': u'Domena publiczna - tłumacz Cecylia Niewiadomska zm. 1925',
+}
diff --git a/tests/files/dcparser/andersen_brzydkie_kaczatko.xml b/tests/files/dcparser/andersen_brzydkie_kaczatko.xml
new file mode 100644 (file)
index 0000000..d653a9b
--- /dev/null
@@ -0,0 +1,24 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Andersen/Brzydkie_kaczątko">
+        <dc:creator xml:lang="pl">Andersen, Hans Christian</dc:creator>
+        <dc:title xml:lang="pl">Brzydkie kaczątko</dc:title>
+        <dc:contributor.translator xml:lang="pl">Niewiadomska, Cecylia</dc:contributor.translator>
+        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Romantyzm</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Epika</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Baśń</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/brzydkie-kaczatko</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/dlibra/doccontent2?id=3563&amp;dirids=4</dc:source.URL>
+        <dc:source xml:lang="pl">Andersen, Hans Christian (1805-1875), Baśnie, Gebethner i Wolff, wyd. 7, Kraków, 1925</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - tłumacz Cecylia Niewiadomska zm. 1925</dc:rights>
+        <dc:date.pd xml:lang="pl">1925</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-08-14</dc:date>
+        <dc:audience xml:lang="pl">SP1</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcparser/biedrzycki_akslop.out b/tests/files/dcparser/biedrzycki_akslop.out
new file mode 100644 (file)
index 0000000..1111b9c
--- /dev/null
@@ -0,0 +1,17 @@
+{
+            'editors': [u'Sekuła, Aleksandra'],
+            'publisher': u'Fundacja Nowoczesna Polska',
+            'about': 'http://wiki.wolnepodreczniki.pl/Lektury:Biedrzycki/Akslop',
+            'source_name': u'Miłosz Biedrzycki, * ("Gwiazdka"), Fundacja "brulion", Kraków-Warszawa, 1993',
+            'author': u'Biedrzycki, Miłosz',
+            'url': u'http://wolnelektury.pl/katalog/lektura/akslop',
+            'created_at': u'2009-06-04',
+            'title': u'Akslop',
+            'kind': u'Liryka',
+            'source_url': u'http://free.art.pl/mlb/gwiazdka.html#t1',
+            'epoch': u'Współczesność',
+            'genre': u'Wiersz',
+            'technical_editors': [u'Sutkowska, Olga'],
+            'license': u'http://creativecommons.org/licenses/by-sa/3.0/',
+            'license_description': u'Creative Commons Uznanie Autorstwa - Na Tych Samych Warunkach 3.0.PL'
+}
diff --git a/tests/files/dcparser/biedrzycki_akslop.xml b/tests/files/dcparser/biedrzycki_akslop.xml
new file mode 100644 (file)
index 0000000..da0cd9f
--- /dev/null
@@ -0,0 +1,25 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Biedrzycki/Akslop">
+        <dc:creator xml:lang="pl">Biedrzycki, Miłosz</dc:creator>
+        <dc:title xml:lang="pl">Akslop</dc:title>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Współczesność</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Wiersz</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl).</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/akslop</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://free.art.pl/mlb/gwiazdka.html#t1</dc:source.URL>
+        <dc:source xml:lang="pl">Miłosz Biedrzycki, * ("Gwiazdka"), Fundacja "brulion", Kraków-Warszawa, 1993</dc:source>
+        <dc:rights xml:lang="pl">Creative Commons Uznanie Autorstwa - Na Tych Samych Warunkach 3.0.PL</dc:rights>
+        <dc:rights.license>http://creativecommons.org/licenses/by-sa/3.0/</dc:rights.license>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2009-06-04</dc:date>
+        <dc:audience xml:lang="pl">L</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcparser/kochanowski_piesn7.out b/tests/files/dcparser/kochanowski_piesn7.out
new file mode 100644 (file)
index 0000000..4c1dc8f
--- /dev/null
@@ -0,0 +1,18 @@
+{
+            'publisher': u'Fundacja Nowoczesna Polska',
+            'about': u'http://wiki.wolnepodreczniki.pl/Lektury:Kochanowski/Pieśni/Pieśń_VII_(1)',
+            'source_name': u'Kochanowski, Jan (1530-1584), Dzieła polskie, tom 1, oprac. Julian Krzyżanowski, wyd. 8, Państwowy Instytut Wydawniczy, Warszawa, 1976',
+            'author': u'Kochanowski, Jan',
+            'url': u'http://wolnelektury.pl/katalog/lektura/piesni-ksiegi-pierwsze-piesn-vii-trudna-rada-w-tej-mierze-pr',
+            'created_at': u'2007-08-31',
+            'title': u'Pieśń VII (Trudna rada w tej mierze: przyjdzie się rozjechać...)',
+            'kind': u'Liryka',
+            'source_url': u'http://www.polona.pl/Content/1499',
+            'released_to_public_domain_at': u'1584-01-01',
+            'epoch': u'Renesans',
+            'genre': u'Pieśń',
+            'technical_editors': [u'Gałecki, Dariusz'],
+            'license_description': u'Domena publiczna - Jan Kochanowski zm. 1584 ',
+            'editors': [u'Sekuła, Aleksandra', u'Krzyżanowski, Julian', u'Otwinowska, Barbara'],
+}
+
diff --git a/tests/files/dcparser/kochanowski_piesn7.xml b/tests/files/dcparser/kochanowski_piesn7.xml
new file mode 100644 (file)
index 0000000..b4d8d2e
--- /dev/null
@@ -0,0 +1,27 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Kochanowski/Pieśni/Pieśń_VII_(1)">
+        <dc:creator xml:lang="pl">Kochanowski, Jan</dc:creator>
+        <dc:title xml:lang="pl">Pieśń VII (Trudna rada w tej mierze: przyjdzie się rozjechać...)</dc:title>
+        <dc:relation.isPartOf xml:lang="pl">http://www.wolnelektury.pl/lektura/piesni-ksiegi-pierwsze</dc:relation.isPartOf>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.editor xml:lang="pl">Krzyżanowski, Julian</dc:contributor.editor>
+        <dc:contributor.editor xml:lang="pl">Otwinowska, Barbara</dc:contributor.editor>
+        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Renesans</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Pieśń</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/piesni-ksiegi-pierwsze-piesn-vii-trudna-rada-w-tej-mierze-pr</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/1499</dc:source.URL>
+        <dc:source xml:lang="pl">Kochanowski, Jan (1530-1584), Dzieła polskie, tom 1, oprac. Julian Krzyżanowski, wyd. 8, Państwowy Instytut Wydawniczy, Warszawa, 1976</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - Jan Kochanowski zm. 1584 </dc:rights>
+        <dc:date.pd xml:lang="pl">1584</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-08-31</dc:date>
+        <dc:audience xml:lang="pl">L</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
diff --git a/tests/files/dcparser/mickiewicz_rybka.out b/tests/files/dcparser/mickiewicz_rybka.out
new file mode 100644 (file)
index 0000000..ff4bd98
--- /dev/null
@@ -0,0 +1,18 @@
+{
+            'editors': [u'Sekuła, Aleksandra', u'Kallenbach, Józef'],
+            'publisher': u'Fundacja Nowoczesna Polska',
+            'about': 'http://wiki.wolnepodreczniki.pl/Lektury:Mickiewicz/Ballady/Rybka',
+            'source_name': u'Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922',
+            'author': u'Mickiewicz, Adam',
+            'url': u'http://wolnelektury.pl/katalog/lektura/ballady-i-romanse-rybka',
+            'created_at': u'2007-09-06',
+            'title': u'Rybka',
+            'kind': u'Liryka',
+            'source_url': u'http://www.polona.pl/Content/2222',
+            'released_to_public_domain_at': u'1855-01-01',
+            'epoch': u'Romantyzm',
+            'genre': u'Ballada',
+            'technical_editors': [u'Sutkowska, Olga'],
+            'license_description': u'Domena publiczna - Adam Mickiewicz zm. 1855',
+}
+
diff --git a/tests/files/dcparser/mickiewicz_rybka.xml b/tests/files/dcparser/mickiewicz_rybka.xml
new file mode 100644 (file)
index 0000000..0796a5b
--- /dev/null
@@ -0,0 +1,28 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Mickiewicz/Ballady/Rybka">
+        <dc:creator xml:lang="pl">Mickiewicz, Adam</dc:creator>
+        <dc:title xml:lang="pl">Rybka</dc:title>
+        <dc:relation.isPartOf xml:lang="pl">http://www.wolnelektury.pl/lektura/ballady-i-romanse</dc:relation.isPartOf>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.editor xml:lang="pl">Kallenbach, Józef</dc:contributor.editor>
+        <dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Romantyzm</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Ballada</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/ballady-i-romanse-rybka</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/2222</dc:source.URL>
+        <dc:source xml:lang="pl">Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - Adam Mickiewicz zm. 1855</dc:rights>
+        <dc:date.pd xml:lang="pl">1855</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-09-06</dc:date>
+        <dc:audience xml:lang="pl">SP2</dc:audience>
+        <dc:audience xml:lang="pl">G</dc:audience>
+        <dc:audience xml:lang="pl">L</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcparser/sofokles_antygona.out b/tests/files/dcparser/sofokles_antygona.out
new file mode 100644 (file)
index 0000000..0f2b4d0
--- /dev/null
@@ -0,0 +1,19 @@
+{
+            'editors': [u'Sekuła, Aleksandra'],
+            'publisher': u'Fundacja Nowoczesna Polska',
+            'about': 'http://wiki.wolnepodreczniki.pl/Lektury:Sofokles/Antygona',
+            'source_name': u'Sofokles (496-406 a.C.), Antygona, Zakład Narodowy im. Ossolińskich, wyd. 7, Lwów, 1939',
+            'author': u'Sofokles',
+            'url': u'http://wolnelektury.pl/katalog/lektura/antygona',
+            'created_at': u'2007-08-30',
+            'title': u'Antygona',
+            'kind': u'Dramat',
+            'source_url': u'http://www.polona.pl/Content/3768',
+            'translators': [u'Morawski, Kazimierz'],
+            'released_to_public_domain_at': u'1925-01-01',
+            'epoch': u'Starożytność',
+            'genre': u'Tragedia',
+            'technical_editors': [u'Gałecki, Dariusz'],
+            'license_description': u'Domena publiczna - tłumacz Kazimierz Morawski zm. 1925',
+}
+
diff --git a/tests/files/dcparser/sofokles_antygona.xml b/tests/files/dcparser/sofokles_antygona.xml
new file mode 100644 (file)
index 0000000..4acb2d4
--- /dev/null
@@ -0,0 +1,25 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Sofokles/Antygona">
+        <dc:creator xml:lang="pl">Sofokles</dc:creator>
+        <dc:title xml:lang="pl">Antygona</dc:title>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.translator xml:lang="pl">Morawski, Kazimierz</dc:contributor.translator>
+        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Starożytność</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Dramat</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Tragedia</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/antygona</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/3768</dc:source.URL>
+        <dc:source xml:lang="pl">Sofokles (496-406 a.C.), Antygona, Zakład Narodowy im. Ossolińskich, wyd. 7, Lwów, 1939</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - tłumacz Kazimierz Morawski zm. 1925</dc:rights>
+        <dc:date.pd xml:lang="pl">1925</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-08-30</dc:date>
+        <dc:audience xml:lang="pl">G</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcserialize/andersen_brzydkie_kaczatko.out b/tests/files/dcserialize/andersen_brzydkie_kaczatko.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/dcserialize/andersen_brzydkie_kaczatko.xml b/tests/files/dcserialize/andersen_brzydkie_kaczatko.xml
new file mode 100644 (file)
index 0000000..d653a9b
--- /dev/null
@@ -0,0 +1,24 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Andersen/Brzydkie_kaczątko">
+        <dc:creator xml:lang="pl">Andersen, Hans Christian</dc:creator>
+        <dc:title xml:lang="pl">Brzydkie kaczątko</dc:title>
+        <dc:contributor.translator xml:lang="pl">Niewiadomska, Cecylia</dc:contributor.translator>
+        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Romantyzm</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Epika</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Baśń</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/brzydkie-kaczatko</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/dlibra/doccontent2?id=3563&amp;dirids=4</dc:source.URL>
+        <dc:source xml:lang="pl">Andersen, Hans Christian (1805-1875), Baśnie, Gebethner i Wolff, wyd. 7, Kraków, 1925</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - tłumacz Cecylia Niewiadomska zm. 1925</dc:rights>
+        <dc:date.pd xml:lang="pl">1925</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-08-14</dc:date>
+        <dc:audience xml:lang="pl">SP1</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcserialize/biedrzycki_akslop.out b/tests/files/dcserialize/biedrzycki_akslop.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/dcserialize/biedrzycki_akslop.xml b/tests/files/dcserialize/biedrzycki_akslop.xml
new file mode 100644 (file)
index 0000000..da0cd9f
--- /dev/null
@@ -0,0 +1,25 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Biedrzycki/Akslop">
+        <dc:creator xml:lang="pl">Biedrzycki, Miłosz</dc:creator>
+        <dc:title xml:lang="pl">Akslop</dc:title>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Współczesność</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Wiersz</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl).</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/akslop</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://free.art.pl/mlb/gwiazdka.html#t1</dc:source.URL>
+        <dc:source xml:lang="pl">Miłosz Biedrzycki, * ("Gwiazdka"), Fundacja "brulion", Kraków-Warszawa, 1993</dc:source>
+        <dc:rights xml:lang="pl">Creative Commons Uznanie Autorstwa - Na Tych Samych Warunkach 3.0.PL</dc:rights>
+        <dc:rights.license>http://creativecommons.org/licenses/by-sa/3.0/</dc:rights.license>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2009-06-04</dc:date>
+        <dc:audience xml:lang="pl">L</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcserialize/kochanowski_piesn7.out b/tests/files/dcserialize/kochanowski_piesn7.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/dcserialize/kochanowski_piesn7.xml b/tests/files/dcserialize/kochanowski_piesn7.xml
new file mode 100644 (file)
index 0000000..b4d8d2e
--- /dev/null
@@ -0,0 +1,27 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Kochanowski/Pieśni/Pieśń_VII_(1)">
+        <dc:creator xml:lang="pl">Kochanowski, Jan</dc:creator>
+        <dc:title xml:lang="pl">Pieśń VII (Trudna rada w tej mierze: przyjdzie się rozjechać...)</dc:title>
+        <dc:relation.isPartOf xml:lang="pl">http://www.wolnelektury.pl/lektura/piesni-ksiegi-pierwsze</dc:relation.isPartOf>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.editor xml:lang="pl">Krzyżanowski, Julian</dc:contributor.editor>
+        <dc:contributor.editor xml:lang="pl">Otwinowska, Barbara</dc:contributor.editor>
+        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Renesans</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Pieśń</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/piesni-ksiegi-pierwsze-piesn-vii-trudna-rada-w-tej-mierze-pr</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/1499</dc:source.URL>
+        <dc:source xml:lang="pl">Kochanowski, Jan (1530-1584), Dzieła polskie, tom 1, oprac. Julian Krzyżanowski, wyd. 8, Państwowy Instytut Wydawniczy, Warszawa, 1976</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - Jan Kochanowski zm. 1584 </dc:rights>
+        <dc:date.pd xml:lang="pl">1584</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-08-31</dc:date>
+        <dc:audience xml:lang="pl">L</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
diff --git a/tests/files/dcserialize/mickiewicz_rybka.out b/tests/files/dcserialize/mickiewicz_rybka.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/dcserialize/mickiewicz_rybka.xml b/tests/files/dcserialize/mickiewicz_rybka.xml
new file mode 100644 (file)
index 0000000..0796a5b
--- /dev/null
@@ -0,0 +1,28 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Mickiewicz/Ballady/Rybka">
+        <dc:creator xml:lang="pl">Mickiewicz, Adam</dc:creator>
+        <dc:title xml:lang="pl">Rybka</dc:title>
+        <dc:relation.isPartOf xml:lang="pl">http://www.wolnelektury.pl/lektura/ballady-i-romanse</dc:relation.isPartOf>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.editor xml:lang="pl">Kallenbach, Józef</dc:contributor.editor>
+        <dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Romantyzm</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Ballada</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/ballady-i-romanse-rybka</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/2222</dc:source.URL>
+        <dc:source xml:lang="pl">Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - Adam Mickiewicz zm. 1855</dc:rights>
+        <dc:date.pd xml:lang="pl">1855</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-09-06</dc:date>
+        <dc:audience xml:lang="pl">SP2</dc:audience>
+        <dc:audience xml:lang="pl">G</dc:audience>
+        <dc:audience xml:lang="pl">L</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/dcserialize/sofokles_antygona.out b/tests/files/dcserialize/sofokles_antygona.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/dcserialize/sofokles_antygona.xml b/tests/files/dcserialize/sofokles_antygona.xml
new file mode 100644 (file)
index 0000000..4acb2d4
--- /dev/null
@@ -0,0 +1,25 @@
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+    <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Sofokles/Antygona">
+        <dc:creator xml:lang="pl">Sofokles</dc:creator>
+        <dc:title xml:lang="pl">Antygona</dc:title>
+        <dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+        <dc:contributor.translator xml:lang="pl">Morawski, Kazimierz</dc:contributor.translator>
+        <dc:contributor.technical_editor xml:lang="pl">Gałecki, Dariusz</dc:contributor.technical_editor>
+        <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+        <dc:subject.period xml:lang="pl">Starożytność</dc:subject.period>
+        <dc:subject.type xml:lang="pl">Dramat</dc:subject.type>
+        <dc:subject.genre xml:lang="pl">Tragedia</dc:subject.genre>
+        <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+        <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/antygona</dc:identifier.url>
+        <dc:source.URL xml:lang="pl">http://www.polona.pl/Content/3768</dc:source.URL>
+        <dc:source xml:lang="pl">Sofokles (496-406 a.C.), Antygona, Zakład Narodowy im. Ossolińskich, wyd. 7, Lwów, 1939</dc:source>
+        <dc:rights xml:lang="pl">Domena publiczna - tłumacz Kazimierz Morawski zm. 1925</dc:rights>
+        <dc:date.pd xml:lang="pl">1925</dc:date.pd>
+        <dc:format xml:lang="pl">xml</dc:format>
+        <dc:type xml:lang="pl">text</dc:type>
+        <dc:type xml:lang="en">text</dc:type>
+        <dc:date xml:lang="pl">2007-08-30</dc:date>
+        <dc:audience xml:lang="pl">G</dc:audience>
+        <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+</rdf:RDF>
\ No newline at end of file
diff --git a/tests/files/erroneous/asnyk_miedzy_nami.html b/tests/files/erroneous/asnyk_miedzy_nami.html
new file mode 100644 (file)
index 0000000..1d7e17f
--- /dev/null
@@ -0,0 +1,46 @@
+<div xmlns:wl="http://wolnelektury.pl/functions" id="book-text">
+  <div id="toc">
+    <h2>Spis treści</h2>
+    <ol/>
+  </div>
+  <h1>
+    <span class="author">Adam Asnyk</span>
+    <span class="title">Między nami nic nie było</span>
+  </h1>
+  <div class="stanza">
+    <p class="verse"><a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a>Między nami nic nie było!</p>
+    <p class="verse">
+    Żadnych zwierzeń, wyznań żadnych!</p>
+    <p class="verse">
+    Nic nas z sobą nie łączyło —</p>
+    <p class="verse">
+    Prócz wiosennych marzeń zdradnych;</p>
+  </div>
+  <div class="stanza">
+    <p class="verse"><a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a>Prócz tych woni, barw i blasków,</p>
+    <p class="verse">
+    Unoszących się w przestrzeni;</p>
+    <p class="verse">
+    Prócz szumiących śpiewem lasków</p>
+    <p class="verse">
+    I tej świeżej łąk zieleni;</p>
+  </div>
+  <div class="stanza">
+    <p class="verse">Prócz tych kaskad i potoków,</p>
+    <p class="verse"><a name="f10" class="target"> </a><a href="#f10" class="anchor">10</a>
+    Zraszających każdy parów,</p>
+    <p class="verse">
+    Prócz girlandy tęcz, obłoków,</p>
+    <p class="verse">
+    Prócz natury słodkich czarów;</p>
+  </div>
+  <div class="stanza">
+    <p class="verse">Prócz tych wspólnych, jasnych zdrojów,</p>
+    <p class="verse">
+    Z których serce zachwyt piło;</p>
+    <p class="verse"><a name="f15" class="target"> </a><a href="#f15" class="anchor">15</a>
+    Prócz pierwiosnków i powojów,—</p>
+    <p class="verse">
+    Między nami nic nie było!</p>
+  </div>
+</div>
diff --git a/tests/files/erroneous/asnyk_miedzy_nami.xml b/tests/files/erroneous/asnyk_miedzy_nami.xml
new file mode 100644 (file)
index 0000000..aa5ef17
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version='1.0' encoding='utf-8'?>
+<utwor><liryka_lp>
+    <autor_utworu>Adam Asnyk</autor_utworu>
+    <nazwa_utworu>Między nami nic nie było</nazwa_utworu>
+
+    <strofa>Między nami nic nie było!/
+    Żadnych zwierzeń, wyznań żadnych!/
+    Nic nas z sobą nie łączyło ---/
+    Prócz wiosennych marzeń zdradnych;</strofa>
+
+    <strofa>Prócz tych woni, barw i blasków,/
+    Unoszących się w przestrzeni;/
+    Prócz szumiących śpiewem lasków/
+    I tej świeżej łąk zieleni;
+
+    <strofa>Prócz tych kaskad i potoków,/
+    Zraszających każdy parów,/
+    Prócz girlandy tęcz, obłoków,/
+    Prócz natury słodkich czarów;</strofa>
+
+    <strofa>Prócz tych wspólnych, jasnych zdrojów,/
+    Z których serce zachwyt piło;/
+    Prócz pierwiosnków i powojów,---/
+    Między nami nic nie było!</strofa>
+</liryka_lp></utwor>
diff --git a/tests/files/text/asnyk_miedzy_nami.txt b/tests/files/text/asnyk_miedzy_nami.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/files/text/asnyk_miedzy_nami.xml b/tests/files/text/asnyk_miedzy_nami.xml
new file mode 100644 (file)
index 0000000..5716a28
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version='1.0' encoding='utf-8'?>
+<utwor><liryka_lp>
+    <autor_utworu>Adam Asnyk</autor_utworu>
+    <nazwa_utworu>Między nami nic nie było</nazwa_utworu>
+
+    <strofa>Między nami nic nie było!/
+    Żadnych zwierzeń, wyznań żadnych!/
+    Nic nas z sobą nie łączyło ---/
+    Prócz wiosennych marzeń zdradnych;</strofa>
+
+    <strofa>Prócz tych woni, barw i blasków,/
+    Unoszących się w przestrzeni;/
+    Prócz szumiących śpiewem lasków/
+    I tej świeżej łąk zieleni;</strofa>
+
+    <strofa>Prócz tych kaskad i potoków,/
+    Zraszających każdy parów,/
+    Prócz girlandy tęcz, obłoków,/
+    Prócz natury słodkich czarów;</strofa>
+
+    <strofa>Prócz tych wspólnych, jasnych zdrojów,/
+    Z których serce zachwyt piło;/
+    Prócz pierwiosnków i powojów,---/
+    Między nami nic nie było!</strofa>
+</liryka_lp></utwor>
diff --git a/tests/test_dcparser.py b/tests/test_dcparser.py
new file mode 100755 (executable)
index 0000000..62e664c
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import unittest
+
+from lxml import etree
+from utils import get_file_path
+from librarian import dcparser, html, ParseError
+from utils import AutoTestMetaclass
+
+class TestDCParser(unittest.TestCase):
+    __metaclass__ = AutoTestMetaclass
+
+    TEST_DIR = 'dcparser'
+
+    def run_auto_test(self, in_data, out_data):
+        info = dcparser.BookInfo.from_string(in_data).to_dict()
+        should_be = eval(out_data)
+        for key in should_be:
+            self.assertEqual( info[key], should_be[key] )
+
+class TestDCSerialize(unittest.TestCase):
+    __metaclass__ = AutoTestMetaclass
+
+    TEST_DIR = 'dcserialize'
+
+    def run_auto_test(self, in_data, out_data):
+        import lxml.etree
+        # first parse the input
+        info = dcparser.BookInfo.from_string(in_data)
+
+        # serialize
+        serialized = lxml.etree.tostring(info.to_etree(), encoding=unicode).encode('utf-8')
+
+        # then parse again
+        info_bis = dcparser.BookInfo.from_string(serialized)
+
+        # check if they are the same
+        for key in vars(info):
+            self.assertEqual( getattr(info, key), getattr(info_bis, key))
+
+        for key in vars(info_bis):
+            self.assertEqual( getattr(info, key), getattr(info_bis, key))
+
+class TestParserErrors(unittest.TestCase):
+    def test_error(self):
+        try:
+            html.transform(get_file_path('erroneous', 'asnyk_miedzy_nami.xml'),
+                           get_file_path('erroneous', 'asnyk_miedzy_nami.html'))
+            self.fail()
+        except ParseError:
+            pass
+            #self.assertEqual(e.position, (25, 13))    
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_text.py b/tests/test_text.py
new file mode 100755 (executable)
index 0000000..00fd787
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import unittest
+
+from utils import get_file_path
+from librarian import dcparser
+from librarian import text, NoDublinCore
+
+
+class TestXML(unittest.TestCase):
+    def test_no_dublincore(self):
+        try:
+            text.transform(get_file_path('text', 'asnyk_miedzy_nami.xml'),
+                           get_file_path('text', 'asnyk_miedzy_nami.txt'))
+            self.fail()
+        except NoDublinCore, e:
+            pass
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/utils.py b/tests/utils.py
new file mode 100644 (file)
index 0000000..1870a07
--- /dev/null
@@ -0,0 +1,62 @@
+from __future__ import with_statement
+
+import os
+from distutils.core import Command
+from unittest import TextTestRunner, TestLoader
+from glob import glob
+from os.path import dirname, join, realpath, splitext, basename, walk
+from os import listdir
+import codecs
+
+class AutoTestMetaclass(type):
+
+    def __new__(cls, name, bases, class_dict):        
+        test_dir = class_dict.pop('TEST_DIR')
+        path = realpath( join(dirname(__file__), 'files', test_dir) )
+
+        for file in listdir(path):
+            base, ext = splitext(file)
+            if ext != '.xml':
+                continue
+
+            class_dict['test_'+base] = cls.make_test_runner(base, \
+                    join(path, base +'.xml'), join(path, base + '.out') )
+
+        return type.__new__(cls, name, bases, class_dict)
+    
+    @staticmethod
+    def make_test_runner(name, inputf, outputf):
+        def runner(self):
+            with open(inputf, 'rb') as ifd:
+                with codecs.open(outputf, 'rb', encoding='utf-8') as ofd:
+                    self.run_auto_test(ifd.read(), ofd.read())            
+        return runner
+
+
+def get_file_path(dir_name, file_name):
+    return realpath(join(dirname(__file__), 'files', dir_name, file_name))
+
+class TestCommand(Command):
+    user_options = []
+
+    def initialize_options(self):
+        self._dir = os.getcwd()
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        '''
+        Finds all the tests modules in tests/, and runs them.
+        '''
+        testfiles = []
+        for t in glob(join(self._dir, 'tests', '*.py')):
+            module_name = splitext(basename(t))[0]
+            if module_name.startswith('test'):
+                testfiles.append('.'.join(['tests', module_name])
+                )
+
+        tests = TestLoader().loadTestsFromNames(testfiles)
+        t = TextTestRunner(verbosity=2)
+        t.run(tests)
+