Esempio n. 1
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is.
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type = get_serialize_type(environ)
    extension = environ.get('tiddlyweb.extension')
    serialized = False

    # If this is a tiddler with a CANONICAL_URI_FIELD redirect
    # there unless we are requesting a json form
    if (CANONICAL_URI_FIELD in tiddler.fields
            and not CANONICAL_URI_PASS_TYPE in mime_type):
        raise HTTP302(tiddler.fields[CANONICAL_URI_FIELD])

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type or
                mime_type.startswith(tiddler.type) or
                extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type, serialized

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
        serialized = True
    except (TiddlerFormatError, NoSerializationError) as exc:
        raise HTTP415(exc)
    return content, mime_type, serialized
Esempio n. 2
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type = web.get_serialize_type(environ)
    extension = environ.get('tiddlyweb.extension')

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type or
                mime_type.startswith(tiddler.type) or
                extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
    except (TiddlerFormatError, NoSerializationError), exc:
        raise HTTP415(exc)
Esempio n. 3
0
def get_rellinks(environ, tiddler):
    """
    Create a dict of rellinks for this tiddler in this tank.
    """
    store = environ['tiddlyweb.store']
    bag_name = tiddler.bag
    links = {'index': True}
    if tiddler.title == INDEX_PAGE:
        links['index'] = False

    tiddlers = [filtered_tiddler.title for filtered_tiddler in
            filter_tiddlers(store.list_bag_tiddlers(Bag(bag_name)),
                'sort=modified', environ)
            if renderable(store.get(filtered_tiddler), environ)]

    try:
        this_index = tiddlers.index(tiddler.title)
        prev_index = this_index - 1
        if prev_index >= 0:
            prev_tiddler = tiddlers[prev_index]
        else:
            prev_tiddler = None
        try:
            next_tiddler = tiddlers[this_index + 1]
        except IndexError:
            next_tiddler = None

        links['prev'] = prev_tiddler
        links['next'] = next_tiddler
    except ValueError:
        pass

    return links
Esempio n. 4
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type = web.get_serialize_type(environ)
    extension = environ.get('tiddlyweb.extension')

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type
                or mime_type.startswith(tiddler.type) or extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
    except (TiddlerFormatError, NoSerializationError), exc:
        raise HTTP415(exc)
Esempio n. 5
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is.
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type, accept = get_serialize_type(environ,
                                                           accept_type=True)
    extension = environ.get('tiddlyweb.extension')
    serialized = False

    # If this is a tiddler with a CANONICAL_URI_FIELD redirect
    # there unless we are requesting a json form
    if (CANONICAL_URI_FIELD in tiddler.fields
            and CANONICAL_URI_PASS_TYPE not in mime_type):
        raise HTTP302(tiddler.fields[CANONICAL_URI_FIELD])

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type
                or accept.startswith(tiddler.type) or extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type, serialized

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
        serialized = True
    except (TiddlerFormatError, NoSerializationError) as exc:
        raise HTTP415(exc)
    return content, mime_type, serialized
Esempio n. 6
0
    def _add_tiddler_to_feed(self, feed, tiddler):
        do_revisions = self.environ.get('tiddlyweb.query', {}).get(
                'depth', [None])[0]

        if not do_revisions:
            if binary_tiddler(tiddler):
                # XXX: ought to be enclosures?
                if tiddler.type.startswith('image/'):
                    description = ('\n<img src="%s" />\n'
                            % tiddler_url(self.environ, tiddler))
                else:
                    description = ('\n<a href="%s">%s</a>\n'
                            % (tiddler_url(self.environ, tiddler),
                                tiddler.title))
            elif (renderable(tiddler, self.environ)):
                try:
                    description = render_wikitext(tiddler, self.environ)
                except KeyError:
                    description = 'Tiddler cannot be rendered.'
            else:
                description = '<pre>' + tiddler.text + '</pre>'

            self._add_item(feed, tiddler, tiddler_url(self.environ, tiddler),
                    tiddler.title, description)
        else:
            self._process_tiddler_revisions(feed, tiddler,
                    tiddler_url(self.environ, tiddler), do_revisions)
