From bd185087dc899b6157f821fdd29561caffcc4682 Mon Sep 17 00:00:00 2001 From: Artem Yunusov Date: Thu, 31 Jul 2008 03:06:39 +0500 Subject: A lot of bug fixes, added ElementTree support for extensions, some new tests. --- markdown.py | 154 +++++++++++++++------------ mdx_footnotes.py | 117 +++++++++++--------- mdx_rss.py | 102 +++++++++--------- tests/extensions-x-footnotes/footnote.html | 82 +++++++------- tests/markdown-test/angle-links-and-img.html | 7 ++ tests/markdown-test/angle-links-and-img.txt | 4 + tests/misc/blockquote-below-paragraph.html | 6 ++ tests/misc/blockquote-below-paragraph.txt | 3 + tests/misc/html-comments.html | 2 + tests/misc/html-comments.txt | 2 + 10 files changed, 263 insertions(+), 216 deletions(-) mode change 100644 => 100755 markdown.py create mode 100755 tests/markdown-test/angle-links-and-img.html create mode 100755 tests/markdown-test/angle-links-and-img.txt create mode 100755 tests/misc/blockquote-below-paragraph.html create mode 100755 tests/misc/blockquote-below-paragraph.txt create mode 100755 tests/misc/html-comments.html create mode 100755 tests/misc/html-comments.txt diff --git a/markdown.py b/markdown.py old mode 100644 new mode 100755 index e4235ff..3891ac3 --- a/markdown.py +++ b/markdown.py @@ -62,26 +62,32 @@ def message(level, text): def isstr(s): return isinstance(s, unicode) or isinstance(s, str) -try: - # Python 2.5+ - import xml.etree.cElementTree as etree -except ImportError: +def importETree(): + """ Importing best variant of ElementTree + and returning module object """ + try: # Python 2.5+ - import xml.etree.ElementTree as etree + import xml.etree.cElementTree as etree except ImportError: try: - # normal cElementTree install - import cElementTree as etree + # Python 2.5+ + import xml.etree.ElementTree as etree except ImportError: try: - # normal ElementTree install - import elementtree.ElementTree as etree + # normal cElementTree install + import cElementTree as etree except ImportError: - message(CRITICAL, - "Failed to import ElementTree from any known place") - sys.exit(1) + try: + # normal ElementTree install + import elementtree.ElementTree as etree + except ImportError: + message(CRITICAL, + "Failed to import ElementTree from any known place") + sys.exit(1) + return etree +etree = importETree() def indentETree(elem, level=0): @@ -173,8 +179,8 @@ def isBlockLevel (tag): def codepoint2name(code): - """ Returns entity defenition by code, or code - if there is no such entity defenition""" + """ Returns entity definition by code, or code + if there is no such entity definition""" entity = htmlentitydefs.codepoint2name.get(code) if entity: return "%s%s;" % (AND_SUBSTITUTE, entity) @@ -351,7 +357,7 @@ class HeaderPreprocessor(Preprocessor): """ Replace underlined headers with hashed headers to avoid - the nead for lookahead later. + the need for lookahead later. """ def run (self, lines): @@ -394,7 +400,7 @@ class LinePreprocessor(Preprocessor): blockquote_re = re.compile(r'^(> )+') def run (self, lines): - """ Find a store HR lines. """ + """ Find and replace HR lines. """ for i in range(len(lines)): prefix = '' @@ -467,9 +473,8 @@ expression and needs support the following methods: pattern.getCompiledRegExp() - returns a regular expression - pattern.handleMatch(m, doc) - takes a match object and returns - a NanoDom node (as a part of the provided - doc) or None + pattern.handleMatch(m) - takes a match object and returns + a ElementTree element or just plain text All of python markdown's built-in patterns subclass from Pattern, but you can add additional patterns that don't. @@ -521,16 +526,20 @@ else: #LINK_RE = NOIMG + BRK + r'\s*\(([^\)]*)\)' # [text](url) LINK_RE = NOIMG + BRK + \ -r'''\(\s*(((?:(?:\(.*?\))|[^\(\)]))*?|<\10*?>)\s*((['"])(.*)\12)?\)''' # [text](url) or [text]() +r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*?)\s*((['"])(.*)\12)?\)''' # [text](url) or [text]() +#r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*)\s*((['"])(.*)\12)?\)''' # [text](url) or [text]() + +#LINK_RE2 = NOIMG + BRK + \ +#r'''\(\s*(((?:(?:\(.*?\))|[^\(\)]))*?|<\10*?>)\s*((['"])(.*)\12)?\)''' # [text](url) or [text]() -IMAGE_LINK_RE = r'\!' + BRK + r'\s*\(([^\)]*)\)' # ![alttxt](http://x.com/) +IMAGE_LINK_RE = r'\!' + BRK + r'\s*\((<.*?>|([^\)]*))\)' # ![alttxt](http://x.com/) or ![alttxt]() REFERENCE_RE = NOIMG + BRK+ r'\s*\[([^\]]*)\]' # [Google][3] IMAGE_REFERENCE_RE = r'\!' + BRK + '\s*\[([^\]]*)\]' # ![alt text][2] NOT_STRONG_RE = r'( \* )' # stand-alone * or _ AUTOLINK_RE = r'<((?:f|ht)tps?://[^>]*)>' # AUTOMAIL_RE = r'<([^> \!]*@[^> ]*)>' # #HTML_RE = r'(\<[^\>]*\>)' # <...> -HTML_RE = r'(\<[a-zA-Z/][^\>]*\>)' # <...> +HTML_RE = r'(\<([a-zA-Z/][^\>]*?|\!--.*?--)\>)' # <...> ENTITY_RE = r'(&[\#a-zA-Z0-9]*;)' # & LINE_BREAK_RE = r' \n' # two spaces at end of line LINE_BREAK_2_RE = r' $' # two spaces at end of text @@ -559,15 +568,13 @@ class Pattern: def handleMatch(self, m): """ - Return a NanoDom element from the given match. Subclasses should + Return a ElementTree element from the given match. Subclasses should override this method. Keyword arguments: * m: A re match object containing a match of the pattern. - * doc: An instance of a NanoDom Document. - """ pass @@ -578,7 +585,7 @@ class Pattern: BasePattern = Pattern # for backward compatibility class SimpleTextPattern (Pattern): - """ Return a simple TextNode of group(2) of a Pattern. """ + """ Return a simple text of group(2) of a Pattern. """ def handleMatch(self, m): text = m.group(2) if text == INLINE_PLACEHOLDER_PREFIX: @@ -587,7 +594,7 @@ class SimpleTextPattern (Pattern): class SimpleTagPattern (Pattern): """ - Return NanoDom Element of type `tag` with a child TextNode of group(2) + Return element of type `tag` with a text attribute of group(3) of a Pattern. """ @@ -601,12 +608,12 @@ class SimpleTagPattern (Pattern): return el class SubstituteTagPattern (SimpleTagPattern): - """ Return a NanoDom ELement of type `tag` with no children. """ + """ Return a eLement of type `tag` with no children. """ def handleMatch (self, m): return etree.Element(self.tag) class BacktickPattern (Pattern): - """ Return a NanoDom `` Element containing the matching text. """ + """ Return a `` element containing the matching text. """ def __init__ (self, pattern): Pattern.__init__(self, pattern) self.tag = "code" @@ -619,7 +626,7 @@ class BacktickPattern (Pattern): class DoubleTagPattern (SimpleTagPattern): """ - Return a TextNode nested in tag2 nested in tag1. + Return a ElementTree element nested in tag2 nested in tag1. Usefull for strong emphasis etc. """ @@ -642,7 +649,7 @@ class HtmlPattern (Pattern): class LinkPattern (Pattern): - """ Return a NanoDom link Element from the given match. """ + """ Return a link element from the given match. """ def handleMatch(self, m): el = etree.Element("a") el.text = m.group(2) @@ -693,13 +700,16 @@ class LinkPattern (Pattern): return urlunparse(url) class ImagePattern(LinkPattern): - """ Return a NanoDom img Element from the given match. """ + """ Return a img element from the given match. """ def handleMatch(self, m): el = etree.Element("img") src_parts = m.group(9).split() if src_parts: - el.set('src', self.sanatize_url(src_parts[0])) + src = src_parts[0] + if src[0] == "<" and src[-1] == ">": + src = src[1:-1] + el.set('src', self.sanatize_url(src)) else: el.set('src', "") if len(src_parts) > 1: @@ -714,7 +724,7 @@ class ImagePattern(LinkPattern): return el class ReferencePattern(LinkPattern): - """ Match to a stored reference and return a NanoDom link Element. """ + """ Match to a stored reference and return link element. """ def handleMatch(self, m): if m.group(9): @@ -743,7 +753,7 @@ class ReferencePattern(LinkPattern): class ImageReferencePattern (ReferencePattern): - """ Match to a stored reference and return a NanoDom img Element. """ + """ Match to a stored reference and return img element. """ def makeTag(self, href, title, text): el = etree.Element("img") el.set("src", self.sanatize_url(href)) @@ -821,10 +831,10 @@ There are two types of post-processors: Postprocessor and TextPostprocessor class Postprocessor: """ - Postprocessors are run before the dom it converted back into text. + Postprocessors are run before the ElementTree serialization. Each Postprocessor implements a "run" method that takes a pointer to a - NanoDom document, modifies it as necessary and returns a NanoDom + ElementTree, modifies it as necessary and returns a ElementTree document. Postprocessors must extend markdown.Postprocessor. @@ -834,11 +844,10 @@ class Postprocessor: """ - def run(self, dom): + def run(self, et): """ Subclasses of Postprocessor should implement a `run` method, which - takes a NanoDOm document and returns a (possably modified) NanoDom - document. + takes a ElementTree and returns a (possably modified) ElementTree. """ pass @@ -847,7 +856,7 @@ class Postprocessor: class TextPostprocessor: """ - TextPostprocessors are run after the dom it converted back into text. + TextPostprocessors are run after the ElementTree it converted back into text. Each TextPostprocessor implements a "run" method that takes a pointer to a text string, modifies it as necessary and returns a text string. @@ -1107,6 +1116,7 @@ class CorePatterns: 'isline2': r'(\-*)', # --- 'isline3': r'(\_*)', # ___ 'tabbed': r'((\t)|( ))(.*)', # an indented line + 'tabbed2': r'(()( ))(.*)', # an indented line 'quoted': r'[ ]{0,2}> ?(.*)', # a quoted block ("> ...") } @@ -1279,8 +1289,7 @@ class Markdown: for prep in self.preprocessors : self.lines = prep.run(self.lines) - # Create a NanoDom tree from the lines and attach it to Document - + # Create a ElementTree from the lines buffer = [] for line in self.lines: @@ -1292,16 +1301,7 @@ class Markdown: buffer.append(line) self._processSection(self.root, buffer) - - #self._processSection(self.top_element, self.lines) - - # Not sure why I put this in but let's leave it for now. - #self.top_element.appendChild(self.doc.createTextNode('\n')) - - # Run the post-processors - for postprocessor in self.postprocessors: - postprocessor.run(self.doc) - + return etree.ElementTree(self.root) @@ -1323,10 +1323,15 @@ class Markdown: Returns: None """ - + # Loop through lines until none left. while lines: - + + # Skipping empty line + if not lines[0]: + lines = lines[1:] + continue + # Check if this section starts with a list, a blockquote or # a code block @@ -1370,7 +1375,7 @@ class Markdown: else: # Ok, so it's just a simple block paragraph, lines = self._linesUntil(lines, lambda line: - not line.strip()) + not line.strip() or line[0] == '>') if len(paragraph) and paragraph[0].startswith('#'): self._processHeader(parent_elem, paragraph) @@ -1448,7 +1453,7 @@ class Markdown: Keyword arguments: - * parent_elem: A dom element to which the content will be added + * parent_elem: A ElementTree element to which the content will be added * lines: a list of lines * inList: a level @@ -1486,7 +1491,7 @@ class Markdown: # Check if the next non-blank line is still a part of the list if ( RE.regExp['ul'].match(next) or RE.regExp['ol'].match(next) or - RE.regExp['tabbed'].match(next) ): + RE.regExp['tabbed'].match(next)): # get rid of any white space in the line items[item].append(line.strip()) looseList = loose or looseList @@ -1497,7 +1502,7 @@ class Markdown: # Now we need to detect list items (at the current level) # while also detabing child elements if necessary - for expr in ['ul', 'ol', 'tabbed']: + for expr in ['ul', 'ol', 'tabbed', 'tabbed2']: m = RE.regExp[expr].match(line) if m: @@ -1507,7 +1512,7 @@ class Markdown: # at the beginning of the list item items.append([m.group(1)]) item += 1 - elif expr == 'tabbed': # This line needs to be detabbed + elif expr == 'tabbed' or expr == 'tabbed2': # This line needs to be detabbed items[item].append(m.group(4)) #after the 'tab' i += 1 @@ -1518,7 +1523,7 @@ class Markdown: else: i += 1 - # Add the dom elements + # Add the ElementTree elements for item in items: li = etree.SubElement(ul, "li") @@ -1540,7 +1545,8 @@ class Markdown: i = -1 for line in lines: i += 1 - if condition(line): break + if condition(line): + break else: i += 1 return lines[:i], lines[i:] @@ -1554,7 +1560,7 @@ class Markdown: Keyword arguments: - * parent_elem: DOM element to which the content will be added + * parent_elem: ElementTree element to which the content will be added * lines: a list of lines * inList: a level @@ -1592,13 +1598,13 @@ class Markdown: def _processCodeBlock(self, parent_elem, lines, inList): """ Given a list of document lines starting with a code block - finds the end of the block, puts it into the dom verbatim + finds the end of the block, puts it into the ElementTree verbatim wrapped in ("
") and recursively processes the
         the remainder of the text file.
 
         Keyword arguments:
         
