1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
"""Simplify adding markup to a piece of text."""
from xml.sax import saxutils
# Helper functions to turn start/end tags into text
def _start_element(tag, attrs):
s = "<" + tag
for name, value in attrs.items():
s += " %s=%s" % (name, saxutils.quoteattr(value))
return s + ">"
def _end_element(tag):
return "</%s>" % tag
class MidPoint:
def __init__(self):
self.left = []
self.right = []
class MarkupEditor:
def __init__(self, text):
self.text = text
self._max = len(text)
self.midpoints = {}
def _get(self, pos):
assert 0 <= pos <= self._max, \
"position (%d) out of range; 0 <= x <= %d" % self._max
if self.midpoints.has_key(pos):
return self.midpoints[pos]
x = MidPoint()
self.midpoints[pos] = x
return x
def insert_text(self, pos, text):
point = self._get(pos)
point.right.insert(0, saxutils.escape(text))
def insert_raw_text(self, pos, text):
point = self._get(pos)
point.right.insert(0, text)
def insert_element(self, leftpos, rightpos, tag, attrs = {}):
strleft = _start_element(tag, attrs)
strright = _end_element(tag)
if leftpos == rightpos:
point = self._get(leftpos)
point.right.insert(0, strleft + strright)
else:
assert leftpos < rightpos, (leftpos, rightpos)
left = self._get(leftpos)
right = self._get(rightpos)
left.right.insert(0, strleft)
right.left.append(strright)
def insert_singleton(self, pos, tag, attrs = {}):
point = self._get(pos)
s = _start_element(tag, attrs)
point.right.insert(0, s)
def to_file(self, outfile):
items = self.midpoints.items()
items.sort()
text = self.text
prevpos = 0
for pos, midpoint in items:
outfile.write(text[prevpos:pos])
for s in midpoint.left:
outfile.write(s)
for s in midpoint.right:
outfile.write(s)
prevpos = pos
outfile.write(text[prevpos:])
def _compare(markup, expect):
from cStringIO import StringIO
file = StringIO()
markup.to_file(file)
s = file.getvalue()
assert s == expect, (s, expect)
def test():
markup = MarkupEditor("01234")
_compare(markup, "01234")
markup.insert_text(0, "A")
_compare(markup, "A01234")
markup.insert_text(5, "Z")
_compare(markup, "A01234Z")
markup.insert_text(5, "Y")
_compare(markup, "A01234YZ")
markup.insert_text(5, "<")
_compare(markup, "A01234<YZ")
markup.insert_raw_text(1, "BCD")
_compare(markup, "A0BCD1234<YZ")
markup.insert_raw_text(3, "<P>")
_compare(markup, "A0BCD12<P>34<YZ")
markup.insert_element(1, 3, "a", {"tag": "value"})
_compare(markup, 'A0<a tag="value">BCD12</a><P>34<YZ')
markup.insert_element(1, 1, "Q", {"R": "S"})
_compare(markup, 'A0<Q R="S"></Q><a tag="value">BCD12</a><P>34<YZ')
markup.insert_singleton(3, "br")
_compare(markup, 'A0<Q R="S"></Q><a tag="value">BCD12</a><br><P>34<YZ')
if __name__ == "__main__":
test()
|