Skip to content

Commit

Permalink
Add HTML rendering for internal links.
Browse files Browse the repository at this point in the history
This includes rendering for categories, interwiki links and media files.

Also: add a full test: parsing an article from the French Wikipedia. To
run it, launch "python parser.py" and look at article.htm
  • Loading branch information
peter17 committed Jul 30, 2011
1 parent e2b6293 commit 4f58bb3
Show file tree
Hide file tree
Showing 18 changed files with 427 additions and 75 deletions.
102 changes: 102 additions & 0 deletions article.htm
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head><title>Test!</title></head><body>
<p>Contenu soumis à la licence CC-BY-SA 3.0 (<a href="http://creativecommons.org/licenses/by-sa/3.0/deed.fr)">http://creativecommons.org/licenses/by-sa/3.0/deed.fr)</a> Source : Article Berceuse de Wikipédia en français (<a href="http://fr.wikipedia.org/wiki/Berceuse).">http://fr.wikipedia.org/wiki/Berceuse).</a> </p>
<p><a href="Template:Voir homonymes">Template:Voir homonymes</a><a href="Template:ébauche">Template:ébauche</a><div class="thumbnail"><img src="William-Adolphe Bouguereau (1825-1905) - Lullaby (1875).jpg" style="float:right;width:250px;" /><p><em>La Berceuse</em> (œuvre de <a href="William Bouguereau">William Bouguereau</a> - <a href="Template:XIXe siècle">Template:XIXe siècle</a>)</p></div>
Une <strong>berceuse</strong> est une <a href="chanson">chanson</a> douce destinée à aider les <a href="enfant">enfant</a>s à <a href="Sommeil">s'endormir</a>. Il existe des berceuses chantées dans toutes les langues du monde.</p>
<h2>Berceuses françaises</h2>
<p>Les berceuses françaises traditionnelles les plus connues sont « Dodo, l'enfant do / l'enfant dormira peut-être » et « Fais dodo, Colas mon p'tit frère ». Une berceuse du Nord, « <a href="P'tit Quinquin (chanson)">P'tit Quinquin</a> » est également devenue célèbre.</p>
<h2>Dans la musique classique</h2>
<p>Les berceuses en musique classique obéissent souvent à une forme nommée aussi "berceuse" dans les langues étrangères. Elles sont généralement à trois <a href="Temps (solfège)">temps</a>, à <a href="tonalité">tonalité</a> simple, alternant des harmonies <a href="dominante">dominante</a> et <a href="Tonique (musique)">tonique</a>.</p>
<p><strong>Berceuses célèbres classées par compositeurs :</strong></p>
{| style="text-align:center; background: #f9f9f9; color: #000;font-size:90%; line-height:1.1em; float:right;clear:right; margin:1em 1.5em 1em 1em; width:300px; border: 1px solid #aaa; padding: 0.1em;" cellspacing="7"<p>! class="media audio" style="background-color:#ccf; line-height:3.1em" | Fichier audio|-|<span style="height:20px; width:100%; padding:4pt; padding-left:0.3em; line-height:2em;"><strong>[[Media:{{{filename|{{{nomfichier|{<a href="Template:2">Template:2</a>}}}}}}}|{{{title|{{{titre|{<a href="Template:1">Template:1</a>}}}}}}}]]</strong> <em>([[:Fichier:{{{filename|{{{nomfichier|{<a href="Template:2">Template:2</a>}}}}}}}|info]])</em><br />&lt;small&gt;{{{suitetexte|{<a href="Template:description">Template:description</a>}}}}&lt;/small&gt;&lt;center&gt;[[Fichier:{{{filename|{{{nomfichier|{<a href="Template:2">Template:2</a>}}}}}}}|noicon]]&lt;/center&gt;</span><br /><span style="height:20px; width:100%; padding-left:0.3em;"><span><img src="Circle question mark.png" style="width:14px;" /> <em><a href="Aide:Écouter des sons ogg">Des problèmes pour écouter le fichier ?</a></em></span>|}</span></p>
<ul>
<li> <a href="Jean-Sébastien Bach">Bach</a><ul>
<li> Menuet pour clavier Nº1 en sol majeur (Carnets intimes d'Anna Magdalena II/1), BWV Anh. 114</li>
<li> « <a href="Jésus que ma joie demeure">Jésus, que ma joie demeure</a> », (<a href="Liste des cantates de Johann Sebastian Bach">Cantate Nº147</a>), BWV 147</li>
<li> Suite pour orchestre n°3 en re majeur, BWV 1068</li>
</ul>
</li>
<li> <a href="Ludwig van Beethoven">Beethoven</a><ul>
<li> « <a href="Sonate pour piano nº 14 de Beethoven">Sonate au clair de lune</a> » (Sonate pour piano n° 14 en do dièse mineur), op. 27/2</li>
<li> « <a href="La Lettre à Élise">Lettre à Élise</a> » (La Bagatelle en la mineur), WoO 59</li>
<li> « <a href="Sonate pour piano nº 8 de Beethoven">Sonate Pathétique</a> » (Sonate pour piano nº 8 de Beethoven), op. 13/2, Adagio cantabile</li>
</ul>
</li>
<li> <a href="Johannes Brahms">Brahms</a><ul>
<li> « Bonsoir et bonne nuit », berceuse ("Guten Abend, gut Nacht", Wiegenlied), op. 49/4</li>
</ul>
</li>
<li> <a href="Frédéric Chopin">Chopin</a><ul>
<li> « <a href="Berceuse (Chopin)">Berceuse en ré bémol majeur</a> », op.57</li>
</ul>
</li>
<li> <a href="Claude Debussy">Debussy</a><ul>
<li> « <a href="Suite Bergamasque">Clair de lune</a> » ("Suite Bergamasque" pour piano), L. 75/3</li>
</ul>
</li>
<li> <a href="Antonín Dvořák">Dvořák</a><ul>
<li> « <a href="Symphonie nº 9 de Dvořák">Sonate du Nouveau Monde</a> » (Symphonie n° 9 en mi mineur, B. 178), op. 95</li>
</ul>
</li>
<li> <a href="Gabriel Fauré">Fauré</a><ul>
<li> « <a href="Dolly (Fauré)">Berceuse</a> » (première pièce de la suite Dolly, pour piano à quatre mains), op. 56</li>
</ul>
</li>
<li> <a href="Felix Mendelssohn Bartholdy">Mendelssohn</a><ul>
<li> « <a href="Romances sans paroles (Mendelssohn)">Chant du printemps</a> » (Romances sans paroles pour piano), op. 62/6</li>
</ul>
</li>
<li> <a href="Wolfgang Amadeus Mozart">Mozart</a><ul>
<li> « <a href="Ah ! vous dirai-je, maman">Ah ! vous dirai-je, maman</a> » (Douze variations), K. 265</li>
<li> « <a href="Sonate pour piano n° 16 de Mozart">Sonate facile</a> » (Sonate pour piano nº 16 en do majeur), K. 545</li>
<li> « La Chasse » (Sonate pour piano n° 18 en ré majeur), K. 576, 3ème mouvement</li>
</ul>
</li>
<li> <a href="Johann Pachelbel">Pachelbel</a><ul>
<li> « <a href="Canon de Pachelbel">Canon en ré majeur sur une basse obstinée</a> »</li>
</ul>
</li>
<li> <a href="Robert Schumann">Schumann</a><ul>
<li> « <a href="Scènes d'enfants (Schumann)">Gens et pays étrangers</a> » (Les Scènes d'enfants, "Kinderszenen"), op. 15</li>
</ul>
</li>
<li> <a href="Bedřich Smetana">Smetana</a><ul>
<li> « <a href="Má Vlast">La Moldau</a> » (Second poèmes symphoniques de "Ma Patrie")</li>
</ul>
</li>
<li> <a href="Antonio Vivaldi">Vivaldi</a><ul>
<li> « <a href="Les Quatre Saisons">L'Hiver</a> » (Les Quatre Saisons, Opus 8/4)</li>
</ul>
</li>
</ul>
<p>Les plus connues sont la berceuse « <em>Bonsoir et bonne nuit</em> » de Brahms et la « <em>Berceuse en ré bémol majeur</em> » de <a href="Chopin">Chopin</a>. Des compositeurs comme <a href="Franz Liszt">Franz Liszt</a>, <a href="Gabriel Fauré">Gabriel Fauré</a>, <a href="Maurice Ravel">Maurice Ravel</a>, <a href="Mili Balakirev">Mili Balakirev</a>, <a href="Igor Stravinski">Igor Stravinski</a> (<em><a href="Berceuses du chat">Berceuses du chat</a></em>) et <a href="George Gershwin">George Gershwin</a> ont aussi écrit des berceuses.</p>
<h2>Dans la musique populaire</h2>
<h3>Dans la chanson française</h3>
<ul>
<li> <a href="Bénabar">Bénabar</a> : « La berceuse », de l'album <em><a href="Reprise des négociations">Reprise des négociations</a></em>, 2005</li>
<li> <a href="Henri Salvador">Henri Salvador</a> : « Une chanson douce » (Le Loup, la Biche et le Chevalier), de l'album <em>Rigolo</em>, 1968</li>
</ul>
<h3>Dans la musique pop</h3>
<ul>
<li> <a href="Beatles">Beatles</a> : « <a href="Good Night (chanson)">Good Night</a> », de l'<em><a href="The Beatles (album)">album blanc</a></em>, 1968</li>
</ul>
<h3>Dans le jazz</h3>
<ul>
<li> <a href="Baden Powell de Aquino">Baden Powell</a> : « Berceuse a Jussara », de l'album <em>Le Monde Musical</em>, 1964</li>
<li> <a href="Henri Salvador">Henri Salvador</a> : « Une chanson douce » (Le Loup, la Biche et le Chevalier), de l'album <em>Rigolo</em>, 1968</li>
</ul>
<h2> Voir aussi </h2>
<ul>
<li> <a href="Lullaby">Lullaby</a> dans la section anglaise et italienne où il y a une description d'une bonne partie des berceuses européennes.</li>
</ul>
<p><a href="Template:Wiktionnaire">Template:Wiktionnaire</a></p>
<h3>Bibliographie</h3>
<ul>
<li>Claudine Antoine, <em>La Berceuse populaire dans le contexte de la petite enfance</em>, Université Strasbourg 2, 1988, 2 vol., 358 + 333 p. (thèse de Musiocologie)</li>
<li>Marina Altmann de Litvan (dir.), <em>La berceuse : jeux d'amour et de magie</em>, Erès, Ramonville Saint-Agne, 2008, 151 p. <a href="Template:ISBN">Template:ISBN</a></li>
</ul>
<p><a href="Template:portail musique">Template:portail musique</a></p>
<p>Categories: <a href="Berceuse">Berceuse</a>, <a href="Musique par genre">Musique par genre</a>, <a href="Musique traditionnelle">Musique traditionnelle</a></p>
<p>Interwiki: <a href="http://ar.wikipedia.org/wiki/تهويدة">تهويدة</a>, <a href="http://az.wikipedia.org/wiki/Layla">Layla</a>, <a href="http://br.wikipedia.org/wiki/Luskellerez">Luskellerez</a>, <a href="http://ca.wikipedia.org/wiki/Cançó de bressol">Cançó de bressol</a>, <a href="http://cs.wikipedia.org/wiki/Ukolébavka">Ukolébavka</a>, <a href="http://da.wikipedia.org/wiki/Berceuse">Berceuse</a>, <a href="http://de.wikipedia.org/wiki/Wiegenlied">Wiegenlied</a>, <a href="http://en.wikipedia.org/wiki/Lullaby">Lullaby</a>, <a href="http://eo.wikipedia.org/wiki/Lulkanto">Lulkanto</a>, <a href="http://es.wikipedia.org/wiki/Nana (canción de cuna)">Nana (canción de cuna)</a></p>
</body></html>
133 changes: 127 additions & 6 deletions html.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from constants import html_entities
from pijnu.library.node import Nil, Nodes
from mediawiki_parser import wikitextParser
from mutagen import Metadata

def toolset(allowed_tags, allowed_autoclose_tags, allowed_attributes):
def toolset(allowed_tags, allowed_autoclose_tags, allowed_attributes, interwiki, namespaces):
tags_stack = []

external_autonumber = []
Expand All @@ -11,6 +12,33 @@ def toolset(allowed_tags, allowed_autoclose_tags, allowed_attributes):
is rendered as: "<a href="...">[1]</a> <a href="...">[2]</a>
"""

category_links = []
""" This will contain the links to the categories of the article. """
interwiki_links = []
""" This will contain the links to the foreign versions of the article. """

for namespace, value in namespaces.iteritems():
assert value in range(16), "Incorrect value for namespaces"
"""
Predefined namespaces; source: includes/Defines.php of MediaWiki-1.17.0
'NS_MAIN', 0
'NS_TALK', 1
'NS_USER', 2
'NS_USER_TALK', 3
'NS_PROJECT', 4
'NS_PROJECT_TALK', 5
'NS_FILE', 6
'NS_FILE_TALK', 7
'NS_MEDIAWIKI', 8
'NS_MEDIAWIKI_TALK', 9
'NS_TEMPLATE', 10
'NS_TEMPLATE_TALK', 11
'NS_HELP', 12
'NS_HELP_TALK', 13
'NS_CATEGORY', 14
'NS_CATEGORY_TALK', 15
"""

def balance_tags(tag=None):
i = 0
if tag is not None:
Expand Down Expand Up @@ -48,11 +76,18 @@ def render_raw_text(node):
node.value = "%s" % node.leaf()

def render_paragraph(node):
node.value = '<p>' + content(node) + '</p>\n'
value = content(node)
if value != '':
node.value = '<p>' + value + '</p>\n'

def render_body(node):
from apostrophes import parseAllQuotes
node.value = '<body>\n' + parseAllQuotes(content(node)) + '</body>'
metadata = ''
if category_links != []:
metadata += '<p>Categories: ' + ', '.join(category_links) + '</p>\n'
if interwiki_links != []:
metadata += '<p>Interwiki: ' + ', '.join(interwiki_links) + '</p>\n'
node.value = '<body>\n' + parseAllQuotes(content(node)) + metadata + '</body>'

def render_entity(node):
value = '%s' % node.leaf()
Expand Down Expand Up @@ -269,9 +304,91 @@ def render_external_link(node):
text = node.value[1].leaf()
node.value = '<a href="%s">%s</a>' % (node.value[0].leaf(), text)

def render_interwiki(prefix, page):
link = '<a href="%s">%s</a>' % (interwiki[prefix] + page, page)
if link not in interwiki_links:
interwiki_links.append(link)

def render_category(category_name):
link = '<a href="%s">%s</a>' % (category_name, category_name)
if link not in category_links:
category_links.append(link)

def render_file(file_name, arguments):
""" This implements a basic handling of images.
MediaWiki supports much more parameters (see includes/Parser.php).
"""
style = ''
thumbnail = False
legend = ''
if arguments != []:
parameters = arguments[0].value
for parameter in parameters:
parameter = '%s' % parameter.leaf()
if parameter[-2:] == 'px':
size = parameter[0:-2]
if 'x' in size:
size_x, size_y = size.split('x', 1)
try:
size_x = int(size_x)
size_y = int(size_y)
style += 'width:%spx;height:%spx' % (size_x, size_y)
except:
legend = parameter
else:
try:
size_x = int(size)
style += 'width:%spx;' % size_x
except:
legend = parameter
elif parameter in ['left', 'right', 'center']:
style += 'float:%s;' % parameter
elif parameter in ['thumb', 'thumbnail']:
thumbnail = True
elif parameter == 'border':
style += 'border:1px solid grey'
else:
legend = parameter
result = '<img src="%s" style="%s" />' % (file_name, style)
if thumbnail:
result = '<div class="thumbnail">%s<p>%s</p></div>\n' % (result, legend)
return result

def render_internal_link(node):
force_link = False
url = ''
page_name = node.value.pop(0).value
if page_name[0] == ':':
force_link = True
page_name = page_name[1:]
if ':' in page_name:
namespace, page_name = page_name.split(':', 1)
if namespace in interwiki and not force_link:
render_interwiki(namespace, page_name)
node.value = ''
return
elif namespace in interwiki:
url = interwiki[namespace]
namespace = ''
if namespace in namespaces:
if namespaces[namespace] == 6 and not force_link: # File
node.value = render_file(page_name, node.value)
return
elif namespaces[namespace] == 14 and not force_link: # Category
render_category(page_name)
node.value = ''
return
if namespace:
page_name = namespace + ':' + page_name
if len(node.value) == 0:
text = page_name
else:
text = '|'.join('%s' % item.leaf() for item in node.value[0])
node.value = '<a href="%s%s">%s</a>' % (url, page_name, text)

return locals()

def make_parser(allowed_tags=[], allowed_autoclose_tags=[], allowed_attributes=[]):
def make_parser(allowed_tags=[], allowed_autoclose_tags=[], allowed_attributes=[], interwiki={}, namespaces={}):
"""Constructs the parser for the HTML backend.
:arg allowed_tags: List of the HTML tags that should be allowed in the parsed wikitext.
Expand All @@ -281,7 +398,11 @@ def make_parser(allowed_tags=[], allowed_autoclose_tags=[], allowed_attributes=[
parsed wikitext. All the other self-closing tags will be output as &lt;tag /&gt;
:arg allowed_attributes: List of the HTML attributes that should be allowed in the parsed
tags (e.g.: class="", style=""). All the other attributes (e.g.: onclick="") will
be removed.
be removed.
:arg interwiki: List of the allowed interwiki prefixes (en, fr, es, commons, etc.)
:arg namespaces: List of the namespaces of the wiki (File, Category, Template, etc.),
including the localized version of those strings (Modele, Categorie, etc.),
associated to the corresponding namespace code.
"""
tools = toolset(allowed_tags, allowed_autoclose_tags, allowed_attributes)
tools = toolset(allowed_tags, allowed_autoclose_tags, allowed_attributes, interwiki, namespaces)
return wikitextParser.make_parser(tools)
4 changes: 2 additions & 2 deletions mediawiki.pijnu
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,15 @@ def replace_by_space(node):
# TODO: allow IPv6 addresses (http://[::1]/etc)
address : (!(QUOTE/R_BRACKET) [\x21..\xff])+ : liftValue
url : protocol address : join
inline_url : url{1} : render_url

# Links

allowed_in_link : (!(R_BRACKET/PIPE) ESC_CHAR)+ : restore join
link_text : (clean_inline / allowed_in_link)* : liftValue
link_argument : PIPE link_text : liftValue
link_arguments : link_argument*
internal_link : LINK_BEGIN page_name link_arguments LINK_END : liftValue
internal_link : LINK_BEGIN page_name link_arguments LINK_END : render_internal_link
optional_link_text : SPACETAB+ link_text : liftValue
external_link : L_BRACKET url optional_link_text? R_BRACKET : render_external_link
link : internal_link / external_link
Expand All @@ -137,7 +138,6 @@ def replace_by_space(node):

# Text types

inline_url : url{1} : render_url
styled_text : link / inline_url / html_comment / tag / entity
not_styled_text : preformatted / nowiki
allowed_char : ESC_CHAR{1} : restore liftValue
Expand Down
Loading

0 comments on commit 4f58bb3

Please sign in to comment.