More SVGdraw fixups, make namespaces work on import

This commit is contained in:
Dan Williams 2006-05-15 14:47:06 -04:00
parent ae2eb70b6c
commit 0ca5a7fed5

View File

@ -227,6 +227,8 @@ class Attribute:
self.value = value self.value = value
self.nsname = nsname self.nsname = nsname
self.nsref = nsref self.nsref = nsref
def __repr__(self):
return "(%s=%s, ns: %s=%s)" % (self.name, self.value, self.nsname, self.nsref)
def get_attr_value(attrs, name): def get_attr_value(attrs, name):
return attrs[name] return attrs[name]
@ -271,7 +273,9 @@ class SVGelement:
def setParent(self, parent): def setParent(self, parent):
self._parent = parent self._parent = parent
def setAttribute(self, attribute): def setAttribute(self, attribute, replace=True):
if not replace and self.hasAttribute(attribute.name):
return
self._attributes[attribute.name] = attribute self._attributes[attribute.name] = attribute
def delAttribute(self, name): def delAttribute(self, name):
@ -287,19 +291,63 @@ class SVGelement:
raise Exception("Can't construct a default object.") raise Exception("Can't construct a default object.")
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
def _get_namespace(attrname, nslist):
colon_idx = attrname.find(':')
if colon_idx <= 0:
return (attrname, None, None)
nsname = attrname[:colon_idx]
nsref = None
attrname = attrname[colon_idx+1:]
for (ns, val) in nslist:
if ns == nsname:
nsref = val
break
if not nsref:
nsname = None
return (attrname, nsname, nsref)
_get_namespace = staticmethod(_get_namespace)
_XMLNS_TAG = "xmlns:"
def construct(name, attributes, text=None, cdata=None): def construct(name, attributes, text=None, cdata=None):
try: try:
eltClass = elementTable[name] eltClass = elementTable[name]
except KeyError, e: except KeyError, e:
print "Unknown SVG element %s." % e print "Unknown SVG element %s." % e
return None return None
element = eltClass._construct(attributes) # Coalesce namespaces into the attributes themselves
attr_dict = {}
elt_namespace = None
namespaces = []
tmp_attrs = []
# Separate namespaces from actual attributes
for attrname, attrvalue in attributes.items(): for attrname, attrvalue in attributes.items():
element.setAttribute(Attribute(attrname, attrvalue)) if attrname.startswith(SVGelement._XMLNS_TAG):
if text: namespaces.append((attrname[len(SVGelement._XMLNS_TAG):], attrvalue))
element.text = text elif attrname.startswith("xmlns"):
if cdata: # Element-wide attribute
element.cdata = cdata elt_namespace = attrvalue
else:
tmp_attrs.append((attrname, attrvalue))
# Create attributes and assign namespaces to them
for (attrname, attrvalue) in tmp_attrs:
nsname = nsref = None
attr = None
# search for its namespace, if any
(attrname, nsname, nsref) = SVGelement._get_namespace(attrname, namespaces)
attr = Attribute(attrname, attrvalue, nsname, nsref)
attr_dict[attrname] = attr
element = eltClass._construct(attr_dict)
if element:
for attr in attr_dict.values():
element.setAttribute(attr, replace=False)
if text:
element.text = text
if cdata:
element.cdata = cdata
if not element.namespace and elt_namespace:
element.namespace = elt_namespace
return element return element
construct = staticmethod(construct) construct = staticmethod(construct)
@ -389,10 +437,10 @@ class tref(SVGelement):
return s return s
def _construct(attributes): def _construct(attributes):
href = get_attr_value(attributes, 'xlink:href') href = get_attr_value(attributes, 'href')
if href and href.startswith("xlink:"): if href and href.nsname == 'xlink':
href = href[len("xlink:"):] return tref(href.value)
return tref(href) return None
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
class spannedtext: class spannedtext:
@ -458,7 +506,7 @@ class rect(SVGelement):
def _construct(attributes): def _construct(attributes):
width = get_attr_value(attributes, 'width') width = get_attr_value(attributes, 'width')
height = get_attr_value(attributes, 'height') height = get_attr_value(attributes, 'height')
return rect(width=width, height=height) return rect(width=width.value, height=height.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -490,7 +538,7 @@ class ellipse(SVGelement):
def _construct(attributes): def _construct(attributes):
rx = get_attr_value(attributes, 'rx') rx = get_attr_value(attributes, 'rx')
ry = get_attr_value(attributes, 'ry') ry = get_attr_value(attributes, 'ry')
return ellipse(rx=rx, ry=ry) return ellipse(rx=rx.value, ry=ry.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -516,10 +564,10 @@ class circle(SVGelement):
def _construct(attributes): def _construct(attributes):
r = get_attr_value(attributes, 'r') r = get_attr_value(attributes, 'r')
if int(r) == 1: if int(r.value) == 1:
return point() return point()
else: else:
return circle(r=r) return circle(r=r.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -529,7 +577,7 @@ class point(circle):
A point is defined as a circle with a size 1 radius. It may be more efficient to use a A point is defined as a circle with a size 1 radius. It may be more efficient to use a
very small rectangle if you use many points because a circle is difficult to render. very small rectangle if you use many points because a circle is difficult to render.
""" """
def __init__(self,x=None,y=None,fill='black',**args): def __init__(self,x=None,y=None,fill=None,**args):
circle.__init__(self,x,y,1,fill,**args) circle.__init__(self,x,y,1,fill,**args)
class line(SVGelement): class line(SVGelement):
@ -573,7 +621,7 @@ class polyline(SVGelement):
def _construct(attributes): def _construct(attributes):
points = get_attr_value(attributes, 'points') points = get_attr_value(attributes, 'points')
return polyline(points) return polyline(points.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -593,7 +641,7 @@ class polygon(SVGelement):
def _construct(attributes): def _construct(attributes):
points = get_attr_value(attributes, 'points') points = get_attr_value(attributes, 'points')
return polygon(points) return polygon(points.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -615,7 +663,7 @@ class path(SVGelement):
def _construct(attributes): def _construct(attributes):
pathdata = get_attr_value(attributes, 'd') pathdata = get_attr_value(attributes, 'd')
return path(d) return path(pathdata.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -656,10 +704,10 @@ class textpath(SVGelement):
self.text=text self.text=text
def _construct(attributes): def _construct(attributes):
href = get_attr_value(attributes, 'xlink:href') href = get_attr_value(attributes, 'href')
if href and href.startswith("xlink:"): if href and href.nsname == 'xlink':
href = href[len("xlink:"):] return textpath(href.value)
return textpath(href) return None
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -782,7 +830,7 @@ class stop(SVGelement):
def _construct(attributes): def _construct(attributes):
offset = get_attr_value(attributes, 'offset') offset = get_attr_value(attributes, 'offset')
return stop(offset) return stop(offset.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
class style(SVGelement): class style(SVGelement):
@ -795,7 +843,7 @@ class style(SVGelement):
def _construct(attributes): def _construct(attributes):
type = get_attr_value(attributes, 'type') type = get_attr_value(attributes, 'type')
return style(type) return style(type.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -820,12 +868,12 @@ class image(SVGelement):
self.setAttribute(Attribute('y', y)) self.setAttribute(Attribute('y', y))
def _construct(attributes): def _construct(attributes):
href = get_attr_value(attributes, 'xlink:href') href = get_attr_value(attributes, 'href')
if href and href.startswith("xlink:"):
href = href[len("xlink:"):]
width = get_attr_value(attributes, 'width') width = get_attr_value(attributes, 'width')
height = get_attr_value(attributes, 'height') height = get_attr_value(attributes, 'height')
return image(href, width=width, height=height) if href and href.nsname == 'xlink':
return image(href.value, width=width.value, height=height.value)
return None
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -839,10 +887,10 @@ class cursor(SVGelement):
self.setAttribute(Attribute('href', url, 'xlink', xlinkNSRef)) self.setAttribute(Attribute('href', url, 'xlink', xlinkNSRef))
def _construct(attributes): def _construct(attributes):
href = get_attr_value(attributes, 'xlink:href') href = get_attr_value(attributes, 'href')
if href and href.startswith("xlink:"): if href and href.nsname == 'xlink':
href = href[len("xlink:"):] return cursor(href.value)
return cursor(href) return None
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -955,10 +1003,10 @@ class use(SVGelement):
self.setAttribute(Attribute('height', height)) self.setAttribute(Attribute('height', height))
def _construct(attributes): def _construct(attributes):
href = get_attr_value(attributes, 'xlink:href') href = get_attr_value(attributes, 'href')
if href and href.startswith("xlink:"): if href and href.nsname == 'xlink':
href = href[len("xlink:"):] return use(href.value)
return use(href) return None
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -973,10 +1021,10 @@ class link(SVGelement):
self.setAttribute(Attribute('href', link, 'xlink', xlinkNSRef)) self.setAttribute(Attribute('href', link, 'xlink', xlinkNSRef))
def _construct(attributes): def _construct(attributes):
href = get_attr_value(attributes, 'xlink:href') href = get_attr_value(attributes, 'href')
if href and href.startswith("xlink:"): if href and href.nsname == 'xlink':
href = href[len("xlink:"):] return link(href.value)
return link(href) return None
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -1005,7 +1053,7 @@ class script(SVGelement):
def _construct(attributes): def _construct(attributes):
type = get_attr_value(attributes, 'type') type = get_attr_value(attributes, 'type')
return script(type, cdata=cdata) return script(type.value, cdata=cdata.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -1025,7 +1073,7 @@ class animate(SVGelement):
def _construct(attributes): def _construct(attributes):
attribute = get_attr_value(attributes, 'attributeName') attribute = get_attr_value(attributes, 'attributeName')
return animate(attribute) return animate(attribute.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -1086,7 +1134,7 @@ class animateColor(SVGelement):
def _construct(attributes): def _construct(attributes):
attribute = get_attr_value(attributes, 'attributeName') attribute = get_attr_value(attributes, 'attributeName')
return animateColor(attribute) return animateColor(attribute.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -1104,7 +1152,7 @@ class set(SVGelement):
def _construct(attributes): def _construct(attributes):
attribute = get_attr_value(attributes, 'attributeName') attribute = get_attr_value(attributes, 'attributeName')
return set(attribute) return set(attribute.value)
_construct = staticmethod(_construct) _construct = staticmethod(_construct)
@ -1190,13 +1238,15 @@ class SVGImportParser(object):
def StartElementHandler(self, name, attrs): def StartElementHandler(self, name, attrs):
self.log("<%s>" % name) self.log("<%s>" % name)
self._indent = self._indent + 1 self._indent = self._indent + 1
import copy
attrs = copy.deepcopy(attrs)
for attrname, attrvalue in attrs.items(): for attrname, attrvalue in attrs.items():
self.log("%s = %s" % (attrname, attrvalue)) self.log("%s = %s" % (attrname, attrvalue))
parent = self._stack.peek() parent = self._stack.peek()
elt = SVGelement.construct(name, attrs) elt = SVGelement.construct(name, attrs)
if not self._base: if not self._base:
self._base = elt self._base = elt
if parent: if parent and elt:
parent.addElement(elt) parent.addElement(elt)
self._stack.push(elt) self._stack.push(elt)
@ -1214,6 +1264,8 @@ class SVGImportParser(object):
self.log("Text = '%s'" % content.strip()) self.log("Text = '%s'" % content.strip())
elt = self._stack.peek() elt = self._stack.peek()
if elt: if elt:
if not elt.text:
elt.text = ""
elt.text = elt.text + content.strip() elt.text = elt.text + content.strip()
def EndCdataSectionHandler(self): def EndCdataSectionHandler(self):
@ -1425,16 +1477,14 @@ elementTable = {
'svg': svg 'svg': svg
} }
def main(): def from_file(document):
d=drawing()
import sys import sys
f = open(sys.argv[1], "r") f = open(sys.argv[1], "r")
fc = f.read() fc = f.read()
d.fromXml(fc) document.fromXml(fc)
print d.toXml() print document.toXml()
return
def to_file(document):
s=svg((0,0,100,100)) s=svg((0,0,100,100))
r=rect(-100,-100,300,300,'cyan') r=rect(-100,-100,300,300,'cyan')
s.addElement(r) s.addElement(r)
@ -1465,10 +1515,14 @@ def main():
for j in range(5,105,10): for j in range(5,105,10):
c=circle(i,j,1,'red','black',.5) c=circle(i,j,1,'red','black',.5)
s.addElement(c) s.addElement(c)
d.setSVG(s) document.setSVG(s)
print d.toXml() print document.toXml()
def main():
d=drawing()
from_file(d)
# to_file(d)
if __name__=='__main__': if __name__=='__main__':
main() main()