Index: fedd/compose.py
===================================================================
--- fedd/compose.py	(revision f9c2f63407d8491281b0ecaa50c4c6f66f3b80f9)
+++ fedd/compose.py	(revision 4d4dde4d8373b8156623629e3bb507e131c9f0b2)
@@ -6,4 +6,6 @@
 import random
 import copy
+
+import xml.parsers.expat
 
 from optparse import OptionParser, OptionValueError
@@ -28,5 +30,94 @@
 		",".join(self.provides), ",".join(self.accepts))
 
+    def to_xml(self):
+	rv = "<constraint>"
+	if isinstance(self.name, tuple):
+	    rv += "<name>%s</name>" % self.name[0]
+	else:
+	    rv += "<name>%s</name>" % self.name
+	rv += "<required>%s</required>" % self.required
+	for p in self.provides:
+	    rv += "<provides>%s</provides>" % p
+	for a in self.accepts:
+	    rv += "<accepts>%s</accepts>" % a
+	rv+= "</constraint>"
+	return rv
+
+def constraints_from_xml(string=None, file=None, filename=None, 
+	top="constraints"):
+    class parser:
+	def __init__(self, top):
+	    self.top = top
+	    self.constraints = [ ]
+	    self.chars = None
+	    self.current = None
+	    self.in_top = False
 	
+	def start_element(self, name, attrs):
+	    self.chars = None
+	    self.key = str(name)
+
+	    if name == self.top:
+		self.in_top = True
+
+	    if self.in_top:
+		if name == 'constraint':
+		    self.current = constraint()
+
+	def end_element(self, name):
+	    if self.current:
+		if self.chars is not None:
+		    self.chars = self.chars.strip()
+
+		if name == 'required':
+		    if self.chars is None:
+			self.current.required = False
+		    else:
+			self.current.required = (self.chars.lower() == 'true')
+		elif name == 'name':
+		    self.current.name = self.chars
+		elif name == 'accepts':
+		    self.current.accepts.append(self.chars)
+		elif name == 'provides':
+		    self.current.provides.append(self.chars)
+		elif name == 'constraint':
+		    self.constraints.append(self.current)
+		    self.current = None
+		else:
+		    print >>sys.stderr, \
+			    "Unexpected element in constraint: %s" % name
+	    elif name == self.top:
+		self.in_top = False
+
+
+	def char_data(self, data):
+	    if self.in_top:
+		if self.chars is None: self.chars = data
+		else: self.chars += data
+
+    p = parser(top=top)
+    xp = xml.parsers.expat.ParserCreate()
+
+    xp.StartElementHandler = p.start_element
+    xp.EndElementHandler = p.end_element
+    xp.CharacterDataHandler = p.char_data
+
+    if len([x for x in (string, filename, file) if x is not None])!= 1:
+	raise RuntimeError("Exactly one one of file, filename and string " + \
+		"must be set")
+    elif filename:
+	f = open(filename, "r")
+	xp.ParseFile(f)
+	f.close()
+    elif file:
+	xp.ParseFile(file)
+    elif string:
+	xp.Parse(string, isfinal=True)
+    else:
+	return []
+
+    return p.constraints
+
+
 class ComposeOptionParser(OptionParser):
     """
@@ -47,6 +138,7 @@
 	self.add_option('--output', dest='outfile', default=None,
 		help='Output file name')
-	self.add_option('--format', dest='format', default="xml",
-		help='Output file format')
+        self.add_option("--format", dest="format", type="choice", 
+                choices=("xml", "topdl", "tcl", "ns"),
+                help="Output file format")
 	self.add_option('--add_testbeds', dest='add_testbeds', default=False,
 		action='store_true',
@@ -311,29 +403,4 @@
     return marks
 
-def add_constraint_attributes(top, marks):
-    """
-    Take the constraints in marks and add attributes representing them to the
-    nodes in top.
-    """
-    for e in [e for e in top.elements if isinstance(e, topdl.Computer)]:
-	if e.name in marks and not e.get_attribute('composition_point'):
-	    c = marks[e.name]
-	    e.set_attribute('composition_point', 'true')
-	    e.set_attribute('required', '%s' % c.required)
-	    e.set_attribute('provides', ",".join(c.provides))
-	    e.set_attribute('accepts', ",".join(c.accepts))
-
-def remove_constraint_attributes(top, marks):
-    """
-    Remove constraint attributes that match the ones in the dict from the
-    topology.
-    """
-    for e in [e for e in top.elements \
-	    if isinstance(e, topdl.Computer) and e.name in marks]:
-	e.remove_attribute('composition_point')
-	e.remove_attribute('required')
-	e.remove_attribute('provides')
-	e.remove_attribute('accepts')
-
 def import_ns2_component(fn):
     """
@@ -353,5 +420,4 @@
     if not top:
 	raise RuntimeError("Cannot create topology from: %s" % fn)
-    add_constraint_attributes(top, marks)
 
     return (top, marks)
@@ -367,14 +433,6 @@
     """
     top = topdl.topology_from_xml(filename=fn, top='experiment')
-    marks = { }
-    for e in [ e for e in top.elements if isinstance(e, topdl.Computer)]:
-	if e.get_attribute('composition_point'):
-	    r = e.get_attribute('required') or 'false'
-	    a = e.get_attribute('accepts') 
-	    p = e.get_attribute('provides')
-	    if a and p:
-		c = constraint(name=e.name, required=(r == 'required'),
-		    provides=p.split(','), accepts=a.split(','))
-		marks[e.name] = c
+    cons = constraints_from_xml(filename=fn, top='constraints')
+    marks= dict([(c.name, c ) for c in cons])
     return (top, marks)
 
@@ -410,5 +468,11 @@
 	attributes should be in the topology.
 	"""
+	print >>f, "<component>"
+	print >>f, "<constraints>"
+	for c in constraints:
+	    print >>f, c.to_xml()
+	print >>f, "</constraints>"
 	print >>f, topdl.topology_to_xml(comp, top='experiment')
+	print >>f, "</component>"
 
     def ns2_out(f, top, constraints):
@@ -586,8 +650,5 @@
     connect_composition_points(comp, constraints, names)
 
-    # Remove composition attributes for satisfied constraints
-    remove_constraint_attributes(comp, dict(
-	[(c.name[0], c) for c in constraints if c.match]))
-elif topos == 1:
+elif components == 1:
     comp = topos[0]
     if opts.add_testbeds:
@@ -598,5 +659,5 @@
     sys.exit("Did not read any components.")
 
-# Put out the composition with only the unmatched constriaints
+# Put out the composition with only the unmatched constraints
 output_composition(comp, [c for c in constraints if not c.match], 
 	opts.outfile, opts.format)