Esempio n. 7
0
 def _tiddler_dict(self, tiddler, fat=False, render=False):
     """
     Select fields from a tiddler to create
     a dictonary.
     """
     unwanted_keys = ['text', 'store']
     wanted_keys = [
         attribute for attribute in tiddler.slots
         if attribute not in unwanted_keys
     ]
     wanted_info = {}
     for attribute in wanted_keys:
         wanted_info[attribute] = getattr(tiddler, attribute, None)
     wanted_info['permissions'] = self._tiddler_permissions(tiddler)
     wanted_info['uri'] = tiddler_url(self.environ, tiddler)
     if fat:
         if tiddler.text:
             if binary_tiddler(tiddler):
                 wanted_info['text'] = b64encode(tiddler.text)
             else:
                 wanted_info['text'] = tiddler.text
         else:
             wanted_info['text'] = ''
     if render and renderable(tiddler, self.environ):
         wanted_info['render'] = render_wikitext(tiddler, self.environ)
     return wanted_info
    def transcluder(self, match):
        if 'markdown.transclusions' in self.environ:
            seen_titles = self.environ['markdown.transclusions']
        else:
            seen_titles = []

        interior_title = match.group(1)
        try:
            target = match.group(2) or match.group(3)
        except IndexError:
            target = None

        # bail out if we have no store
        if not self.store:
            return match.group(0)

        try:
            interior_tiddler = self.resolve_tiddler(target, interior_title)
            interior_tiddler = self.store.get(interior_tiddler)
        except (StoreError, KeyError, PermissionsError):
            return match.group(0)

        semaphore_title = '%s:%s' % (interior_tiddler.bag,
                interior_tiddler.title)

        if semaphore_title not in seen_titles:
            seen_titles.append(semaphore_title)
            self.environ['markdown.transclusions'] = seen_titles
            if renderable(interior_tiddler, self.environ):
                content = render_wikitext(interior_tiddler, self.environ)
            else:
                content = ''
            seen_titles.pop()
            return '<article id="%s" class="transclusion" data-uri="%s" ' \
                    'data-title="%s" data-bag="%s">%s</article>' % (
                            self._make_id(interior_tiddler),
                            self.interior_url(interior_tiddler),
                            interior_tiddler.title,
                            interior_tiddler.bag, content)
        else:
            return match.group(0)
Esempio n. 9
0
 def _tiddler_dict(self, tiddler, fat=False, render=False):
     """
     Select fields from a tiddler to create
     a dictonary.
     """
     unwanted_keys = ['text', 'store']
     wanted_keys = [attribute for attribute in tiddler.slots if
             attribute not in unwanted_keys]
     wanted_info = {}
     for attribute in wanted_keys:
         wanted_info[attribute] = getattr(tiddler, attribute, None)
     wanted_info['permissions'] = self._tiddler_permissions(tiddler)
     if fat:
         if binary_tiddler(tiddler):
             wanted_info['text'] = b64encode(tiddler.text)
         else:
             wanted_info['text'] = tiddler.text
             if render and renderable(tiddler, self.environ):
                 wanted_info['render'] = render_wikitext(tiddler,
                         self.environ)
     return wanted_info
