Index: fedd/federation/topdl.py
===================================================================
--- fedd/federation/topdl.py	(revision df783c1ca49a9d217508072d7226d4777a7179ac)
+++ fedd/federation/topdl.py	(revision db6b092dbd30839cdaeb24ac51df1e525a79befa)
@@ -23,5 +23,5 @@
     def get_attribute(self, key):
 	rv = None
-	attrs = getattr(self, 'attributes', None)
+	attrs = getattr(self, 'attribute', None)
 	if attrs:
 	    for a in attrs:
@@ -40,4 +40,7 @@
 	self.value = value
 
+    def clone(self):
+	return Attribute(attribute=self.attribute, value=self.value)
+
     def to_dict(self):
 	return { 'attribute': self.attribute, 'value': self.value }
@@ -48,4 +51,7 @@
 	self.kind = kind
 
+    def clone(self):
+	return Capacity(rate=self.rate, kind=self.kind)
+
     def to_dict(self):
 	return { 'rate': self.rate, 'kind': self.kind }
@@ -55,4 +61,7 @@
 	self.time = time
 	self.kind = kind
+
+    def clone(self):
+	return Latency(time=self.time, kind=self.kind)
 
     def to_dict(self):
@@ -68,4 +77,16 @@
 	self.interfaces = [ ]
 
+    def clone(self):
+	if self.capacity: c = self.capacity.clone()
+	else: c = None
+
+	if self.latency: l = self.latency.clone()
+	else: l = None
+
+	return Substrate(name=self.name,
+		capacity=c,
+		latency=l,
+		attribute = [a.clone() for a in self.attribute])
+
     def to_dict(self):
 	rv = { 'name': self.name }
@@ -83,4 +104,8 @@
 	self.attribute = [ self.init_class(Attribute, a) for a in \
 		self.make_list(attribute) ]
+
+    def clone(self):
+	return CPU(type=self.type,
+		attribute = [a.clone() for a in self.attribute])
 
     def to_dict(self):
@@ -100,4 +125,8 @@
 		for a in self.make_list(attribute) ]
 
+    def clone(self):
+	return Storage(amount=self.amount, persistence=self.persistence, 
+		attribute = [a.clone() for a in self.attribute])
+
     def to_dict(self):
 	rv = { 'amount': float(self.amount), 'persistence': self.persistence }
@@ -116,4 +145,11 @@
 		for a in self.make_list(attribute) ]
 
+    def clone(self):
+	return OperatingSystem(name=self.name,
+		version=self.version,
+		distribution=self.distribution,
+		distributionversion=self.distributionversion,
+		attribute = [ a.clone() for a in self.attribute])
+
     def to_dict(self):
 	rv = { }
@@ -132,4 +168,8 @@
 	self.attribute = [ self.init_class(Attribute, a)\
 		for a in self.make_list(attribute) ]
+
+    def clone(self):
+	return Software(location=self.location, install=self.install, 
+		attribute=[a.clone() for a in self.attribute])
 
     def to_dict(self):
@@ -150,4 +190,15 @@
 	self.element = element 
 	self.subs = [ ]
+
+    def clone(self):
+	if self.capacity: c = self.capacity.clone()
+	else: c = None
+
+	if self.latency: l = self.latency.clone()
+	else: l = None
+
+	return Interface(substrate=self.substrate,
+		capacity=c, latency=l,
+		attribute = [ a.clone() for a in self.attribute])
 
     def to_dict(self):
@@ -181,6 +232,17 @@
 	map(assign_element, self.interface)
 
+    def clone(self):
+	return Computer(name=self.name,
+		cpu=[x.clone() for x in self.cpu],
+		os=[x.clone() for x in self.os],
+		software=[x.clone() for x in self.software],
+		storage=[x.clone() for x in self.storage],
+		interface=[x.clone() for x in self.interface],
+		attribute=[x.clone() for x in self.attribute])
+
     def to_dict(self):
 	rv = { }
+	if self.name:
+	    rv['name'] = self.name
 	if self.cpu:
 	    rv['cpu'] = [ c.to_dict() for  c in self.cpu ]
