diff --git a/IPython/nbconvert/exporters/exporter.py b/IPython/nbconvert/exporters/exporter.py
index af9da29..f15cb9c 100755
--- a/IPython/nbconvert/exporters/exporter.py
+++ b/IPython/nbconvert/exporters/exporter.py
@@ -68,6 +68,7 @@ default_filters = {
'strip_math_space': filters.strip_math_space,
'wrap_text': filters.wrap_text,
'escape_latex': filters.escape_latex,
+ 'parse_citation': filters.parse_citation
}
#-----------------------------------------------------------------------------
diff --git a/IPython/nbconvert/filters/__init__.py b/IPython/nbconvert/filters/__init__.py
index 9751c94..87dd748 100755
--- a/IPython/nbconvert/filters/__init__.py
+++ b/IPython/nbconvert/filters/__init__.py
@@ -3,4 +3,5 @@ from .datatypefilter import *
from .highlight import *
from .latex import *
from .markdown import *
-from .strings import *
\ No newline at end of file
+from .strings import *
+from .citation import *
\ No newline at end of file
diff --git a/IPython/nbconvert/filters/citation.py b/IPython/nbconvert/filters/citation.py
new file mode 100644
index 0000000..e03cc25
--- /dev/null
+++ b/IPython/nbconvert/filters/citation.py
@@ -0,0 +1,70 @@
+"""Citation handling for LaTeX output."""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+
+
+__all__ = ['parse_citation']
+
+
+def parse_citation(s):
+ """Parse citations in Markdown cells.
+
+ This looks for HTML tags having a data attribute names `data-cite`
+ and replaces it by the call to LaTeX cite command. The tranformation
+ looks like this:
+
+ `(Granger, 2013)`
+
+ Becomes
+
+ `\\cite{granger}`
+
+ Any HTML tag can be used, which allows the citations to be formatted
+ in HTML in any manner.
+ """
+ try:
+ from lxml import html
+ except ImportError:
+ return s
+
+ tree = html.fragment_fromstring(s, create_parent='div')
+ _process_node_cite(tree)
+ s = html.tostring(tree)
+ s = s.lstrip('
')
+ s = s.rstrip('
')
+ return s
+
+
+def _process_node_cite(node):
+ """Do the citation replacement as we walk the lxml tree."""
+
+ def _get(o, name):
+ value = getattr(o, name)
+ return '' if value is None else value
+
+ if 'data-cite' in node.attrib:
+ cite = '\cite{%(ref)s}' % {'ref': node.attrib['data-cite']}
+ prev = node.getprevious()
+ if prev is not None:
+ prev.tail = _get(prev, 'tail') + cite + _get(node, 'tail')
+ else:
+ parent = node.getparent()
+ if parent is not None:
+ parent.text = _get(parent, 'text') + cite + _get(node, 'tail')
+ try:
+ node.getparent().remove(node)
+ except AttributeError:
+ pass
+ else:
+ for child in node:
+ _process_node_cite(child)
diff --git a/IPython/nbconvert/filters/tests/test_citation.py b/IPython/nbconvert/filters/tests/test_citation.py
new file mode 100644
index 0000000..7bb033b
--- /dev/null
+++ b/IPython/nbconvert/filters/tests/test_citation.py
@@ -0,0 +1,54 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from ..citation import parse_citation
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+test_md = """
+# My Heading
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
+porttitor scelerisque ac id diam Granger. Mauris elit
+velit, lobortis sed interdum at, vestibulum vitae libero Perez.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit
+Thomas. Quisque iaculis ligula ut ipsum mattis viverra.
+
+* One Jonathan.
+* Two Matthias.
+* Three Paul.
+"""
+
+test_md_parsed = """
+# My Heading
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
+porttitor scelerisque ac id diam \cite{granger}. Mauris elit
+velit, lobortis sed interdum at, vestibulum vitae libero \cite{fperez}.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit
+\cite{takluyver}. Quisque iaculis ligula ut ipsum mattis viverra.
+
+* One \cite{jdfreder}.
+* Two \cite{carreau}.
+* Three \cite{ivanov}.
+"""
+
+def test_parse_citation():
+ """Are citations parsed properly?"""
+ try:
+ import lxml
+ except ImportError:
+ assert test_md == parse_citation(test_md)
+ else:
+ assert test_md_parsed == parse_citation(test_md)
diff --git a/IPython/nbconvert/templates/latex/latex_basic.tplx b/IPython/nbconvert/templates/latex/latex_basic.tplx
index ff3303b..d8d6e68 100644
--- a/IPython/nbconvert/templates/latex/latex_basic.tplx
+++ b/IPython/nbconvert/templates/latex/latex_basic.tplx
@@ -103,11 +103,11 @@ it introduces a new line
((* endblock stream *))
((* block markdowncell scoped *))
-((( cell.source | markdown2latex )))
+((( cell.source | parse_citation | markdown2latex )))
((* endblock markdowncell *))
((* block headingcell scoped -*))
-((( ('#' * cell.level + cell.source) | replace('\n', ' ') | markdown2latex )))
+((( ('#' * cell.level + cell.source) | replace('\n', ' ') | parse_citation | markdown2latex )))
((* endblock headingcell *))
((* block rawcell scoped *))
@@ -127,6 +127,10 @@ unknown type ((( cell.type )))
((( super() )))
((* block bodyEnd *))
+
+((* block bibliography *))
+((* endblock bibliography *))
+
\end{document}
((* endblock bodyEnd *))
((* endblock body *))
diff --git a/IPython/nbconvert/templates/latex/sphinx.tplx b/IPython/nbconvert/templates/latex/sphinx.tplx
index ee59ad8..80ee3fb 100644
--- a/IPython/nbconvert/templates/latex/sphinx.tplx
+++ b/IPython/nbconvert/templates/latex/sphinx.tplx
@@ -192,6 +192,9 @@ Note: For best display, use latex syntax highlighting. =))
\renewcommand{\indexname}{Index}
\printindex
+ ((* block bibliography *))
+ ((* endblock bibliography *))
+
% End of document
\end{document}
((* endblock bodyEnd *))
@@ -229,7 +232,7 @@ Note: For best display, use latex syntax highlighting. =))
in IPYNB file titles) do not make their way into latex. Sometimes this
causes latex to barf. =))
((*- endif -*))
- {((( cell.source | markdown2latex )))}
+ {((( cell.source | parse_citation | markdown2latex )))}
((*- endblock headingcell *))
%==============================================================================
@@ -239,7 +242,7 @@ Note: For best display, use latex syntax highlighting. =))
% called since we know we want latex output.
%==============================================================================
((*- block markdowncell scoped-*))
-((( cell.source | markdown2latex )))
+((( cell.source | parse_citation | markdown2latex )))
((*- endblock markdowncell -*))
%==============================================================================