Esempio n. 10
0
def wiki_page(environ, start_response):
    """
    Present a single tiddler from a given tank.
    """
    tank_name = get_route_value(environ, 'bag_name')
    store = environ['tiddlyweb.store']
    usersign = environ['tiddlyweb.usersign']
    config = environ['tiddlyweb.config']

    try:
        bag = store.get(Bag(tank_name))
        bag = augment_bag(store, bag)
    except NoBagError:
        raise HTTP404('no tank found for %s' % tank_name)

    try:
        tiddler_name = get_route_value(environ, 'tiddler_name')
    except (KeyError, AttributeError):
        raise HTTP302(tank_page_uri(environ, tank_name, INDEX_PAGE))

    if tiddler_name in SPECIAL_PAGES:
        return SPECIAL_PAGES[tiddler_name](environ, start_response)

    # let permissions problems raise
    bag.policy.allows(usersign, 'read')

    editable = True
    creatable = True
    deletable = True
    try:
        bag.policy.allows(usersign, 'write')
    except PermissionsError:
        editable = False
    try:
        bag.policy.allows(usersign, 'create')
    except PermissionsError:
        creatable = False
    try:
        bag.policy.allows(usersign, 'delete')
    except PermissionsError:
        deletable = False

    try:
        tiddler = Tiddler(tiddler_name, tank_name)
        tiddler = store.get(tiddler)
    except NoTiddlerError:
        tiddler.type = 'text/x-markdown'
        tiddler.text = '### This tiddler does not yet exist\n'
        if creatable:
            editable = True
        else:
            editable = False
        deletable = False
        if tiddler.title != INDEX_PAGE:
            sisterlinks = get_sisterlinks(environ, tiddler)
            tiddler.text = (tiddler.text +
                            '\n### Other tiddlers with similar names\n' +
                            ''.join([
                                '* [[%s]]@[[%s]] @%s\n' %
                                (stiddler.title, stiddler.bag, stiddler.bag)
                                for stiddler in sisterlinks
                            ]))

    if renderable(tiddler, environ):
        backlinks = get_backlinks(environ, tiddler)
        rellinks = get_rellinks(environ, tiddler)
        compable = full_search(config, 'id:"%s:app"' % tank_name)
        html = render_wikitext(tiddler, environ)
        start_response('200 OK', [('Content-Type', 'text/html; charset=UTF-8'),
                                  ('Cache-Control', 'no-cache')])
        return send_template(
            environ, WIKI_TEMPLATE, {
                'tiddler': tiddler,
                'html': html,
                'bag': bag,
                'backlinks': backlinks,
                'create': creatable,
                'edit': editable,
                'delete': deletable,
                'compable': compable,
                'links': rellinks,
            })
    else:
        return tiddler_get(environ, start_response)
def _process_for_transclusion(output, tiddler, environ):
    """
    Process the output for transclusions.
    """
    if 'twikified.seen_titles' in environ:
        seen_titles = environ['twikified.seen_titles']
    else:
        seen_titles = []

    parser = html5lib.HTMLParser(
        tree=html5lib.treebuilders.getTreeBuilder("dom"))

    output = output.decode('utf-8', 'replace')
    try:
        dom = parser.parse('<div>' + output + '</div>')
        spans = dom.getElementsByTagName('span')
        for span in spans:
            for attribute in span.attributes.keys():
                if attribute == 'tiddler':
                    attr = span.attributes[attribute]
                    interior_title = attr.value
                    try:
                        span_class = span.attributes['class'].value
                        if span_class.startswith('@'):
                            interior_recipe = span_class[1:] + '_public'
                        else:
                            interior_recipe = ''
                    except KeyError:
                        interior_recipe = ''
                    title_semaphore = '%s:%s' % (interior_title,
                                                 interior_recipe)
                    if title_semaphore not in seen_titles:
                        seen_titles.append(title_semaphore)
                        interior_tiddler = Tiddler(interior_title)
                        try:
                            store = environ['tiddlyweb.store']
                            if interior_recipe:
                                recipe = store.get(Recipe(interior_recipe))
                                interior_tiddler.recipe = interior_recipe
                                interior_tiddler.bag = (
                                    determine_bag_from_recipe(
                                        recipe, interior_tiddler,
                                        environ).name)
                            else:
                                if tiddler.recipe:
                                    interior_tiddler.recipe = tiddler.recipe
                                    recipe = store.get(Recipe(tiddler.recipe))
                                    interior_tiddler.bag = (
                                        determine_bag_from_recipe(
                                            recipe, interior_tiddler,
                                            environ).name)
                                else:
                                    interior_tiddler.bag = tiddler.bag
                            interior_bag = store.get(Bag(interior_tiddler.bag))
                            interior_bag.policy.allows(
                                environ['tiddlyweb.usersign'], 'read')
                            interior_tiddler = store.get(interior_tiddler)
                        except (StoreError, PermissionsError):
                            continue
                        if renderable(interior_tiddler, environ):
                            environ['twikified.seen_titles'] = seen_titles
                            interior_content = render_wikitext(
                                interior_tiddler, environ)
                            interior_dom = parser.parse('<div>' +
                                                        interior_content
                                                        + '</div>')
                            span.appendChild(
                                interior_dom.getElementsByTagName(
                                    'div')[0])

        output = dom.getElementsByTagName('div')[0].toxml()
    except ExpatError, exc:
        # If expat couldn't process the output, we need to make it
        # unicode as what came over the socket was utf-8 but expat
        # needs that in the first place.
        LOGGER.warn('got expat error: %s:%s %s',
                    tiddler.bag, tiddler.title, exc)
        output = output.decode('utf-8', 'replace')
