diff --git a/IPython/nbconvert/filters/citation.py b/IPython/nbconvert/filters/citation.py
index 1442d55..2ee7e13 100644
--- a/IPython/nbconvert/filters/citation.py
+++ b/IPython/nbconvert/filters/citation.py
@@ -9,9 +9,13 @@
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
-# Code
+# Imports
#-----------------------------------------------------------------------------
+from HTMLParser import HTMLParser
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
__all__ = ['citation2latex']
@@ -32,41 +36,72 @@ def citation2latex(s):
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, encoding='unicode')
- if s.endswith(''):
- s = s[:-6]
- if s.startswith('
'):
- s = s[5:]
- return s
+ parser = CitationParser()
+ parser.feed(s)
+ parser.close()
+ outtext = u''
+ startpos = 0
+ for citation in parser.citelist:
+ outtext += s[startpos:citation[1]]
+ outtext += '\\cite{%s}'%citation[0]
+ startpos = citation[2]
+ outtext += s[startpos:]
+ return outtext
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+class CitationParser(HTMLParser):
+ """Citation Parser
-def _process_node_cite(node):
- """Do the citation replacement as we walk the lxml tree."""
+ Replaces html tags with data-cite attribute with respective latex \\cite.
- def _get(o, name):
- value = getattr(o, name, None)
- return '' if value is None else value
+ Inherites from HTMLParser, overrides:
+ - handle_starttag
+ - handle_endtag
+ """
+ # number of open tags
+ opentags = None
+ # list of found citations
+ citelist = None
+ # active citation tag
+ citetag = None
+
+ def __init__(self):
+ self.citelist = []
+ self.opentags = 0
+ HTMLParser.__init__(self)
- 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)
+ def get_offset(self):
+ # Compute startposition in source
+ lin, offset = self.getpos()
+ pos = 0
+ for i in range(lin-1):
+ pos = self.data.find('\n',pos) + 1
+ return pos + offset
+
+ def handle_starttag(self, tag, attrs):
+ # for each tag check if attributes are present and if no citation is active
+ if self.opentags == 0 and len(attrs)>0:
+ for atr, data in attrs:
+ if atr.lower() == 'data-cite':
+ self.citetag = tag
+ self.opentags = 1
+ self.citelist.append([data, self.get_offset()])
+ return
+
+ if tag == self.citetag:
+ # found an open citation tag but not the starting one
+ self.opentags += 1
+
+ def handle_endtag(self, tag):
+ if tag == self.citetag:
+ # found citation tag check if starting one
+ if self.opentags == 1:
+ pos = self.get_offset()
+ self.citelist[-1].append(pos+len(tag)+3)
+ self.opentags -= 1
+
+ def feed(self, data):
+ self.data = data
+ HTMLParser.feed(self, data)