You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by rh...@apache.org on 2007/07/23 16:36:07 UTC
svn commit: r558742 - in /incubator/qpid/trunk/qpid/python: mllib/
mllib/__init__.py mllib/dom.py mllib/parsers.py mllib/transforms.py
qpid/spec.py qpid/xmlutil.py
Author: rhs
Date: Mon Jul 23 07:36:05 2007
New Revision: 558742
URL: http://svn.apache.org/viewvc?view=rev&rev=558742
Log:
Added a better XML library.
Added:
incubator/qpid/trunk/qpid/python/mllib/
incubator/qpid/trunk/qpid/python/mllib/__init__.py (with props)
incubator/qpid/trunk/qpid/python/mllib/dom.py (with props)
incubator/qpid/trunk/qpid/python/mllib/parsers.py (with props)
incubator/qpid/trunk/qpid/python/mllib/transforms.py (with props)
Removed:
incubator/qpid/trunk/qpid/python/qpid/xmlutil.py
Modified:
incubator/qpid/trunk/qpid/python/qpid/spec.py
Added: incubator/qpid/trunk/qpid/python/mllib/__init__.py
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/mllib/__init__.py?view=auto&rev=558742
==============================================================================
--- incubator/qpid/trunk/qpid/python/mllib/__init__.py (added)
+++ incubator/qpid/trunk/qpid/python/mllib/__init__.py Mon Jul 23 07:36:05 2007
@@ -0,0 +1,60 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+This module provides document parsing and transformation utilities for
+both SGML and XML.
+"""
+
+import dom, transforms, parsers
+import xml.sax, types
+from cStringIO import StringIO
+
+def transform(node, *args):
+ result = node
+ for t in args:
+ if isinstance(t, types.ClassType):
+ t = t()
+ result = result.dispatch(t)
+ return result
+
+def sgml_parse(source):
+ if isinstance(source, basestring):
+ source = StringIO(source)
+ fname = "<string>"
+ elif hasattr(source, "name"):
+ fname = source.name
+ p = parsers.SGMLParser()
+ num = 1
+ for line in source:
+ p.feed(line)
+ p.parser.line(fname, num, None)
+ num += 1
+ p.close()
+ return p.parser.tree
+
+def xml_parse(source):
+ p = parsers.XMLParser()
+ xml.sax.parse(source, p)
+ return p.parser.tree
+
+def sexp(node):
+ s = transforms.Sexp()
+ node.dispatch(s)
+ return s.out
Propchange: incubator/qpid/trunk/qpid/python/mllib/__init__.py
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/qpid/trunk/qpid/python/mllib/dom.py
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/mllib/dom.py?view=auto&rev=558742
==============================================================================
--- incubator/qpid/trunk/qpid/python/mllib/dom.py (added)
+++ incubator/qpid/trunk/qpid/python/mllib/dom.py Mon Jul 23 07:36:05 2007
@@ -0,0 +1,250 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+Simple DOM for both SGML and XML documents.
+"""
+
+from transforms import Text
+
+class Container:
+
+ def __init__(self):
+ self.children = []
+
+ def add(self, child):
+ child.parent = self
+ self.children.append(child)
+
+ def extend(self, children):
+ for child in children:
+ child.parent = self
+ self.children.append(child)
+
+class Component:
+
+ def __init__(self):
+ self.parent = None
+
+ def index(self):
+ if self.parent:
+ return self.parent.children.index(self)
+ else:
+ return 0
+
+ def _line(self, file, line, column):
+ self.file = file
+ self.line = line
+ self.column = column
+
+class DispatchError(Exception):
+
+ def __init__(self, scope, f):
+ msg = "no such attribtue"
+
+class Dispatcher:
+
+ def is_type(self, type):
+ cls = self
+ while cls != None:
+ if cls.type == type:
+ return True
+ cls = cls.base
+ return False
+
+ def dispatch(self, f):
+ cls = self
+ while cls != None:
+ if hasattr(f, cls.type):
+ return getattr(f, cls.type)(self)
+ else:
+ cls = cls.base
+
+ cls = self
+ attrs = ""
+ while cls != None:
+ if attrs:
+ sep = ", "
+ if cls.base == None:
+ sep += "or "
+ else:
+ sep = ""
+ attrs += "%s'%s'" % (sep, cls.type)
+ cls = cls.base
+
+ raise AttributeError("'%s' object has no attribute %s" %
+ (f.__class__.__name__, attrs))
+
+class Node(Container, Component, Dispatcher):
+
+ type = "node"
+ base = None
+
+ def __init__(self):
+ Container.__init__(self)
+ Component.__init__(self)
+ self.query = Query([self])
+
+ def __getitem__(self, name):
+ for nd in self.query[name]:
+ return nd
+
+ def text(self):
+ return self.dispatch(Text())
+
+ def tag(self, name, *attrs, **kwargs):
+ t = Tag(name, *attrs, **kwargs)
+ self.add(t)
+ return t
+
+ def data(self, s):
+ d = Data(s)
+ self.add(d)
+ return d
+
+ def entity(self, s):
+ e = Entity(s)
+ self.add(e)
+ return e
+
+class Tree(Node):
+
+ type = "tree"
+ base = Node
+
+class Tag(Node):
+
+ type = "tag"
+ base = Node
+
+ def __init__(self, _name, *attrs, **kwargs):
+ Node.__init__(self)
+ self.name = _name
+ self.attrs = list(attrs)
+ self.attrs.extend(kwargs.items())
+ self.singleton = False
+
+ def get_attr(self, name):
+ for k, v in self.attrs:
+ if name == k:
+ return v
+
+ def __getitem__(self, name):
+ if name and name[0] == "@":
+ return self.get_attr(name[1:])
+ else:
+ for nd in self.query[name]:
+ return nd
+ return self.get_attr(name)
+
+ def dispatch(self, f):
+ try:
+ method = getattr(f, "do_" + self.name)
+ except AttributeError:
+ return Dispatcher.dispatch(self, f)
+ return method(self)
+
+class Leaf(Component, Dispatcher):
+
+ type = "leaf"
+ base = None
+
+ def __init__(self, data):
+ assert isinstance(data, basestring)
+ self.data = data
+
+class Data(Leaf):
+ type = "data"
+ base = Leaf
+
+class Entity(Leaf):
+ type = "entity"
+ base = Leaf
+
+class Character(Leaf):
+ type = "character"
+ base = Leaf
+
+class Comment(Leaf):
+ type = "comment"
+ base = Leaf
+
+###################
+## Query Classes ##
+###########################################################################
+
+class View:
+
+ def __init__(self, source):
+ self.source = source
+
+class Filter(View):
+
+ def __init__(self, predicate, source):
+ View.__init__(self, source)
+ if callable(predicate):
+ self.predicate = predicate
+ elif predicate[0] == "#":
+ type = predicate[1:]
+ self.predicate = lambda x: x.is_type(type)
+ else:
+ self.predicate = lambda x: isinstance(x, Tag) and x.name == predicate
+
+ def __iter__(self):
+ for nd in self.source:
+ if self.predicate(nd): yield nd
+
+class Flatten(View):
+
+ def __iter__(self):
+ sources = [iter(self.source)]
+ while sources:
+ try:
+ nd = sources[-1].next()
+ if isinstance(nd, Tree):
+ sources.append(iter(nd.children))
+ else:
+ yield nd
+ except StopIteration:
+ sources.pop()
+
+class Children(View):
+
+ def __iter__(self):
+ for nd in self.source:
+ for child in nd.children:
+ yield child
+
+class Query(View):
+
+ def __iter__(self):
+ for nd in self.source:
+ yield nd
+
+ def __getitem__(self, predicate):
+ if isinstance(predicate, basestring):
+ path = predicate.split("/")
+ else:
+ path = [predicate]
+
+ query = self.source
+ for p in path:
+ query = Query(Filter(p, Flatten(Children(query))))
+
+ return query
Propchange: incubator/qpid/trunk/qpid/python/mllib/dom.py
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/qpid/trunk/qpid/python/mllib/parsers.py
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/mllib/parsers.py?view=auto&rev=558742
==============================================================================
--- incubator/qpid/trunk/qpid/python/mllib/parsers.py (added)
+++ incubator/qpid/trunk/qpid/python/mllib/parsers.py Mon Jul 23 07:36:05 2007
@@ -0,0 +1,139 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+Parsers for SGML and XML to dom.
+"""
+
+import sgmllib, xml.sax.handler
+from dom import *
+
+class Parser:
+
+ def __init__(self):
+ self.tree = Tree()
+ self.node = self.tree
+ self.nodes = []
+
+ def line(self, id, lineno, colno):
+ while self.nodes:
+ n = self.nodes.pop()
+ n._line(id, lineno, colno)
+
+ def add(self, node):
+ self.node.add(node)
+ self.nodes.append(node)
+
+ def start(self, name, attrs):
+ tag = Tag(name, *attrs)
+ self.add(tag)
+ self.node = tag
+
+ def end(self, name):
+ self.balance(name)
+ self.node = self.node.parent
+
+ def data(self, data):
+ children = self.node.children
+ if children and isinstance(children[-1], Data):
+ children[-1].data += data
+ else:
+ self.add(Data(data))
+
+ def comment(self, comment):
+ self.add(Comment(comment))
+
+ def entity(self, ref):
+ self.add(Entity(ref))
+
+ def character(self, ref):
+ self.add(Character(ref))
+
+ def balance(self, name = None):
+ while self.node != self.tree and name != self.node.name:
+ self.node.parent.extend(self.node.children)
+ del self.node.children[:]
+ self.node.singleton = True
+ self.node = self.node.parent
+
+
+class SGMLParser(sgmllib.SGMLParser):
+
+ def __init__(self, entitydefs = None):
+ sgmllib.SGMLParser.__init__(self)
+ if entitydefs == None:
+ self.entitydefs = {}
+ else:
+ self.entitydefs = entitydefs
+ self.parser = Parser()
+
+ def unknown_starttag(self, name, attrs):
+ self.parser.start(name, attrs)
+
+ def handle_data(self, data):
+ self.parser.data(data)
+
+ def handle_comment(self, comment):
+ self.parser.comment(comment)
+
+ def unknown_entityref(self, ref):
+ self.parser.entity(ref)
+
+ def unknown_charref(self, ref):
+ self.parser.character(ref)
+
+ def unknown_endtag(self, name):
+ self.parser.end(name)
+
+ def close(self):
+ sgmllib.SGMLParser.close(self)
+ self.parser.balance()
+ assert self.parser.node == self.parser.tree
+
+class XMLParser(xml.sax.handler.ContentHandler):
+
+ def __init__(self):
+ self.parser = Parser()
+ self.locator = None
+
+ def line(self):
+ if self.locator != None:
+ self.parser.line(self.locator.getSystemId(),
+ self.locator.getLineNumber(),
+ self.locator.getColumnNumber())
+
+ def setDocumentLocator(self, locator):
+ self.locator = locator
+
+ def startElement(self, name, attrs):
+ self.parser.start(name, attrs.items())
+ self.line()
+
+ def endElement(self, name):
+ self.parser.end(name)
+ self.line()
+
+ def characters(self, content):
+ self.parser.data(content)
+ self.line()
+
+ def skippedEntity(self, name):
+ self.parser.entity(name)
+ self.line()
+
Propchange: incubator/qpid/trunk/qpid/python/mllib/parsers.py
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/qpid/trunk/qpid/python/mllib/transforms.py
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/mllib/transforms.py?view=auto&rev=558742
==============================================================================
--- incubator/qpid/trunk/qpid/python/mllib/transforms.py (added)
+++ incubator/qpid/trunk/qpid/python/mllib/transforms.py Mon Jul 23 07:36:05 2007
@@ -0,0 +1,164 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+Useful transforms for dom objects.
+"""
+
+from cStringIO import StringIO
+from dom import *
+
+class Visitor:
+
+ def descend(self, node):
+ for child in node.children:
+ child.dispatch(self)
+
+ def node(self, node):
+ self.descend(node)
+
+ def leaf(self, leaf):
+ pass
+
+class Identity:
+
+ def descend(self, node):
+ result = []
+ for child in node.children:
+ result.append(child.dispatch(self))
+ return result
+
+ def default(self, tag):
+ result = Tag(tag.name, *tag.attrs)
+ result.extend(self.descend(tag))
+ return result
+
+ def tree(self, tree):
+ result = Tree()
+ result.extend(self.descend(tree))
+ return result
+
+ def tag(self, tag):
+ return self.default(tag)
+
+ def leaf(self, leaf):
+ return leaf.__class__(leaf.data)
+
+class Sexp(Identity):
+
+ def __init__(self):
+ self.stack = []
+ self.level = 0
+ self.out = ""
+
+ def open(self, s):
+ self.out += "(%s" % s
+ self.level += len(s) + 1
+ self.stack.append(s)
+
+ def line(self, s = ""):
+ self.out = self.out.rstrip()
+ self.out += "\n" + " "*self.level + s
+
+ def close(self):
+ s = self.stack.pop()
+ self.level -= len(s) + 1
+ self.out = self.out.rstrip()
+ self.out += ")"
+
+ def tree(self, tree):
+ self.open("+ ")
+ for child in tree.children:
+ self.line(); child.dispatch(self)
+ self.close()
+
+ def tag(self, tag):
+ self.open("Node(%s) " % tag.name)
+ for child in tag.children:
+ self.line(); child.dispatch(self)
+ self.close()
+
+ def leaf(self, leaf):
+ self.line("%s(%s)" % (leaf.__class__.__name__, leaf.data))
+
+class Output:
+
+ def descend(self, node):
+ out = StringIO()
+ for child in node.children:
+ out.write(child.dispatch(self))
+ return out.getvalue()
+
+ def default(self, tag):
+ out = StringIO()
+ out.write("<%s" % tag.name)
+ for k, v in tag.attrs:
+ out.write(' %s="%s"' % (k, v))
+ out.write(">")
+ out.write(self.descend(tag))
+ if not tag.singleton:
+ out.write("</%s>" % tag.name)
+ return out.getvalue()
+
+ def tree(self, tree):
+ return self.descend(tree)
+
+ def tag(self, tag):
+ return self.default(tag)
+
+ def data(self, leaf):
+ return leaf.data
+
+ def entity(self, leaf):
+ return "&%s;" % leaf.data
+
+ def character(self, leaf):
+ raise Exception("TODO")
+
+ def comment(self, leaf):
+ return "<!-- %s -->" % leaf.data
+
+class Empty(Output):
+
+ def tag(self, tag):
+ return self.descend(tag)
+
+ def data(self, leaf):
+ return ""
+
+ def entity(self, leaf):
+ return ""
+
+ def character(self, leaf):
+ return ""
+
+ def comment(self, leaf):
+ return ""
+
+class Text(Empty):
+
+ def data(self, leaf):
+ return leaf.data
+
+ def entity(self, leaf):
+ return "&%s;" % leaf.data
+
+ def character(self, leaf):
+ # XXX: is this right?
+ return "&#%s;" % leaf.data
Propchange: incubator/qpid/trunk/qpid/python/mllib/transforms.py
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/qpid/trunk/qpid/python/qpid/spec.py
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/qpid/spec.py?view=diff&rev=558742&r1=558741&r2=558742
==============================================================================
--- incubator/qpid/trunk/qpid/python/qpid/spec.py (original)
+++ incubator/qpid/trunk/qpid/python/qpid/spec.py Mon Jul 23 07:36:05 2007
@@ -29,7 +29,7 @@
situations.
"""
-import re, textwrap, new, xmlutil
+import re, textwrap, new, mllib
class SpecContainer:
@@ -275,21 +275,20 @@
self.docs = docs
def get_desc(nd):
- label = nd.get("@label")
+ label = nd["@label"]
if not label:
- label = nd.text
+ label = nd.text()
if label:
label = label.strip()
return label
def get_docs(nd):
- return [n.text for n in nd["doc"]]
+ return [n.text() for n in nd.query["doc"]]
def load_fields(nd, l, domains):
- for f_nd in nd["field"]:
- try:
- type = f_nd["@domain"]
- except KeyError:
+ for f_nd in nd.query["field"]:
+ type = f_nd["@domain"]
+ if type == None:
type = f_nd["@type"]
type = pythonize(type)
domain = None
@@ -300,27 +299,27 @@
get_desc(f_nd), get_docs(f_nd)))
def load(specfile, *errata):
- doc = xmlutil.parse(specfile)
- spec_root = doc["amqp"][0]
+ doc = mllib.xml_parse(specfile)
+ spec_root = doc["amqp"]
spec = Spec(int(spec_root["@major"]), int(spec_root["@minor"]), specfile)
- for root in [spec_root] + map(lambda x: xmlutil.parse(x)["amqp"][0], errata):
+ for root in [spec_root] + map(lambda x: mllib.xml_parse(x)["amqp"], errata):
# constants
- for nd in root["constant"]:
+ for nd in root.query["constant"]:
const = Constant(spec, pythonize(nd["@name"]), int(nd["@value"]),
- nd.get("@class"), get_docs(nd))
+ nd["@class"], get_docs(nd))
try:
spec.constants.add(const)
- except ValueError, e:
+ except ValueError, e:
print "Warning:", e
# domains are typedefs
- for nd in root["domain"]:
+ for nd in root.query["domain"]:
spec.domains.add(Domain(spec, nd.index(), pythonize(nd["@name"]),
pythonize(nd["@type"]), get_desc(nd),
get_docs(nd)))
# classes
- for c_nd in root["class"]:
+ for c_nd in root.query["class"]:
cname = pythonize(c_nd["@name"])
if spec.classes.byname.has_key(cname):
klass = spec.classes.byname[cname]
@@ -331,16 +330,16 @@
added_methods = []
load_fields(c_nd, klass.fields, spec.domains.byname)
- for m_nd in c_nd["method"]:
+ for m_nd in c_nd.query["method"]:
mname = pythonize(m_nd["@name"])
if klass.methods.byname.has_key(mname):
meth = klass.methods.byname[mname]
else:
meth = Method(klass, mname,
int(m_nd["@index"]),
- m_nd.get_bool("@content", False),
- [pythonize(nd["@name"]) for nd in m_nd["response"]],
- m_nd.get_bool("@synchronous", False),
+ m_nd["@content"] == "1",
+ [pythonize(nd["@name"]) for nd in m_nd.query["response"]],
+ m_nd["@synchronous"] == "1",
get_desc(m_nd),
get_docs(m_nd))
klass.methods.add(meth)