Esempio n. 12
0
def wiki_page(environ, start_response):
    """
    Present a single tiddler from a given tank.
    """
    tank_name = get_route_value(environ, "bag_name")
    store = environ["tiddlyweb.store"]
    usersign = environ["tiddlyweb.usersign"]
    config = environ["tiddlyweb.config"]

    try:
        bag = store.get(Bag(tank_name))
        bag = augment_bag(store, bag)
    except NoBagError:
        raise HTTP404("no tank found for %s" % tank_name)

    try:
        tiddler_name = get_route_value(environ, "tiddler_name")
    except (KeyError, AttributeError):
        raise HTTP302(tank_page_uri(environ, tank_name, INDEX_PAGE))

    if tiddler_name in SPECIAL_PAGES:
        return SPECIAL_PAGES[tiddler_name](environ, start_response)

    # let permissions problems raise
    bag.policy.allows(usersign, "read")

    editable = True
    creatable = True
    deletable = True
    try:
        bag.policy.allows(usersign, "write")
    except PermissionsError:
        editable = False
    try:
        bag.policy.allows(usersign, "create")
    except PermissionsError:
        creatable = False
    try:
        bag.policy.allows(usersign, "delete")
    except PermissionsError:
        deletable = False

    try:
        tiddler = Tiddler(tiddler_name, tank_name)
        tiddler = store.get(tiddler)
    except NoTiddlerError:
        tiddler.type = "text/x-markdown"
        tiddler.text = "### This tiddler does not yet exist\n"
        if creatable:
            editable = True
        else:
            editable = False
        deletable = False
        if tiddler.title != INDEX_PAGE:
            sisterlinks = get_sisterlinks(environ, tiddler)
            tiddler.text = (
                tiddler.text
                + "\n### Other tiddlers with similar names\n"
                + "".join(
                    ["* [[%s]]@[[%s]] @%s\n" % (stiddler.title, stiddler.bag, stiddler.bag) for stiddler in sisterlinks]
                )
            )

    if renderable(tiddler, environ):
        backlinks = get_backlinks(environ, tiddler)
        rellinks = get_rellinks(environ, tiddler)
        compable = full_search(config, 'id:"%s:app"' % tank_name)
        html = render_wikitext(tiddler, environ)
        start_response("200 OK", [("Content-Type", "text/html; charset=UTF-8"), ("Cache-Control", "no-cache")])
        return send_template(
            environ,
            WIKI_TEMPLATE,
            {
                "tiddler": tiddler,
                "html": html,
                "bag": bag,
                "backlinks": backlinks,
                "create": creatable,
                "edit": editable,
                "delete": deletable,
                "compable": compable,
                "links": rellinks,
            },
        )
    else:
        return tiddler_get(environ, start_response)