-        * parent_elem: DOM element to which the content will be added
+        * parent_elem: ElementTree element to which the content will be added
         * lines: a list of lines
         * inList: a level
         
@@ -1710,11 +1716,11 @@ class Markdown:
     
     def _processPlaceholders(self, data, parent):
         """
-        Processes string with placeholders and generates DOM tree.
+        Processes string with placeholders and generates ElementTree tree.
         
-        * data: string with placeholders instead of DOM elements.
+        * data: string with placeholders instead of ElementTree elements.
 
-        Returns: NanoDOM Document object with applied inline patterns.
+        Returns: list with ElementTree elements with applied inline patterns.
         """
         
         def linkText(text):
@@ -1880,7 +1886,6 @@ class Markdown:
         
         markdownTree = self._transform()
         
-        
         return markdownTree
         
         
@@ -1898,9 +1903,16 @@ class Markdown:
         """
 
         tree = self.markdownToTree(source)
-        
+
         root = self.applyInlinePatterns(tree).getroot()
-        
+
+        # Run the post-processors
+        for postprocessor in self.postprocessors:
+            postprocessor.stash = self.htmlStash
+            newRoot = postprocessor.run(root)
+            if newRoot:
+                root = newRoot
+
         indentETree(root)
 
         xml = codecs.decode(etree.tostring(root, encoding="utf8"), "utf8")
diff --git a/mdx_footnotes.py b/mdx_footnotes.py
index 4464c50..b46efbb 100644
--- a/mdx_footnotes.py
+++ b/mdx_footnotes.py
@@ -27,6 +27,7 @@ FN_BACKLINK_TEXT = "zz1337820767766393qq"
 
 
 import re, markdown, random
+from markdown import etree
 
 class FootnoteExtension (markdown.Extension):
 
@@ -80,15 +81,21 @@ class FootnoteExtension (markdown.Extension):
         self.used_footnotes={}
         self.footnotes = {}
 
-    def findFootnotesPlaceholder(self, doc) :
-        def findFootnotePlaceholderFn(node=None, indent=0):
-            if node.type == 'text':
-                if node.value.find(self.getConfig("PLACE_MARKER")) > -1 :
-                    return True
-
-        fn_div_list = doc.find(findFootnotePlaceholderFn)
-        if fn_div_list :
-            return fn_div_list[0]
+    def findFootnotesPlaceholder(self, root):
+        
+        def finder(element):
+            for child in element:
+                if child.text:
+                    if child.text.find(self.getConfig("PLACE_MARKER")) > -1:
+                        return child, True
+                if child.tail:
+                    if child.tail.find(self.getConfig("PLACE_MARKER")) > -1:
+                        return (child, element), False
+                finder(child)
+            return None
+                
+        res = finder(root)
+        return res
 
 
     def setFootnote(self, id, text) :
@@ -100,7 +107,7 @@ class FootnoteExtension (markdown.Extension):
     def makeFootnoteRefId(self, num) :
         return 'fnr%d%s' % (num, self.footnote_suffix)
 
-    def makeFootnotesDiv (self, doc) :
+    def makeFootnotesDiv (self, root) :
         """Creates the div with class='footnote' and populates it with
            the text of the footnotes.
 
