Package simplexmlapi :: Module node
[hide private]
[frames] | no frames]

Source Code for Module simplexmlapi.node

  1  from xml.dom.minicompat import * 
  2  from xml.dom.minidom import Node, parseString, Attr 
  3   
4 -class NoSuchNode(Exception):
5 "No node is accessible via the dotted name given." 6
7 -class NoSuchAttribute(Exception):
8 "No attribute is accessible via the dotted name given." 9
10 -class AttributeParsingError(Exception):
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
28 -class DotNodeParent(type):
29 """ 30 Metaclass that makes sure everything in the sequence passed to the 31 constructor is a L{DotNode}. 32 """
33 - def __call__(self, sequence):
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
44 -class DotNodeList(NodeList):
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
52 - def __getitem__(self, index):
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
63 - def __getattribute__(self, attr):
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
71 -class DotNode(object):
72 """ 73 An object whose getattr gets child nodes. 74 """
75 - def __init__(self, node):
76 """ 77 @param node: The L{Node} to wrap. 78 @type node: L{Node} 79 """ 80 self._node = node
81
82 - def __getattr__(self, attr):
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 # Empty idx, so it's a node 101 return self.getChildren(name) 102 elif idx=='a': 103 # idx is 'a', so it's an attribute 104 return self.getAttribute(name) 105 else: 106 try: 107 # Try casting idx as an integer to see if it's a list index 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
114 - def getName(self):
115 """ 116 @return: The tag name of the root node. 117 @rtype: str 118 """ 119 return self._node.tagName
120
121 - def getChildren(self, name, *args):
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
140 - def getItem(self, name, idx):
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
157 - def getAttribute(self, name, *args):
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
172 - def getValue(self):
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 # Property accessor 182 _ = property(getValue) 183 184
185 -class DotXMLDoc(object):
186 """ 187 Accepts the source of an XML document, parses it, and provides dotted name 188 access to the root node. 189 """
190 - def __init__(self, source):
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
198 - def __getattr__(self, attr):
199 """ 200 Pass off attribute access to the root node. 201 """ 202 return getattr(self._root, attr)
203
204 - def __del__(self):
205 """ 206 Remove the XML document from memory. 207 """ 208 self._doc.unlink()
209 210
211 -class DotNodeAttribute(str):
212 """ 213 A string with a C{getValue} method. 214 215 This allows attribute values to be accessed just like L{DotNode}s. 216 """
217 - def getValue(self): return self
218 _ = property(getValue)
219