# This program is free software; you can redistribute it and/or modify it under # the terms of the (LGPL) GNU Lesser General Public License as published by the # Free Software Foundation; either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License # for more details at ( http://www.gnu.org/licenses/lgpl.html ). # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # written by: Jeff Ortel ( jortel@redhat.com ) """ Classes providing a (D)ocument (O)bject (M)odel representation of an XML document. The goal is to provide an easy, intuitive interface for managing XML documents. Although the term DOM is used above, this model is B{far} better. XML namespaces in suds are represented using a (2) element tuple containing the prefix and the URI, e.g. I{('tns', 'http://myns')}. """ import suds from suds import * from suds.sax import * from suds.sax.attribute import Attribute from suds.sax.document import Document from suds.sax.element import Element from suds.sax.text import Text import sys from xml.sax import make_parser, InputSource, ContentHandler from xml.sax.handler import feature_external_ges class Handler(ContentHandler): """SAX handler.""" def __init__(self): self.nodes = [Document()] def startElement(self, name, attrs): top = self.top() node = Element(str(name)) for a in attrs.getNames(): n = str(a) v = str(attrs.getValue(a)) attribute = Attribute(n, v) if self.mapPrefix(node, attribute): continue node.append(attribute) node.charbuffer = [] top.append(node) self.push(node) def mapPrefix(self, node, attribute): if attribute.name == "xmlns": if len(attribute.value): node.expns = str(attribute.value) return True if attribute.prefix == "xmlns": prefix = attribute.name node.nsprefixes[prefix] = str(attribute.value) return True return False def endElement(self, name): name = str(name) current = self.pop() if name != current.qname(): raise Exception("malformed document") if current.charbuffer: current.text = Text("".join(current.charbuffer)) del current.charbuffer if current: current.trim() def characters(self, content): text = str(content) node = self.top() node.charbuffer.append(text) def push(self, node): self.nodes.append(node) return node def pop(self): return self.nodes.pop() def top(self): return self.nodes[-1] class Parser: """SAX parser.""" @classmethod def saxparser(cls): p = make_parser() p.setFeature(feature_external_ges, 0) h = Handler() p.setContentHandler(h) return p, h def parse(self, file=None, string=None): """ SAX parse XML text. @param file: Parse a python I{file-like} object. @type file: I{file-like} object @param string: Parse string XML. @type string: str @return: Parsed XML document. @rtype: L{Document} """ if file is None and string is None: return timer = suds.metrics.Timer() timer.start() source = file if file is None: source = InputSource(None) source.setByteStream(suds.BytesIO(string)) sax, handler = self.saxparser() sax.parse(source) timer.stop() if file is None: suds.metrics.log.debug("%s\nsax duration: %s", string, timer) else: suds.metrics.log.debug("sax (%s) duration: %s", file, timer) return handler.nodes[0]