Esempio n. 13
0
def _process_for_transclusion(output, tiddler, environ):
    """
    Process the output for transclusions.
    """
    if 'twikified.seen_titles' in environ:
        seen_titles = environ['twikified.seen_titles']
    else:
        seen_titles = []

    parser = html5lib.HTMLParser(
        tree=html5lib.treebuilders.getTreeBuilder("dom"))

    output = output.decode('utf-8', 'replace')
    try:
        dom = parser.parse('<div>' + output + '</div>')
        spans = dom.getElementsByTagName('span')
        for span in spans:
            for attribute in span.attributes.keys():
                if attribute == 'tiddler':
                    attr = span.attributes[attribute]
                    interior_title = attr.value
                    try:
                        span_class = span.attributes['class'].value
                        if span_class.startswith('@'):
                            interior_recipe = span_class[1:] + '_public'
                        else:
                            interior_recipe = ''
                    except KeyError:
                        interior_recipe = ''
                    title_semaphore = '%s:%s' % (interior_title,
                                                 interior_recipe)
                    if title_semaphore not in seen_titles:
                        seen_titles.append(title_semaphore)
                        interior_tiddler = Tiddler(interior_title)
                        try:
                            store = environ['tiddlyweb.store']
                            if interior_recipe:
                                recipe = store.get(Recipe(interior_recipe))
                                interior_tiddler.recipe = interior_recipe
                                interior_tiddler.bag = (
                                    determine_bag_from_recipe(
                                        recipe, interior_tiddler,
                                        environ).name)
                            else:
                                if tiddler.recipe:
                                    interior_tiddler.recipe = tiddler.recipe
                                    recipe = store.get(Recipe(tiddler.recipe))
                                    interior_tiddler.bag = (
                                        determine_bag_from_recipe(
                                            recipe, interior_tiddler,
                                            environ).name)
                                else:
                                    interior_tiddler.bag = tiddler.bag
                            interior_bag = store.get(Bag(interior_tiddler.bag))
                            interior_bag.policy.allows(
                                environ['tiddlyweb.usersign'], 'read')
                            interior_tiddler = store.get(interior_tiddler)
                        except (StoreError, PermissionsError):
                            continue
                        if renderable(interior_tiddler, environ):
                            environ['twikified.seen_titles'] = seen_titles
                            interior_content = render_wikitext(
                                interior_tiddler, environ)
                            interior_dom = parser.parse('<div>' +
                                                        interior_content +
                                                        '</div>')
                            span.appendChild(
                                interior_dom.getElementsByTagName('div')[0])

        output = dom.getElementsByTagName('div')[0].toxml()
    except ExpatError, exc:
        # If expat couldn't process the output, we need to make it
        # unicode as what came over the socket was utf-8 but expat
        # needs that in the first place.
        LOGGER.warn('got expat error: %s:%s %s', tiddler.bag, tiddler.title,
                    exc)
        output = output.decode('utf-8', 'replace')
