1 from xml.dom.minicompat import *
2 from xml.dom.minidom import Node, parseString, Attr
3
5 "No node is accessible via the dotted name given."
6
8 "No attribute is accessible via the dotted name given."
9
11 "An invalid attribute type was specified."
12
13
14 -def _getText(rootnode):
15 """
16 Get the text value from a C{Node}.
17
18 This is taken nearly verbatim from an example in the Python documentation.
19 U{http://docs.python.org/lib/dom-example.html}
20 """
21 rc = ""
22 for node in rootnode.childNodes:
23 if node.nodeType == node.TEXT_NODE:
24 rc = rc + node.data
25 return rc.strip()
26
27
29 """
30 Metaclass that makes sure everything in the sequence passed to the
31 constructor is a L{DotNode}.
32 """
34 """
35 @param sequence: The sequence that should be contained by this
36 instance.
37 @type sequence: tuple, list
38 @rtype: instance
39 """
40 mutate = lambda item:item.__class__==DotNode and item or DotNode(item)
41 return type.__call__(self, [mutate(item) for item in sequence])
42
43
45 """
46 A L{NodeList} that asks its first child for attributes.
47
48 One can also access this like a dictionary to get an L{Attr} on the first child.
49 """
50 __metaclass__ = DotNodeParent
51
53 """
54 If C{index} is an integer, return the C{index}th item in the list.
55 Otherwise, attempt to retrieve the attribute named C{index} on the
56 first child.
57 """
58 try:
59 return super(DotNodeList, self).__getitem__(int(index))
60 except ValueError:
61 return self.getAttribute(index)
62
64 """
65 All attribute access should be passed off to the first item in the
66 sequence.
67 """
68 return getattr(self[0], attr)
69
70
72 """
73 An object whose getattr gets child nodes.
74 """
76 """
77 @param node: The L{Node} to wrap.
78 @type node: L{Node}
79 """
80 self._node = node
81
83 """
84 Split the attribute and pass it to C{delegate} to be sent on to the
85 resolving method.
86 """
87 def delegate(name, idx=""):
88 """
89 Treat C{name} as a tagName, an attribute or a list index,
90 depending on the value of C{idx}.
91
92 @param name: The name to pass on to the accessor for resolution
93 @type name: str
94 @param idx: The identifier (empty for a node, "a" for an attribute,
95 an integer for an index)
96 @type idx: str
97 @return: void
98 """
99 if not idx:
100
101 return self.getChildren(name)
102 elif idx=='a':
103
104 return self.getAttribute(name)
105 else:
106 try:
107
108 return self.getItem(name, int(idx))
109 except ValueError:
110 raise AttributeParsingError(
111 "The locator you've specified is invalid.")
112 return delegate(*attr.split('__'))
113
115 """
116 @return: The tag name of the root node.
117 @rtype: str
118 """
119 return self._node.tagName
120
122 """
123 Attempt to resolve C{name} as the tag name of a L{Node}. If no node
124 with that name exists, attempt to resolve it as an L{Attr}.
125
126 @param name: The name to attempt to resolve.
127 @type name: str
128 @return: The matching nodes or attribute.
129 @rtype: L{DotNodeAttribute} or L{DotNodeList}
130 """
131 children = self._node.getElementsByTagName(name)
132 if not children:
133 try:
134 return self.getAttribute(name, *args)
135 except NoSuchAttribute:
136 raise NoSuchNode("No %s node found as a child of %s" % (
137 name, self.getName()))
138 return DotNodeList(children)
139
141 """
142 Attempt to retrieve the C{idx}th child node that has tagName C{name}.
143
144 @param name: The tag name to resolve into child nodes.
145 @type name: str
146 @param idx: The list index
147 @type idx: int
148 @return: A sequence containing the matching node.
149 @rtype: L{DotNodeList}
150 """
151 try:
152 return DotNodeList((self.getChildren(name)[idx],))
153 except IndexError:
154 raise NoSuchNode("There aren't that many %s nodes under %s." %(
155 name, self.getName()))
156
158 """
159 Get the C{name} attribute on C{self._node}.
160
161 @param name: The attribute name
162 @type name: str
163 @return: The matching attribute
164 @rtype: L{DotNodeAttribute}
165 """
166 attrval = self._node.getAttribute(name)
167 if not attrval:
168 raise NoSuchAttribute('No %s attribute exists on %s node.' % (
169 name, self.getName()))
170 return DotNodeAttribute(attrval)
171
173 """
174 Get the text value of C{self._node}.
175
176 @return: The text value of C{self._node}
177 @rtype: str
178 """
179 return unicode(_getText(self._node))
180
181
182 _ = property(getValue)
183
184
186 """
187 Accepts the source of an XML document, parses it, and provides dotted name
188 access to the root node.
189 """
191 """
192 @param source: A string containing an XML document.
193 @type source: str
194 """
195 self._doc = parseString(source)
196 self._root = DotNode(self._doc.documentElement)
197
199 """
200 Pass off attribute access to the root node.
201 """
202 return getattr(self._root, attr)
203
205 """
206 Remove the XML document from memory.
207 """
208 self._doc.unlink()
209
210
212 """
213 A string with a C{getValue} method.
214
215 This allows attribute values to be accessed just like L{DotNode}s.
216 """
218 _ = property(getValue)
219