@@ -109,45 +116,39 @@ class FootnoteExtension (markdown.Extension):
         if not self.footnotes.keys() :
             return None
 
-        div = doc.createElement("div")
-        div.setAttribute('class', 'footnote')
-        hr = doc.createElement("hr")
-        div.appendChild(hr)
-        ol = doc.createElement("ol")
-        div.appendChild(ol)
+        div = etree.Element("div")
+        div.set('class', 'footnote')
+        hr = etree.SubElement(div, "hr")
+        ol = etree.SubElement(div, "ol")
+        
 
         footnotes = [(self.used_footnotes[id], id)
                      for id in self.footnotes.keys()]
         footnotes.sort()
 
         for i, id in footnotes :
-            li = doc.createElement('li')
-            li.setAttribute('id', self.makeFootnoteId(i))
+            li = etree.SubElement(ol, "li")
+            li.set("id", self.makeFootnoteId(i))
 
             self.md._processSection(li, self.footnotes[id].split("\n"), looseList=1)
 
-            #li.appendChild(doc.createTextNode(self.footnotes[id]))
-
-            backlink = doc.createElement('a')
-            backlink.setAttribute('href', '#' + self.makeFootnoteRefId(i))
-            backlink.setAttribute('class', 'footnoteBackLink')
-            backlink.setAttribute('title',
-                                  'Jump back to footnote %d in the text' % i)
-            backlink.appendChild(doc.createTextNode(FN_BACKLINK_TEXT))
-
-            if li.childNodes :
-                node = li.childNodes[-1]
-                if node.type == "text" :
-		            li.appendChild(backlink)
-                elif node.nodeName == "p":
-                    node.appendChild(backlink)
+            backlink = etree.Element("a")
+            backlink.set("href", "#" + self.makeFootnoteRefId(i))
+            backlink.set("class", "footnoteBackLink")
+            backlink.set("title",
+                                  "Jump back to footnote %d in the text" % i)
+            backlink.text = FN_BACKLINK_TEXT
+
+            if li.getchildren():
+                node = li[-1]
+                if node.text:
+		            li.append(backlink)
+                elif node.tag == "p":
+                    node.append(backlink)
                 else:
