1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from translate.misc.typecheck import accepts, Self, IsCallable, IsOneOf, Any
26 """A class which is used to build XPath-like paths as a DOM tree is
27 walked. It keeps track of the number of times which it has seen
28 a certain tag, so that it will correctly create indices for tags.
29
30 Initially, the path is empty. Thus
31 >>> xb = XPathBreadcrumb()
32 >>> xb.xpath
33 ""
34
35 Suppose we walk down a DOM node for the tag <foo> and we want to
36 record this, we simply do
37 >>> xb.start_tag('foo')
38
39 Now, the path is no longer empty. Thus
40 >>> xb.xpath
41 foo[0]
42
43 Now suppose there are two <bar> tags under the tag <foo> (that is
44 <foo><bar></bar><bar></bar><foo>), then the breadcrumb will keep
45 track of the number of times it sees <bar>. Thus
46
47 >>> xb.start_tag('bar')
48 >>> xb.xpath
49 foo[0]/bar[0]
50 >>> xb.end_tag()
51 >>> xb.xpath
52 foo[0]
53 >>> xb.start_tag('bar')
54 >>> xb.xpath
55 foo[0]/bar[1]
56 """
57
59 self._xpath = []
60 self._tagtally = [{}]
61
62 @accepts(Self(), unicode)
64 tally_dict = self._tagtally[-1]
65 tally = tally_dict.get(tag, -1) + 1
66 tally_dict[tag] = tally
67 self._xpath.append((tag, tally))
68 self._tagtally.append({})
69
71 self._xpath.pop()
72 self._tagtally.pop()
73
75 def str_component(component):
76 tag, pos = component
77 return u"%s[%d]" % (tag, pos)
78 return u"/".join(str_component(component) for component in self._xpath)
79
80 xpath = property(_get_xpath)
81