~vorlon/ubuntu/saucy/gourmet/trunk

« back to all changes in this revision

Viewing changes to src/lib/exporters/MarkupString.py

  • Committer: Bazaar Package Importer
  • Author(s): Rolf Leggewie
  • Date: 2008-07-26 13:29:41 UTC
  • Revision ID: james.westby@ubuntu.com-20080726132941-6ldd73qmacrzz0bn
Tags: upstream-0.14.0
ImportĀ upstreamĀ versionĀ 0.14.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import xml.sax
 
2
 
 
3
class simpleHandler (xml.sax.ContentHandler):
 
4
    """A simple handler that provides us with indices of marked up content."""
 
5
    def __init__ (self):        
 
6
        self.elements = [] #this will contain a list of elements and their start/end indices
 
7
        self.open_elements = [] #this holds info on open elements while we wait for their close
 
8
        self.content = ""
 
9
 
 
10
    def startElement (self,name,attrs):
 
11
        if name=='foobar': return # we require an outer wrapper, which we promptly ignore.
 
12
        self.open_elements.append({'name':name,
 
13
                                   'attrs':attrs.copy(),
 
14
                                   'start':len(self.content),
 
15
                                   })
 
16
 
 
17
    def endElement (self, name):
 
18
        if name=='foobar': return # we require an outer wrapper, which we promptly ignore.
 
19
        for i in range(len(self.open_elements)):
 
20
            e = self.open_elements[i]
 
21
            if e['name']==name:
 
22
                # append a  (start,end), name, attrs
 
23
                self.elements.append(((e['start'], #start position
 
24
                                       len(self.content)),# current (end) position
 
25
                                      e['name'],e['attrs'])
 
26
                                     )
 
27
                del self.open_elements[i]
 
28
                return
 
29
 
 
30
    def characters (self, chunk):
 
31
        self.content += chunk
 
32
 
 
33
class MarkupString (str):
 
34
    """A simple class for dealing with marked up strings. When we are sliced, we return
 
35
    valid marked up strings, preserving markup."""
 
36
    def __init__ (self, string):        
 
37
        str.__init__(self,string)
 
38
        self.handler = simpleHandler()
 
39
        try:
 
40
            xml.sax.parseString("<foobar>%s</foobar>"%str(string),self.handler)
 
41
        except:
 
42
            print 'Unable to parse "%s"'%string
 
43
            raise
 
44
        self.raw=self.handler.content
 
45
 
 
46
    def __getitem__ (self, n):
 
47
        return self.__getslice__(n,n+1)
 
48
 
 
49
    def __getslice__ (self, s, e):
 
50
        # only include relevant elements
 
51
        if not e or e > len(self.raw): e = len(self.raw)
 
52
        elements = filter(lambda tp: (tp[0][1] >= s and # end after the start...
 
53
                                      tp[0][0] <= e # and start before the end
 
54
                                      ),
 
55
                          self.handler.elements)
 
56
        ends = {}
 
57
        starts = {}
 
58
        for el in elements:
 
59
            # cycle through elements that effect our slice and keep track of
 
60
            # where their start and end tags should go.
 
61
            pos = el[0]
 
62
            name = el[1]
 
63
            attrs = el[2]
 
64
            # write our start tag <stag att="val"...>
 
65
            stag = "<%s"%name
 
66
            for k,v in attrs.items(): stag += " %s=%s"%(k,xml.sax.saxutils.quoteattr(v))
 
67
            stag += ">"
 
68
            etag = "</%s>"%name # simple end tag
 
69
            spos = pos[0]
 
70
            epos = pos[1]
 
71
            if spos < s: spos=s
 
72
            if epos > e: epos=e
 
73
            if epos != spos: # we don't care about tags that don't markup any text
 
74
                if not starts.has_key(spos): starts[spos]=[]
 
75
                starts[spos].append(stag)
 
76
                if not ends.has_key(epos): ends[epos]=[]
 
77
                ends[epos].append(etag)
 
78
        outbuf = "" # our actual output string
 
79
        for pos in range(s,e): # we move through positions
 
80
            char = self.raw[pos]
 
81
            if ends.has_key(pos):  # if there are endtags to insert...
 
82
                for et in ends[pos]: outbuf += et
 
83
            if starts.has_key(pos): # if there are start tags to insert
 
84
                mystarts = starts[pos]
 
85
                # reverse these so the order works out,e.g. <i><b><u></u></b></i>
 
86
                mystarts.reverse()
 
87
                for st in mystarts: outbuf += st
 
88
            outbuf += char
 
89
        if ends.has_key(e):
 
90
            for et in ends[e]: outbuf+= et
 
91
        return MarkupString(str(outbuf)) # the str call is necessary to avoid unicode messiness