-                    p = doc.createElement('p')
-                    p.appendChild(backlink)
-                    li.appendChild(p)
-
-            ol.appendChild(li)
-
+                    p = etree.SubElement(li, "p")
+                    p.append(backlink)
+        div = self.md.applyInlinePatterns(etree.ElementTree(div)).getroot()
         return div
 
 
@@ -194,7 +195,7 @@ class FootnotePreprocessor :
             plain = lines[:i]
 
             detabbed, theRest = self.blockGuru.detectTabbed(lines[i+1:])
-
+   
             self.footnotes.setFootnote(id,
                                        footnote + "\n"
                                        + "\n".join(detabbed))
@@ -227,15 +228,14 @@ class FootnotePattern (markdown.Pattern) :
         markdown.Pattern.__init__(self, pattern)
         self.footnotes = footnotes
 
-    def handleMatch(self, m, doc) :
-        sup = doc.createElement('sup')
-        a = doc.createElement('a')
-        sup.appendChild(a)
+    def handleMatch(self, m) :
+        sup = etree.Element("sup")
+        a = etree.SubElement(sup, "a")
         id = m.group(2)
         num = self.footnotes.used_footnotes[id]
-        sup.setAttribute('id', self.footnotes.makeFootnoteRefId(num))
-        a.setAttribute('href', '#' + self.footnotes.makeFootnoteId(num))
-        a.appendChild(doc.createTextNode(str(num)))
+        sup.set('id', self.footnotes.makeFootnoteRefId(num))
+        a.set('href', '#' + self.footnotes.makeFootnoteId(num))
+        a.text = str(num)
         return sup
 
 class FootnotePostprocessor (markdown.Postprocessor):
