import os
import os.path
+import re
import subprocess
from StringIO import StringIO
from copy import deepcopy
find_annotations(annotations, child, part_no)
+class Stanza(object):
+ """
+ Converts / verse endings into verse elements in a stanza.
+
+ Slashes may only occur directly in the stanza. Any slashes in subelements
+ will be ignored, and the subelements will be put inside verse elements.
+
+ >>> s = etree.fromstring("<strofa>a/\\nb<x>x/\\ny</x>c/ \\nd</strofa>")
+ >>> Stanza(s).versify()
+ >>> print etree.tostring(s)
+ <strofa><wers_normalny>a</wers_normalny><wers_normalny>b<x>x/
+ y</x>c</wers_normalny><wers_normalny>d</wers_normalny></strofa>
+
+ """
+ def __init__(self, stanza_elem):
+ self.stanza = stanza_elem
+ self.verses = []
+ self.open_verse = None
+
+ def versify(self):
+ self.push_text(self.stanza.text)
+ for elem in self.stanza:
+ self.push_elem(elem)
+ self.push_text(elem.tail)
+ tail = self.stanza.tail
+ self.stanza.clear()
+ self.stanza.tail = tail
+ self.stanza.extend(self.verses)
+
+ def open_normal_verse(self):
+ self.open_verse = self.stanza.makeelement("wers_normalny")
+ self.verses.append(self.open_verse)
+
+ def get_open_verse(self):
+ if self.open_verse is None:
+ self.open_normal_verse()
+ return self.open_verse
+
+ def push_text(self, text):
+ if not text or not text.strip():
+ return
+ for i, verse_text in enumerate(re.split(r"/\s*\n", text)):
+ if i:
+ self.open_normal_verse()
+ verse = self.get_open_verse()
+ if len(verse):
+ verse[-1].tail = (verse[-1].tail or "") + verse_text.strip()
+ else:
+ verse.text = (verse.text or "") + verse_text.strip()
+
+ def push_elem(self, elem):
+ if elem.tag.startswith("wers"):
+ verse = deepcopy(elem)
+ verse.tail = None
+ self.verses.append(verse)
+ self.open_verse = verse
+ else:
+ appended = deepcopy(elem)
+ appended.tail = None
+ self.get_open_verse().append(appended)
+
+
def replace_by_verse(tree):
""" Find stanzas and create new verses in place of a '/' character """
stanzas = tree.findall('.//' + WLNS('strofa'))
- for node in stanzas:
- for child_node in node:
- if child_node.tag in ('slowo_obce', 'wyroznienie'):
- foreign_verses = inner_xml(child_node).split('/\n')
- if len(foreign_verses) > 1:
- new_foreign = ''
- for foreign_verse in foreign_verses:
- if foreign_verse.startswith('<wers'):
- new_foreign += foreign_verse
- else:
- new_foreign += ''.join(('<wers_normalny>', foreign_verse, '</wers_normalny>'))
- set_inner_xml(child_node, new_foreign)
- verses = inner_xml(node).split('/\n')
- if len(verses) > 1:
- modified_inner_xml = ''
- for verse in verses:
- if verse.startswith('<wers') or verse.startswith('<extra'):
- modified_inner_xml += verse
- else:
- modified_inner_xml += ''.join(('<wers_normalny>', verse, '</wers_normalny>'))
- set_inner_xml(node, modified_inner_xml)
+ for stanza in stanzas:
+ Stanza(stanza).versify()
def add_to_manifest(manifest, partno):
functions.reg_substitute_entities()
+functions.reg_person_name()
+
+
+def sectionify(tree):
+ """Finds section headers and adds a tree of _section tags."""
+ sections = ['naglowek_czesc',
+ 'naglowek_akt', 'naglowek_rozdzial', 'naglowek_scena',
+ 'naglowek_podrozdzial']
+ section_level = dict((v,k) for (k,v) in enumerate(sections))
+
+ # We can assume there are just subelements an no text at section level.
+ for level, section_name in reversed(list(enumerate(sections))):
+ for header in tree.findall('//' + section_name):
+ section = header.makeelement("_section")
+ header.addprevious(section)
+ section.append(header)
+ sibling = section.getnext()
+ while (sibling is not None and
+ section_level.get(sibling.tag, 1000) > level):
+ section.append(sibling)
+ sibling = section.getnext()
+
def transform(wldoc, verbose=False,
cover=None, flags=None):
style = etree.parse(style_filename)
replace_by_verse(document.edoc)
+ sectionify(document.edoc)
result = document.transform(style)
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
+ Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:wl="http://wolnelektury.pl/functions"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"
+ xmlns:l="http://www.w3.org/1999/xlink">
+
+ <xsl:template mode="para" match="lista_osob">
+ <empty-line/>
+ <xsl:apply-templates mode="para"/>
+ <empty-line/>
+ </xsl:template>
+
+ <xsl:template mode="para" match="kwestia">
+ <empty-line/>
+ <xsl:apply-templates mode="para"/>
+ <empty-line/>
+ </xsl:template>
+
+ <xsl:template mode="para" match="lista_osoba">
+ <p><xsl:apply-templates mode="inline"/></p>
+ </xsl:template>
+
+ <xsl:template mode="para" match="naglowek_listy|naglowek_osoba">
+ <p><strong><xsl:apply-templates mode="inline"/></strong></p>
+ </xsl:template>
+
+ <xsl:template mode="para" match="miejsce_czas|didaskalia|didask_tekst">
+ <p><emphasis><xsl:apply-templates mode="inline"/></emphasis></p>
+ </xsl:template>
+
+ <xsl:template mode="inline" match="didaskalia|didask_tekst">
+ <emphasis><xsl:apply-templates mode="inline"/></emphasis>
+ </xsl:template>
+
+</xsl:stylesheet>
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wl="http://wolnelektury.pl/functions"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"
xmlns:l="http://www.w3.org/1999/xlink">
<xsl:include href="paragraphs.xslt"/>
<xsl:include href="poems.xslt"/>
<xsl:include href="sections.xslt"/>
+ <xsl:include href="drama.xslt"/>
<xsl:strip-space elements="*"/>
<xsl:output encoding="utf-8" method="xml" indent="yes"/>
</xsl:template>
<!-- we can't handle lyrics nicely yet -->
- <xsl:template match="powiesc|opowiadanie|liryka_l|liryka_lp" mode="outer">
+ <xsl:template match="powiesc|opowiadanie|liryka_l|liryka_lp|dramat_wierszowany_l|dramat_wierszowany_lp" mode="outer">
<body> <!-- main body for main book flow -->
<xsl:if test="autor_utworu or nazwa_utworu">
<title>
<xsl:apply-templates mode="title"
- select="autor_utworu|dzielo_nadrzedne|nazwa_utworu"/>
+ select="autor_utworu|dzielo_nadrzedne|nazwa_utworu|podtytul"/>
+ <xsl:call-template name="translators" />
</title>
</xsl:if>
</p>
</epigraph>
- <xsl:variable name="sections" select="count(naglowek_rozdzial)"/>
- <section>
- <xsl:choose>
- <xsl:when test="local-name() = 'liryka_l'">
- <poem>
- <xsl:apply-templates mode="para"/>
- </poem>
- </xsl:when>
-
- <xsl:otherwise>
- <xsl:apply-templates mode="para"
- select="*[count(following-sibling::naglowek_rozdzial)
- = $sections]"/>
- </xsl:otherwise>
- </xsl:choose>
- </section>
-
- <xsl:apply-templates mode="sections"/>
+ <xsl:call-template name="section" />
</body>
</xsl:template>
<p><xsl:apply-templates mode="inline"/></p>
</xsl:template>
+ <xsl:template name="translators">
+ <xsl:if test="//dc:contributor.translator">
+ <p>
+ <xsl:text>tłum. </xsl:text>
+ <xsl:for-each select="//dc:contributor.translator">
+ <xsl:if test="position() != 1">, </xsl:if>
+ <xsl:apply-templates mode="person" />
+ </xsl:for-each>
+ </p>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="text()" mode="person">
+ <xsl:value-of select="wl:person_name(.)" />
+ </xsl:template>
+
+
<xsl:template match="uwaga" mode="title"/>
<xsl:template match="extra" mode="title"/>
</xsl:stylesheet>
xmlns:l="http://www.w3.org/1999/xlink">
<!-- footnote body mode -->
- <xsl:template match="pe" mode="footnotes">
+ <xsl:template match="pa|pe|pr|pt" mode="footnotes">
<!-- we number them absolutely -->
- <xsl:variable name="n" select="count(preceding::pe) + 1"/>
+ <xsl:variable name="n" select="count(preceding::pa) + count(preceding::pe) + count(preceding::pr) + count(preceding::pt) + 1"/>
<xsl:element name="section">
<xsl:attribute name="id">fn<xsl:value-of select="$n"/></xsl:attribute>
- <p><xsl:apply-templates mode="inline"/></p>
+ <p><xsl:apply-templates mode="inline"/>
+ <xsl:if test="local-name() = 'pa'">
+ <xsl:text> [przypis autorski]</xsl:text>
+ </xsl:if></p>
</xsl:element>
</xsl:template>
<xsl:template match="text()" mode="footnotes"/>
<!-- footnote links -->
- <xsl:template match="pe" mode="inline">
- <xsl:variable name="n" select="count(preceding::pe) + 1"/>
+ <xsl:template match="pa|pe|pr|pt" mode="inline">
+ <xsl:variable name="n" select="count(preceding::pa) + count(preceding::pe) + count(preceding::pr) + count(preceding::pt) + 1"/>
<xsl:element name="a">
<xsl:attribute name="type">note</xsl:attribute>
<xsl:attribute name="l:href">#fn<xsl:value-of select="$n"/></xsl:attribute>
<xsl:template match="motyw" mode="inline"/>
<!-- formatting -->
- <xsl:template match="slowo_obce|tytul_dziela">
+ <xsl:template match="slowo_obce" mode="inline">
<emphasis>
<xsl:apply-templates mode="inline"/>
</emphasis>
</xsl:template>
- <xsl:template match="wyroznienie">
+ <xsl:template match="tytul_dziela" mode="inline">
+ <emphasis>
+ <xsl:if test="@typ">„</xsl:if>
+ <xsl:apply-templates mode="inline"/>
+ <xsl:if test="@typ">”</xsl:if>
+ </emphasis>
+ </xsl:template>
+ <xsl:template match="wyroznienie" mode="inline">
<strong>
<xsl:apply-templates mode="inline"/>
</strong>
<!-- in paragraph mode -->
- <xsl:template mode="para" match="akap|akap_dialog">
+ <xsl:template mode="para" match="akap|akap_dialog|akap_cd|motto_podpis">
<!-- paragraphs & similar -->
<p><xsl:apply-templates mode="inline"/></p>
</xsl:template>
+ <xsl:template mode="para" match="dlugi_cytat|motto|dedykacja|nota">
+ <cite><xsl:apply-templates mode="para"/></cite>
+ </xsl:template>
+
+ <xsl:template mode="para" match="srodtytul">
+ <p><strong><xsl:apply-templates mode="inline"/></strong></p>
+ </xsl:template>
+
+ <xsl:template mode="para" match="sekcja_swiatlo">
+ <empty-line/><empty-line/><empty-line/>
+ </xsl:template>
+
+ <xsl:template mode="para" match="sekcja_asterysk">
+ <empty-line/><p>*</p><empty-line/>
+ </xsl:template>
+
+ <xsl:template mode="para" match="separator_linia">
+ <empty-line/><p>————————</p><empty-line/>
+ </xsl:template>
+
+
+
<xsl:template mode="para" match="*"/>
<xsl:template mode="sections" match="*"/>
</xsl:stylesheet>
puts it here -->
<xsl:template match="motyw" mode="poem"/>
- <xsl:template mode="poem" match="wers_normalny">
+ <xsl:template mode="poem" match="wers_normalny|wers_cd|wers_wciety|wers_akap">
<v><xsl:apply-templates mode="inline"/></v>
</xsl:template>
</xsl:stylesheet>
xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"
xmlns:l="http://www.w3.org/1999/xlink">
- <!-- a nice epigraph section -->
- <xsl:template match="dedykacja|nota|nota_red" mode="sections">
- <epigraph>
- <xsl:apply-templates mode="para"/>
- <!-- XXX: <strofa/> can be here as well -->
- </epigraph>
- </xsl:template>
-
- <!-- main text is split by headings -->
- <xsl:template match="naglowek_rozdzial" mode="sections">
- <!--
-
- This one's tricky - we need to sections text into sections.
- In order to do that, all elements belonging to a single section
- must have something in common. We assume that this common factor
- is having the same number of following section headings.
-
- -->
-
- <section>
- <xsl:apply-templates mode="para"
- select="../*[count(following-sibling::naglowek_rozdzial)
- = count(current()/following-sibling::naglowek_rozdzial)]"/>
- </section>
- </xsl:template>
+ <xsl:template name="section">
+ <!-- All the <_section> are in the end. -->
+ <xsl:if test="count(*) > count(_section)">
+ <section>
+ <xsl:choose>
+ <xsl:when test="(local-name() = 'liryka_l' or local-name() = 'liryka_lp')
+ and count(_section) = 0">
+ <poem>
+ <xsl:apply-templates mode="para" />
+ </poem>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates mode="para" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </section>
+ </xsl:if>
+
+ <!-- Now, recursively, all the _section tags. -->
+ <xsl:apply-templates mode="section" select="_section" />
+ </xsl:template>
+
+ <xsl:template match="_section" mode="para" />
+ <xsl:template match="_section" mode="section" >
+ <section>
+ <xsl:call-template name="section" />
+ </section>
+ </xsl:template>
<!-- actual headings -->
- <xsl:template match="naglowek_rozdzial" mode="para">
+ <xsl:template match="naglowek_czesc|naglowek_rozdzial|naglowek_podrozdzial|naglowek_akt|naglowek_scena" mode="para">
<title><p><xsl:apply-templates mode="inline"/></p></title>
</xsl:template>
</xsl:stylesheet>
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from librarian.book2anything import Book2Anything, Option
+from librarian.parser import WLDocument
class Book2Txt(Book2Anything):
Option('-w', '--wrap', action='store', type='int', dest='wrapping', default=0,
help='set line wrap column')
]
+ transform = WLDocument.as_text
if __name__ == '__main__':
maintainer_email='radoslaw.czajka@nowoczesnapolska.org.pl',
url='http://github.com/fnp/librarian',
packages=['librarian'],
- package_data={'librarian': ['xslt/*.xslt', 'epub/*', 'mobi/*', 'pdf/*', 'fonts/*', 'res/*'] +
+ package_data={'librarian': ['xslt/*.xslt', 'epub/*', 'mobi/*', 'pdf/*', 'fb2/*', 'fonts/*', 'res/*'] +
whole_tree(os.path.join(os.path.dirname(__file__), 'librarian'), 'font-optimizer')},
include_package_data=True,
install_requires=['lxml>=2.2'],
'scripts/book2epub',
'scripts/book2mobi',
'scripts/book2pdf',
+ 'scripts/book2fb2',
'scripts/book2partner',
'scripts/book2cover',
'scripts/bookfragments',
--- /dev/null
+<?xml version='1.0' encoding='utf-8'?>
+<!--
+ Example file for testing a converter.
+ Just run it through and see if everything looks ok.
+-->
+<utwor>
+<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="LINK DO PLATFORMY REDAKCYJNEJ">
+<dc:creator xml:lang="pl">Utworu, Autor</dc:creator>
+<dc:title xml:lang="pl">Tytuł w DC</dc:title>
+<dc:contributor.translator xml:lang="pl">Utworu, Tłumacz</dc:contributor.translator>
+<dc:contributor.editor xml:lang="pl">Literacki, Redaktor</dc:contributor.editor>
+<dc:contributor.technical_editor xml:lang="pl">Techniczny, Redaktor</dc:contributor.technical_editor>
+<dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+<dc:subject.period xml:lang="pl">period</dc:subject.period>
+<dc:subject.type xml:lang="pl">type</dc:subject.type>
+<dc:subject.genre xml:lang="pl">genre</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/test1</dc:identifier.url>
+<dc:source xml:lang="pl">source</dc:source>
+<dc:rights xml:lang="pl">Domena publiczna</dc:rights>
+<dc:date.pd xml:lang="pl">1500</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">2000</dc:date>
+<dc:language xml:lang="pl">pol</dc:language>
+</rdf:Description>
+</rdf:RDF>
+<liryka_l>
+
+<nota_red><akap>nota_red</akap></nota_red>
+
+<autor_utworu>autor_utworu</autor_utworu>
+<dzielo_nadrzedne>dzielo_nadrzedne</dzielo_nadrzedne>
+<nazwa_utworu>nazwa_utworu</nazwa_utworu>
+<podtytul>podtytul</podtytul>
+
+<akap>[powyżej:
+nota_red (nie pojawia się w tekście, może być podana osobno),
+autor_utworu, dzielo_nadrzedne, nazwa_utworu, podtytul, tłumacz (z DC)]</akap>
+
+<akap>[Noty: nota/akap, dedykacja/akap, motto/akap, motto_podpis]</akap>
+
+
+<nota><akap>nota/akap</akap></nota>
+<dedykacja><akap>dedykacja/akap</akap></dedykacja>
+<motto><akap>motto/akap</akap></motto>
+<motto_podpis>motto_podpis</motto_podpis>
+
+<akap>[Początek dramatu: lista_osob, naglowek_listy, lista_osoba, miejsce_czas]</akap>
+
+<lista_osob>
+ <naglowek_listy>lista_osob/naglowek_listy</naglowek_listy>
+ <lista_osoba>lista_osob/lista_osoba</lista_osoba>
+ <lista_osoba>lista_osob/lista_osoba</lista_osoba>
+</lista_osob>
+<miejsce_czas>miejsce_czas</miejsce_czas>
+
+<akap>[naglowek_czesc, naglowek_rozdzial, naglowek_podrozdzial, srodtytul]</akap>
+
+<naglowek_czesc>naglowek_czesc</naglowek_czesc>
+<naglowek_rozdzial>naglowek_rozdzial</naglowek_rozdzial>
+<naglowek_podrozdzial>naglowek_podrozdzial</naglowek_podrozdzial>
+<srodtytul>srodtytul</srodtytul>
+
+<akap>[akap, akap_cd, akap_dialog, motyw]</akap>
+
+<akap>akap<begin id="a"/><motyw>motyw</motyw></akap>
+<akap_cd>akap_cd</akap_cd>
+<akap_dialog>akap_dialog<end id="a"/></akap_dialog>
+
+<akap>[strofa, wers_akap, wers_wciety,typ=1-6, wers_cd, zastepnik_wersu]</akap>
+
+<strofa>strofa/
+<wers_akap>wers_akap</wers_akap>/
+<wers_wciety typ="1">wers_wciety@typ=1</wers_wciety>/
+<wers_wciety typ="2">wers_wciety@typ=2</wers_wciety>/
+<wers_wciety typ="3">wers_wciety@typ=3</wers_wciety>
+</strofa><strofa>
+<wers_wciety typ="4">wers_wciety@typ=4</wers_wciety>/
+<wers_wciety typ="5">wers_wciety@typ=5</wers_wciety>/
+<wers_wciety typ="6">wers_wciety@typ=6</wers_wciety>/
+<wers_cd>wers_cd</wers_cd>/
+<zastepnik_wersu />. . . . . . . . . . . . . . . .
+</strofa>
+
+<akap>[dlugi_cytat/akap]</akap>
+
+<dlugi_cytat><akap>Cytowany akapit powinien wyglądać jak cytowany akapit.
+Znaczy, może mieć jakieś dodatkowe wcięcie, jakiś rodzaj wyróżnienia czy coś.</akap></dlugi_cytat>
+
+<akap>[poezja_cyt/strofa]</akap>
+
+<poezja_cyt><strofa>To jest poezja/
+cytowana/
+ma być porządnie/
+wyrównana</strofa></poezja_cyt>
+
+<akap>[naglowek_akt, naglowek_scena]</akap>
+
+<naglowek_akt>naglowek_akt</naglowek_akt>
+<naglowek_scena>naglowek_scena</naglowek_scena>
+
+<akap>[Kwestia: naglowek_osoba, kwestia, didask_tekst, didaskalia, strofa, akap]</akap>
+
+<naglowek_osoba>naglowek_osoba</naglowek_osoba>
+
+<kwestia>
+<didask_tekst>didask_tekst</didask_tekst>
+<didaskalia>didaskalia</didaskalia>
+<strofa>Strofa w dramacie/
+jak amen w pacie/
+rzu.</strofa>
+<akap>Powyższy kawałek wiersza jest najzupełniej bez sensu i tak naprawdę wcale nie trzyma rytmu ani rymu. Być może należy skoncentrować się na dramacie prozą, jak ta tutaj niniejsza wypowiedź. </akap></kwestia>
+
+<akap>[didaskalia, osoba]</akap>
+
+<didaskalia>odezwał się <osoba>autor</osoba>.</didaskalia>
+
+<akap>[Wyróżnienia: tytul_dziela, tytul_dziela@typ=1, wyroznienie, slowo_obce]</akap>
+
+<akap>
+<tytul_dziela>tytul_dziela</tytul_dziela>,
+<tytul_dziela typ="1">tytul_dziela@typ=1</tytul_dziela>,
+<wyroznienie>wyroznienie</wyroznienie>,
+<slowo_obce>slowo_obce</slowo_obce>
+</akap>
+
+<akap>[Przypisy: pa, pt, pr, pe]</akap>
+
+<akap>
+<pa>pa - - - przypis <wyroznienie>autorski</wyroznienie></pa>
+<pt>pt - - - przypis tłumacza</pt>
+<pr>pr - - - przypis redakcyjny</pr>
+<pe>pe - - - przypis edytorski</pe>
+</akap>
+
+<akap>[Separatory]</akap>
+
+<akap>[sekcja_swiatlo:]</akap>
+
+<sekcja_swiatlo></sekcja_swiatlo>
+
+<akap>[sekcja_asterysk:]</akap>
+
+<sekcja_asterysk></sekcja_asterysk>
+
+<akap>[separator_linia:]</akap>
+
+<separator_linia></separator_linia>
+
+
+
+<akap>[Komentarze: uwaga, extra]</akap>
+<uwaga>uwaga</uwaga>
+<extra>extra</extra>
+
+<akap>[Nieużywane]</akap>
+
+<wyp_osoba>wyp_osoba</wyp_osoba>
+<wywiad_pyt><akap>wywiad_pyt/akap</akap></wywiad_pyt>
+<wywiad_odp><akap>wywiad_odp/akap</akap></wywiad_odp>
+<mat>mat</mat>
+<www>www</www>
+
+</liryka_l>
+</utwor>