Esempio n. 14
0
File: wiki.py Progetto: pads/tank
def wiki_page(environ, start_response):
    """
    Present a single tiddler from a given tank.
    """
    tank_name = get_route_value(environ, 'bag_name')
    store = environ['tiddlyweb.store']
    usersign = environ['tiddlyweb.usersign']
    config = environ['tiddlyweb.config']

    try:
        bag = store.get(Bag(tank_name))
    except NoBagError:
        raise HTTP404('no tank found for %s' % tank_name)

    try:
        tiddler_name = get_route_value(environ, 'tiddler_name')
    except (KeyError, AttributeError):
        raise HTTP302(tank_page_uri(environ, tank_name, 'index'))

    if tiddler_name in SPECIAL_PAGES:
        return SPECIAL_PAGES[tiddler_name](environ, start_response)

    # let permissions problems raise
    bag.policy.allows(usersign, 'read')

    editable = True
    creatable = True
    deletable = True
    try:
        bag.policy.allows(usersign, 'write')
    except PermissionsError:
        editable = False
    try:
        bag.policy.allows(usersign, 'create')
    except PermissionsError:
        creatable = False
    try:
        bag.policy.allows(usersign, 'delete')
    except PermissionsError:
        deletable = False

    try:
        tiddler = Tiddler(tiddler_name, tank_name)
        tiddler = store.get(tiddler)
    except NoTiddlerError:
        tiddler.type = 'text/x-markdown'
        tiddler.text = '### This tiddler does not yet exist\n'
        if creatable:
            editable = True
        deletable = False

    if renderable(tiddler, environ):
        backlinks = get_backlinks(environ, tiddler)
        compable = full_search(config, 'id:"%s:app"' % tank_name)
        html = render_wikitext(tiddler, environ)
        wiki_template = get_template(environ, WIKI_TEMPLATE)
        start_response('200 OK', [
            ('Content-Type', 'text/html; charset=UTF-8'),
            ('Cache-Control', 'no-cache')])
        return wiki_template.generate({
            'socket_link': config.get('socket.link'),
            'csrf_token': get_nonce(environ),
            'gravatar': gravatar(environ),
            'user': usersign['name'],
            'tiddler': tiddler,
            'html': html,
            'bag': bag,
            'backlinks': backlinks,
            'edit': editable,
            'delete': deletable,
            'compable': compable,
        })
    else:
        return tiddler_get(environ, start_response)
Esempio n. 15
0
                                public_bag = store.get(Bag(interior_bag))
                                public_bag.policy.allows(
                                    environ['tiddlyweb.usersign'], 'read')
                                interior_tiddler.bag = interior_bag
                            else:
                                if tiddler.recipe:
                                    interior_tiddler.recipe = tiddler.recipe
                                    recipe = store.get(Recipe(tiddler.recipe))
                                    interior_tiddler.bag = determine_bag_from_recipe(
                                        recipe, interior_tiddler, environ).name
                                else:
                                    interior_tiddler.bag = tiddler.bag
                            interior_tiddler = store.get(interior_tiddler)
                        except (StoreError, PermissionsError):
                            continue
                        if renderable(interior_tiddler, environ):
                            interior_content = render(interior_tiddler,
                                                      environ, seen_titles)
                            interior_dom = parser.parse('<div>' +
                                                        interior_content +
                                                        '</div>')
                            span.appendChild(
                                interior_dom.getElementsByTagName('div')[0])

        output = dom.getElementsByTagName('div')[0].toxml()
    except ExpatError, exc:
        # If expat couldn't process the output, we need to make it
        # unicode as what came over the socket was utf-8 but expat
        # needs that in the first place.
        logging.warn('got expat error: %s:%s %s', tiddler.bag, tiddler.title,
                     exc)
Esempio n. 16
0
                                public_bag = store.get(Bag(interior_bag))
                                public_bag.policy.allows(
                                        environ['tiddlyweb.usersign'], 'read')
                                interior_tiddler.bag = interior_bag
                            else:
                                if tiddler.recipe:
                                    interior_tiddler.recipe = tiddler.recipe
                                    recipe = store.get(Recipe(tiddler.recipe))
                                    interior_tiddler.bag = determine_bag_from_recipe(
                                            recipe, interior_tiddler, environ).name
                                else:
                                    interior_tiddler.bag = tiddler.bag
                            interior_tiddler = store.get(interior_tiddler)
                        except (StoreError, PermissionsError):
                            continue
                        if renderable(interior_tiddler, environ):
                            interior_content = render(interior_tiddler, environ,
                                    seen_titles)
                            interior_dom = parser.parse('<div>' + 
                                    interior_content
                                    + '</div>')
                            span.appendChild(interior_dom.getElementsByTagName('div')[0])

        output = dom.getElementsByTagName('div')[0].toxml()
    except ExpatError, exc:
        # If expat couldn't process the output, we need to make it
        # unicode as what came over the socket was utf-8 but expat
        # needs that in the first place.
        logging.warn('got expat error: %s:%s %s', tiddler.bag, tiddler.title, exc)
        output = output.decode('utf-8', 'replace')
    return output