@@ -243,14 +243,25 @@ class FootnotePostprocessor (markdown.Postprocessor):
     def __init__ (self, footnotes) :
         self.footnotes = footnotes
 
-    def run(self, doc) :
-        footnotesDiv = self.footnotes.makeFootnotesDiv(doc)
-        if footnotesDiv :
-            fnPlaceholder = self.extension.findFootnotesPlaceholder(doc)
-            if fnPlaceholder :
+    def run(self, root):
+        footnotesDiv = self.footnotes.makeFootnotesDiv(root)
+        if footnotesDiv:
+            result = self.extension.findFootnotesPlaceholder(root)
+
+            if result:
+                node, isText = result
+                if isText:
+                    node.text = None
+                    node.getchildren().insert(0, footnotesDiv)
+                else:
+                    child, element = node
+                    ind = element.getchildren().find(child)
+                    element.getchildren().insert(ind + 1, footnotesDiv)
+                    child.tail = None
+                    
                 fnPlaceholder.parent.replaceChild(fnPlaceholder, footnotesDiv)
             else :
-                doc.documentElement.appendChild(footnotesDiv)
+                root.append(footnotesDiv)
 
 class FootnoteTextPostprocessor (markdown.Postprocessor):
 
diff --git a/mdx_rss.py b/mdx_rss.py
index 2117baf..b88b9b5 100644
--- a/mdx_rss.py
+++ b/mdx_rss.py
@@ -1,4 +1,5 @@
 import markdown