@@ -203,4 +265,8 @@
 	self.attribute = [ self.init_class(Attribute, c) \
 		for c in self.make_list(attribute) ]
+
+    def clone(self):
+	return Other(interface=[i.clone() for i in self.interface], 
+		attribute=[a.clone() for a in attribute])
 
     def to_dict(self):
@@ -225,7 +291,10 @@
 	    }
 
-	for k in e.keys():
-	    cl = classmap.get(k, None)
-	    if cl: return cl(**e[k])
+	if isinstance(e, dict):
+	    for k in e.keys():
+		cl = classmap.get(k, None)
+		if cl: return cl(**e[k])
+	else:
+	    return e
 
     def __init__(self, substrates=[], elements=[]):
@@ -234,8 +303,13 @@
 	self.elements = [ self.init_element(e) \
 		for e in self.make_list(elements) ]
+	self.incorporate_elements()
+
+    def incorporate_elements(self):
+
 	# Could to this init in one gulp, but we want to look for duplicate
 	# substrate names
 	substrate_map = { }
 	for s in self.substrates:
+	    s.interfaces = [ ]
 	    if not substrate_map.has_key(s.name):
 		substrate_map[s.name] = s
@@ -243,7 +317,8 @@
 		raise ConsistencyError("Duplicate substrate name %s" % s.name)
 
-	substrate_map = dict([ (s.name, s) for s in self.substrates ])
 	for e in self.elements:
 	    for i in e.interface:
+		i.element = e
+		i.subs = [ ]
 		for sn in i.substrate:
 		    # NB, interfaces have substrate names in their substrate
@@ -256,4 +331,13 @@
 			raise ConsistencyError("No such substrate for %s" % sn)
 
+    def clone(self):
+	return Topology(substrates=[s.clone() for s in self.substrates], 
+		elements=[e.clone() for e in self.elements])
+
+
+    def make_indices(self):
+	sub_index = dict([(s.name, s) for s in self.substrates])
+	elem_index = dict([(n, e) for e in self.elements for n in e.name])
+
     def to_dict(self):
 	rv = { }
@@ -264,5 +348,5 @@
 	return rv
 
-def topology_from_xml(string=None, file=None, top="topology"):
+def topology_from_xml(string=None, file=None, filename=None, top="topology"):
     import xml.parsers.expat
 
@@ -318,9 +402,15 @@
     xp.CharacterDataHandler = p.char_data
 
-    if file and string:
-	raise RuntimeError("Only one of file and string")
+    num_set = len([ x for x in (string, filename, file)\
+	    if x is not None ])
+
+    if num_set != 1:
+	raise RuntimeError("Exactly one one of file, filename and string " + \
+		"must be set")
+    elif filename:
+	f = open(filename, "r")
+	xp.ParseFile(f)
     elif file:
-	f = open(file, "r")
-	xp.ParseFile(f)
+	xp.ParseFile(file)
     elif string:
 	xp.Parse(string, isfinal=True)
@@ -360,3 +450,44 @@
 
 
-
+def topology_to_vtopo(t):
+    nodes = [ ]
+    lans = [ ]
+
+    for eidx, e in enumerate(t.elements):
+	n = { }
+	if e.name: name = e.name[0]
+	else: name = "unnamed_node%d" % eidx
+	
+	ips = [ ]
+	for i in e.interfaces:
+	    ip = i.get_attribute('ip4_address')
+	    ips.append(ip)
+	    port = "%s:%d" % (name, idx)
+	    for idx, s in enumerate(i.subs):
+		bw = 100000
+		delay = 0.0
+		if s.capacity:
+		    bw = s.capacity.rate
+		if i.capacity:
+		    bw = i.capacity.rate
+
+		if s.latency:
+		    delay = s.latency.time
+		if i.latency:
+		    bw = i.latency.time
+
+		lans.append({
+		    'member': port,
+		    'vname': s.name,
+		    'ip': ip,
+		    'vnode': name,
+		    'delay': delay,
+		    'bandwidth': bw,
+		    })
+	nodes.append({
+	    'ips': ":".join(ips),
+	    'vname': name,
+	    })
+
+	nodes.append(n)
+    return { 'vtopo': { 'node': node, 'lan': lan } }
