Index: /trunk/data/preferences.xsd
===================================================================
--- /trunk/data/preferences.xsd	(revision 3938)
+++ /trunk/data/preferences.xsd	(revision 3938)
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://josm.openstreetmap.de/preferences-1.0"
+	xmlns:tns="http://josm.openstreetmap.de/preferences-1.0" elementFormDefault="qualified">
+
+	<element name="preferences" type="tns:root"/>
+
+	<complexType name="root">
+		<sequence>
+			<choice minOccurs="0" maxOccurs="unbounded">
+				<element name="tag" type="tns:tag" />
+				<element name="collection" type="tns:collection" />
+			</choice>
+		</sequence>
+	</complexType>
+
+	<complexType name="tag">
+		<attribute name="key" type="string" use="required" />
+		<attribute name="value" type="string" use="required"/>
+	</complexType>
+
+	<complexType name="collection">
+		<sequence>
+			<choice minOccurs="1" maxOccurs="unbounded">
+				<element name="entry" type="tns:entry" />
+			</choice>
+		</sequence>
+		<attribute name="key" type="string" use="required" />
+	</complexType>
+
+	<complexType name="entry">
+		<attribute name="value" type="string" use="required"/>
+	</complexType>
+</schema>
Index: /trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 3937)
+++ /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 3938)
@@ -13,4 +13,5 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.io.Reader;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -32,7 +33,10 @@
 import javax.swing.JOptionPane;
 
+import org.openstreetmap.josm.io.XmlWriter;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlObjectParser;
+import org.xml.sax.SAXException;
 
 /**
@@ -884,5 +888,5 @@
             } else
                 throw new RuntimeException("unsupported preference primitive type");
-            
+
             try {
                 f.set(struct, value);
@@ -909,5 +913,6 @@
      * The default plugin site
      */
-    private final static String[] DEFAULT_PLUGIN_SITE = {"http://josm.openstreetmap.de/plugin%<?plugins=>"};
+    private final static String[] DEFAULT_PLUGIN_SITE = {
+        "http://josm.openstreetmap.de/plugin%<?plugins=>"};
 
     /**
@@ -928,3 +933,69 @@
         putCollection("pluginmanager.sites", sites);
     }
+
+    public static class XMLTag {
+        public String key;
+        public String value;
+    }
+    public static class XMLCollection {
+        public String key;
+    }
+    public static class XMLEntry {
+        public String value;
+    }
+    public void fromXML(Reader in) throws SAXException {
+        XmlObjectParser parser = new XmlObjectParser();
+        parser.map("tag", XMLTag.class);
+        parser.map("entry", XMLEntry.class);
+        parser.map("collection", XMLCollection.class);
+        parser.startWithValidation(in,
+        "http://josm.openstreetmap.de/preferences-1.0", "resource://data/preferences.xsd");
+        LinkedList<String> vals = new LinkedList<String>();
+        while(parser.hasNext()) {
+            Object o = parser.next();
+            if(o instanceof XMLTag) {
+                properties.put(((XMLTag)o).key, ((XMLTag)o).value);
+            } else if (o instanceof XMLEntry) {
+                vals.add(((XMLEntry)o).value);
+            } else if (o instanceof XMLCollection) {
+                properties.put(((XMLCollection)o).key, Utils.join("\u001e", vals));
+                vals = new LinkedList<String>();
+            }
+        }
+    }
+
+    public String toXML(boolean nopass) {
+        StringBuilder b = new StringBuilder(
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+        "<preferences xmlns=\"http://josm.openstreetmap.de/preferences-1.0\">\n");
+        for (Entry<String, String> p : properties.entrySet()) {
+            if (nopass && p.getKey().equals("osm-server.password")) {
+                continue; // do not store plain password.
+            }
+            String r = p.getValue();
+            if(r.contains("\u001e"))
+            {
+                b.append(" <collection key='");
+                b.append(XmlWriter.encode(p.getKey()));
+                b.append("'>\n");
+                for (String val : r.split("\u001e", -1))
+                {
+                    b.append("  <entry value='");
+                    b.append(XmlWriter.encode(val));
+                    b.append("' />\n");
+                }
+                b.append(" </collection>\n");
+            }
+            else
+            {
+                b.append(" <tag key='");
+                b.append(XmlWriter.encode(p.getKey()));
+                b.append("' value='");
+                b.append(XmlWriter.encode(p.getValue()));
+                b.append("' />\n");
+            }
+        }
+        b.append("</preferences>");
+        return b.toString();
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java	(revision 3937)
+++ /trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java	(revision 3938)
@@ -27,7 +27,6 @@
 import org.openstreetmap.josm.io.OsmConnection;
 import org.openstreetmap.josm.io.OsmTransferException;
-import org.openstreetmap.josm.io.XmlWriter;
 import org.openstreetmap.josm.tools.Base64;
-import org.openstreetmap.josm.tools.XmlObjectParser;
+import org.xml.sax.SAXException;
 
 /**
@@ -152,9 +151,4 @@
     }
 
-    public static class Prop {
-        public String key;
-        public String value;
-    }
-
     public void download(String userName, String password) {
         if (!properties.containsKey("applet.username") && userName != null) {
@@ -177,11 +171,8 @@
         boolean res = false;
         try {
-            /* TODO: parse collection! */
-            XmlObjectParser.Uniform<Prop> parser = new XmlObjectParser.Uniform<Prop>(in, "tag", Prop.class);
-            for (Prop p : parser) {
-                res = true;
-                properties.put(p.key, p.value);
-            }
+            fromXML(in);
         } catch (RuntimeException e) {
+            e.printStackTrace();
+        } catch (SAXException e) {
             e.printStackTrace();
         }
@@ -196,33 +187,5 @@
      */
     public void upload() {
-        StringBuilder b = new StringBuilder("<preferences>\n");
-        for (Entry<String, String> p : properties.entrySet()) {
-            if (p.getKey().equals("osm-server.password")) {
-                continue; // do not upload password. It would get stored in plain!
-            }
-            String r = p.getValue();
-            if(r.contains("\u001e"))
-            {
-                b.append("<collection key='");
-                b.append(XmlWriter.encode(p.getKey()));
-                b.append(">\n");
-                for (String val : r.split("\u001e", -1))
-                {
-                    b.append("  <entry value='");
-                    b.append(XmlWriter.encode(val));
-                    b.append("' />\n");
-                }
-            }
-            else
-            {
-                b.append("<tag key='");
-                b.append(XmlWriter.encode(p.getKey()));
-                b.append("' value='");
-                b.append(XmlWriter.encode(p.getValue()));
-                b.append("' />\n");
-            }
-        }
-        b.append("</preferences>");
-        connection.upload(b.toString());
+        connection.upload(toXML(true));
     }
 }