+from markdown import etree
 
 DEFAULT_URL = "http://www.freewisdom.org/projects/python-markdown/"
 DEFAULT_CREATOR = "Yuri Takhteyev"
@@ -18,7 +19,7 @@ month_map = { "Jan" : "01",
               "November" : "11",
               "December" : "12" }
 
-def get_time(heading) :
+def get_time(heading):
 
     heading = heading.split("-")[0]
     heading = heading.strip().replace(",", " ").replace(".", " ")
@@ -28,7 +29,7 @@ def get_time(heading) :
 
     return rdftime(" ".join((month, date, year, "12:00:00 AM")))
 
-def rdftime(time) :
+def rdftime(time):
 
     time = time.replace(":", " ")
     time = time.replace("/", " ")
@@ -37,12 +38,12 @@ def rdftime(time) :
                                         time[3], time[4], time[5])
 
 
-def get_date(text) :
+def get_date(text):
     return "date"
 
 class RssExtension (markdown.Extension):
 
-    def extendMarkdown(self, md, md_globals) :
+    def extendMarkdown(self, md, md_globals):
 
         self.config = { 'URL' : [DEFAULT_URL, "Main URL"],
                         'CREATOR' : [DEFAULT_CREATOR, "Feed creator's name"],
@@ -59,62 +60,59 @@ class RssExtension (markdown.Extension):
 
 class RssPostProcessor (markdown.Postprocessor):
 
-    def __init__(self, md) :
+    def __init__(self, md):
         
         pass
 
-    def run (self, doc) :
+    def run (self, root):
 
-        oldDocElement = doc.documentElement
-        rss = doc.createElement("rss")
-        rss.setAttribute('version', '2.0')
+        rss = etree.Element("rss")
+        rss.set("version", "2.0")
 
-        doc.appendChild(rss)
+        channel = etree.SubElement(rss, "channel")
 
-        channel = doc.createElement("channel")
-        rss.appendChild(channel)
         for tag, text in (("title", self.ext.getConfig("TITLE")),
                           ("link", self.ext.getConfig("URL")),
                           ("description", None)):
-            channel.appendChild(doc.createElement(tag, textNode = text))
-
-        for child in oldDocElement.childNodes :
-
-            if child.type == "element" :
-
-                if child.nodeName in ["h1", "h2", "h3", "h4", "h5"] :
-
-                    heading = child.childNodes[0].value.strip()
-                    
-                    item = doc.createElement("item")
-                    channel.appendChild(item)
-                    item.appendChild(doc.createElement("link",
-                                                       self.ext.getConfig("URL")))
-
-                    item.appendChild(doc.createElement("title", heading))
-
-                    guid = ''.join([x for x in heading if x.isalnum()])
-
-                    guidElem = doc.createElement("guid", guid)
-                    guidElem.setAttribute("isPermaLink", "false")
-                    item.appendChild(guidElem)
-
-                elif child.nodeName in ["p"] :
-
-                    description = doc.createElement("description")
-
-                    
-                    content = "\n".join([node.toxml()
-                                         for node in child.childNodes])
-
-                    cdata = doc.createCDATA(content)
-
-                    description.appendChild(cdata)
-
-                    if item :
-                        item.appendChild(description)
-
-
-def makeExtension(configs) :
+            
+            element = etree.SubElement(channel, tag)
+            element.text = text
+
+        for child in root:
+
+
+            if child.tag in ["h1", "h2", "h3", "h4", "h5"] :
+      
+                heading = child.text.strip()
+                
+                item = etree.SubElement(channel, "item")
+  
+                link = etree.SubElement(item, "link")
+                link.text = self.ext.getConfig("URL")
+
+                title = etree.SubElement(item, "title")
+                title.text = heading
+
+                guid = ''.join([x for x in heading if x.isalnum()])
+
+                guidElem = etree.SubElement(item, "guid")
+                guidElem.text = guid
+                guidElem.set("isPermaLink", "false")
+
+            elif child.tag in ["p"] :
+                if item:
+                    description = etree.SubElement(item, "description")
+                    if len(child):
+                        content = "\n".join([etree.tostring(node)
+                                             for node in child])
+                    else:
+                        content = child.text
+                    pholder = self.stash.store("" % content)
+                    description.text = pholder
+    
+        return rss
+
+
+def makeExtension(configs):
 
     return RssExtension(configs)
diff --git a/tests/extensions-x-footnotes/footnote.html b/tests/extensions-x-footnotes/footnote.html
index de0070d..4a844be 100644
--- a/tests/extensions-x-footnotes/footnote.html
+++ b/tests/extensions-x-footnotes/footnote.html
@@ -1,40 +1,42 @@
-

This is the body with a footnote1 or two2 or more3 4. -

- -

    -
  1. Footnote that ends with a list: -

    -
      -
    • - item 1 -
    • - -
    • - item 2 -
    • -
    -

    -

    - -
  2. - -
  3. This footnote is a blockquote. -

    -

    -

    - -
  4. - -
  5. A simple oneliner. -

    - -
  6. - -
  7. A footnote with multiple paragraphs. -

    -

    Paragraph two. -

    - -
  8. -
-
\ No newline at end of file +

This is the body with a footnote + 1 + or two + 2 + or more + 3 + + + 4 + .

+
+
+
    +
  1. +

    Footnote that ends with a list:

    +
      +
    • item 1
    • +
    • item 2
    • +
    +

    + +

    +
  2. +
  3. +
    +

    This footnote is a blockquote.

    +
    +

    + +

    +
  4. +
  5. +

    A simple oneliner. +

    +
  6. +
  7. +

    A footnote with multiple paragraphs.

    +

    Paragraph two. +

    +
  8. +
+
diff --git a/tests/markdown-test/angle-links-and-img.html b/tests/markdown-test/angle-links-and-img.html new file mode 100755 index 0000000..e32b6e6 --- /dev/null +++ b/tests/markdown-test/angle-links-and-img.html @@ -0,0 +1,7 @@ +

+ link + image + link + image +

+ diff --git a/tests/markdown-test/angle-links-and-img.txt b/tests/markdown-test/angle-links-and-img.txt new file mode 100755 index 0000000..1dbf404 --- /dev/null +++ b/tests/markdown-test/angle-links-and-img.txt @@ -0,0 +1,4 @@ +[link]( "title") +![image]() +[link]() +![image]() diff --git a/tests/misc/blockquote-below-paragraph.html b/tests/misc/blockquote-below-paragraph.html new file mode 100755 index 0000000..5757a9a --- /dev/null +++ b/tests/misc/blockquote-below-paragraph.html @@ -0,0 +1,6 @@ +

Paragraph

+
+

Block quote +Yep

+
+ diff --git a/tests/misc/blockquote-below-paragraph.txt b/tests/misc/blockquote-below-paragraph.txt new file mode 100755 index 0000000..0dd4d5c --- /dev/null +++ b/tests/misc/blockquote-below-paragraph.txt @@ -0,0 +1,3 @@ +Paragraph +>Block quote +>Yep diff --git a/tests/misc/html-comments.html b/tests/misc/html-comments.html new file mode 100755 index 0000000..ac08082 --- /dev/null +++ b/tests/misc/html-comments.html @@ -0,0 +1,2 @@ +

Here is HTML +and once more

diff --git a/tests/misc/html-comments.txt b/tests/misc/html-comments.txt new file mode 100755 index 0000000..cac4da5 --- /dev/null +++ b/tests/misc/html-comments.txt @@ -0,0 +1,2 @@ +Here is HTML +and once more

-- cgit v1.2.3