logo4 Evolution is progress—                          
progress is creativity.        

Creole Macro to Include Pages

view blog view wiki view wiki view wiki

As already outlined there exist some macros quite helpful to start off.

The Initial Code Fragment

def include(macro,environ,pagename=None):
    """Return the parsed content of the page identified by arg_string"""
    if pagename is None:
        return None
    page_record = Page.get_by_key_name('-'+pagename)
    if page_record is not None:
        # infinit recursion protection
        if ('include',macro.arg_string,environ['wiki.page'].id,environ['wiki.metadata_page'].id) in environ['wiki.recurse']:
            return bldr.tag.div("<<include %s>> stopped, possible infite \
recursion encountered" % macro.arg_string.strip())
        environ = environ.copy()
        environ['wiki.metadata_page'] = page_record
        environ['wiki.page'] = page_record
        return environ['wiki.parser'].generate(page_record.body.value,environ=environ)

First Problem Solved

Even if adapting the page to my system this piece of code yields an error, which is caused because the variables environ['wiki.metadata_page'] and environ['wiki.page'] are initially not defined. I found a work around which allows to set the variable to the current page value if empty.

    if environ['my.metadata_page'] == None:
        environ['my.metadata_page'] = page
    if environ['my.page'] == None:
        environ['my.page'] = page

A much better solution is excluding the recursive test from the first page.

    if not environ['creole.metadata_page'] == None and not environ['creole.page'] == None:
        if ('include',macro.arg_string,environ['creole.page'].id,environ['creole.metadata_page'].id) in environ['creole.recurse']:
            return bldr.tag.div("<<include %s>> stopped, possible infinite recursion encountered" % macro.arg_string.strip())
        environ = environ.copy()

Downscaling The Included Text

Next I wanted my included text to fit the structure of the parent page. That is all subheadings have to be downgraded, so I created another parameter that signals the level at which the included page resides.

<<include slug=WaddingtonExperiment headerlevel=2>>

My include routine receives the parameter accordingly.

def include(macro,environ,slug=None,headerlevel=2):

#some stuff

    stream = XML(bldr.tag.div(environ['my.parser'].generate(page.content,environ=environ), id = slug, class_='include'))
    stream = stream.filter(SubstHeaderTag(int(headerlevel)-1))   

    headertag = "h%s" % headerlevel
    return bldr.tag.__getattr__(headertag)(rev.title) + stream

Finally for this Genshi filter to work I had to create a new class.

    class SubstHeaderTag(object):
        def __init__(self,downlevel):
            self.downlevel = downlevel
            self.newtag = 'h1'
        def __call__(self,stream):
            p = re.compile('^h(\d+)$', re.IGNORECASE)
            for kind, data, pos in stream:
                if kind is START:
                    tag, attrs = data
                    m = p.match(tag)
                    if m:
                        self.newtag = "h%s" % str(int(m.group(1))+self.downlevel)
                        data = QName(self.newtag), data[1]
                elif kind is END:
                    m = p.match(tag)
                    if m:
                        data = QName(self.newtag)
                yield kind, data, pos            

Probably this piece of code looks a bit awkward to those more experienced in python programming but it works. Unfortunately I didn't find any documentation how to create a filter and how the data structure in that filter look like.

Tags: Software


(c) Mato Nagel, Weißwasser 2004-2013, Disclaimer