Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/KeyValuePair.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/KeyValuePair.java	(revision 14329)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/KeyValuePair.java	(revision 14329)
@@ -0,0 +1,62 @@
+package org.openstreetmap.josm.plugins.tageditor.tagspec;
+
+public class KeyValuePair {
+	private String key = new String("");
+	private String value = new String("");
+	
+	public KeyValuePair() {}
+	
+	public KeyValuePair(String key, String value) {
+		setKey(key);
+		setValue(value);
+	}
+
+	
+	public String getKey() {
+		return key;
+	}
+
+	public void setKey(String key) {
+		this.key = key == null? ""  :key;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value == null ? "" : value;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((key == null) ? 0 : key.hashCode());
+		result = prime * result + ((value == null) ? 0 : value.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		KeyValuePair other = (KeyValuePair) obj;
+		if (key == null) {
+			if (other.key != null)
+				return false;
+		} else if (!key.equals(other.key))
+			return false;
+		if (value == null) {
+			if (other.value != null)
+				return false;
+		} else if (!value.equals(other.value))
+			return false;
+		return true;
+	}
+
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/LableSpecification.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/LableSpecification.java	(revision 14329)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/LableSpecification.java	(revision 14329)
@@ -0,0 +1,72 @@
+package org.openstreetmap.josm.plugins.tageditor.tagspec;
+
+import org.openstreetmap.josm.plugins.tageditor.ac.AutoCompletionContext;
+
+public class LableSpecification {
+
+	/** the key of the tag */
+	private String value;
+		
+	
+	private boolean applicableToNode = true;
+	private boolean applicableToWay = true;
+	private boolean applicableToRelation = true;
+	
+	/**
+	 * constructor 
+	 */
+	public LableSpecification() {
+	}
+
+	public boolean isApplicable(AutoCompletionContext context) {
+		boolean ret = false;
+		if (context.isSelectionEmpty()) {
+			ret = true;
+		} else {
+			ret = ret || (applicableToNode && context.isSelectionIncludesNodes());
+			ret = ret || (applicableToWay && context.isSelectionIncludesWays());
+			ret = ret || (applicableToRelation && context.isSelectionIncludesRelations());
+		}
+		return ret;
+	}
+
+	/* --------------------------------------------------------------------------- */
+	/* setters/getters                                                             */
+	/* --------------------------------------------------------------------------- */
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
+
+	public boolean isApplicableToNode() {
+		return applicableToNode;
+	}
+
+	public void setApplicableToNode(boolean applicableToNode) {
+		this.applicableToNode = applicableToNode;
+	}
+
+	public boolean isApplicableToWay() {
+		return applicableToWay;
+	}
+
+	public void setApplicableToWay(boolean applicableToWay) {
+		this.applicableToWay = applicableToWay;
+	}
+
+	public boolean isApplicableToRelation() {
+		return applicableToRelation;
+	}
+
+	public void setApplicableToRelation(boolean applicableToRelation) {
+		this.applicableToRelation = applicableToRelation;
+	}
+	
+
+	
+	
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/TagSpecification.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/TagSpecification.java	(revision 14329)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/TagSpecification.java	(revision 14329)
@@ -0,0 +1,148 @@
+package org.openstreetmap.josm.plugins.tageditor.tagspec;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.plugins.tageditor.ac.AutoCompletionContext;
+
+
+/**
+ * A TagSpecifications specifies a tag. The specifications consists of the following
+ * elements: 
+ * <ul>
+ * 	 <li>the <strong>key</strong> the of the tag</li>
+ *   <li>the <strong>type</strong> of the tag</li>
+ *   <li>whether the tag is applicable to a node, a way or a relation</li> 
+ * </ul>
+ * @author Gubaer
+ *
+ */
+public class TagSpecification {
+	
+	/** the key of the tag */
+	private String key;
+	
+	/** the type of the tag */
+	private String type;
+	
+	/** the type of the tag */
+	
+	private boolean applicableToNode = true;
+	private boolean applicableToWay = true;
+	private boolean applicableToRelation = true;
+	
+	private ArrayList<LableSpecification> lables = null;
+	
+	
+	/**
+	 * constructor
+	 */
+	public TagSpecification() {
+		lables = new ArrayList<LableSpecification>();
+	}
+		
+	
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		builder.append("<TagSpecification ");
+		builder.append("key=\"").append(key).append("\"").append(", ");
+		builder.append("type=\"").append(type).append("\"").append(", ");
+		builder.append("applicable-to-node=\"").append(applicableToNode).append("\"").append(", ");
+		builder.append("applicable-to-way=\"").append(applicableToWay).append("\"").append(", ");
+		builder.append("applicable-to-relation=\"").append(applicableToRelation).append("\"");
+		builder.append(" />");
+		return builder.toString();
+	}
+	
+	/**
+	 * @return the list of predefined labels for this tag; an empty list if no
+	 *   labels are defined 
+	 */
+	public List<LableSpecification> getLables() {
+		return lables;
+	}
+	
+	
+	/**
+	 * sets the list of lables for this tag specification
+	 * 
+	 * @param lables  the list of lables; must not be null
+	 * @exception IllegalArgumentException thrown, if lables is null 
+	 */
+	public void setLables(List<LableSpecification> lables) throws IllegalArgumentException {
+		if (lables == null) {
+			throw new IllegalArgumentException("argument 'lables' must not be null");
+		}
+		this.lables.clear();
+		for (LableSpecification l : lables) {
+			this.lables.add(l);
+		}
+	}
+	
+	
+	/**
+	 * adds a lable to the list of lables for this tag specification. The lable
+	 * is only added if i
+	 *  
+	 * @param lable the lable to add; must not be null
+	 * @exception IllegalArgumentException thrown, if lable is null
+	 */
+	public void addLable(LableSpecification lable) throws IllegalArgumentException  {
+		if (lable == null) {
+			throw new IllegalArgumentException("argument 'lable' must not be null");
+		}
+		if (!this.lables.contains(lable)) {
+			this.lables.add(lable);
+		}
+	}
+	
+	public boolean isApplicable(AutoCompletionContext context) {
+		boolean ret = false;
+		if (context.isSelectionEmpty()) {
+			ret = true; 
+		} else {
+			ret = ret || (applicableToNode && context.isSelectionIncludesNodes());
+			ret = ret || (applicableToWay && context.isSelectionIncludesWays());
+			ret = ret || (applicableToRelation && context.isSelectionIncludesRelations());
+		}
+		return ret;
+	}
+	
+	/* --------------------------------------------------------------------------- */
+	/* setters/getters                                                             */
+	/* --------------------------------------------------------------------------- */
+	public String getKey() {
+		return key;
+	}
+	public void setKey(String key) {
+		this.key = key;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public boolean isApplicableToNode() {
+		return applicableToNode;
+	}
+	public void setApplicableToNode(boolean applicableToNode) {
+		this.applicableToNode = applicableToNode;
+	}
+	public boolean isApplicableToWay() {
+		return applicableToWay;
+	}
+	public void setApplicableToWay(boolean applicableToWay) {
+		this.applicableToWay = applicableToWay;
+	}
+	public boolean isApplicableToRelation() {
+		return applicableToRelation;
+	}
+	public void setApplicableToRelation(boolean applicableToRelation) {
+		this.applicableToRelation = applicableToRelation;
+	} 
+
+	
+	
+	
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/TagSpecifications.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/TagSpecifications.java	(revision 14329)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/TagSpecifications.java	(revision 14329)
@@ -0,0 +1,399 @@
+package org.openstreetmap.josm.plugins.tageditor.tagspec;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.openstreetmap.josm.plugins.tageditor.ac.AutoCompletionContext;
+import org.openstreetmap.josm.plugins.tageditor.ac.AutoCompletionItemPritority;
+import org.openstreetmap.josm.plugins.tageditor.ac.AutoCompletionListItem;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+
+/**
+ * This class manages a list of {@link TagSpecification}s.
+ * 
+ * It also provides a method for reading a list of {@link TagSpecification}s from
+ * an XML file.
+ * 
+ * @author Gubaer
+ *
+ */
+public class TagSpecifications {
+	
+	final static public String ATTR_KEY = "key";
+	final static public String ATTR_TYPE = "type";
+	final static public String ATTR_FOR_NODE = "for-node";
+	final static public String ATTR_FOR_WAY = "for-way";
+	final static public String ATTR_FOR_RELATION = "for-relation";
+	final static public String ATTR_VALUE = "value";
+
+	final static public String ELEM_ROOT = "osm-tag-definitions";
+	final static public String ELEM_TAG = "tag";
+	final static public String ELEM_LABEL = "label";
+	
+	final static public String DTD = "osm-tag-definitions.dtd";
+	
+	
+	/** the default name of the resource file with the  tag specifications */ 
+	static public final String RES_NAME_TAG_SPECIFICATIONS = "/resources/osm-tag-definitions.xml";
+	
+	/** the logger object */
+	private static Logger logger = Logger.getLogger(TagSpecification.class.getName());
+	
+	/** list of tag specifications managed list */
+	private ArrayList<TagSpecification> tagSpecifications = null;
+	
+	 
+	
+	private static TagSpecifications instance = null;
+	
+	/**
+	 * loads the the tag specifications from the resource file given by
+	 * {@link #RES_NAME_TAG_SPECIFICATIONS}. 
+	 * 
+	 * @return the list of {@link TagSpecification}s
+	 * @throws Exception thrown, if an exception occurs
+	 */
+	static public void loadFromResources() throws Exception  {
+		InputStream in = TagSpecifications.class.getResourceAsStream(RES_NAME_TAG_SPECIFICATIONS);
+		if (in == null) {
+			logger.log(Level.SEVERE, "failed to create input stream for resource '" + RES_NAME_TAG_SPECIFICATIONS + "'");
+		}
+		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+		TagSpecifications spec = new TagSpecifications();
+		spec.load(reader);
+		reader.close();
+		instance = spec;
+		
+	}
+	
+	static public TagSpecifications getInstance() throws Exception {
+		if (instance == null) {
+			loadFromResources();
+		}
+		return instance;
+	}
+	
+	/**
+	 * constructor 
+	 */
+	public TagSpecifications() {
+		tagSpecifications = new ArrayList<TagSpecification>();
+	}
+	
+	
+	/**
+	 * loads the tag specifications from a specific reader 
+	 * 
+	 * @param in  the reader to read from 
+	 * @throws Exception thrown, if an exception occurs 
+	 */
+	public void load(Reader in) throws Exception {
+		XMLReader parser;
+		
+		try {
+			parser = XMLReaderFactory.createXMLReader();
+			Handler handler = new Handler();
+			parser.setContentHandler(handler);
+			parser.setErrorHandler(handler);
+			parser.setEntityResolver(new ResourceEntityResolver());
+			parser.setFeature( "http://xml.org/sax/features/validation", true);
+			parser.setFeature("http://xml.org/sax/features/namespaces", true);
+			parser.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
+	        parser.parse(new InputSource(in));
+	        
+		} catch (Exception e) {
+			logger.log(Level.SEVERE, "failed to load tag specificatoin file", e);
+			throw e;
+		} finally {
+			parser = null;
+		}
+		
+		
+		
+	}
+
+	public List<AutoCompletionListItem> getKeysForAutoCompletion(AutoCompletionContext context) {
+		ArrayList<AutoCompletionListItem> keys = new ArrayList<AutoCompletionListItem>();
+		for (TagSpecification spec : tagSpecifications) {
+			if (!spec.isApplicable(context)) {
+				continue;
+			}
+			AutoCompletionListItem item = new AutoCompletionListItem();
+			item.setValue(spec.getKey());
+			item.setPriority(AutoCompletionItemPritority.IS_IN_STANDARD);
+			keys.add(item);
+		}
+		return keys;
+	}
+	
+	public List<AutoCompletionListItem> getLabelsForAutoCompletion(String forKey, AutoCompletionContext context) {
+		ArrayList<AutoCompletionListItem> items = new ArrayList<AutoCompletionListItem>();
+		for (TagSpecification spec : tagSpecifications) {
+			if (spec.getKey().equals(forKey)) {
+				List<LableSpecification> lables = spec.getLables();
+				for (LableSpecification l : lables) {
+					if (!l.isApplicable(context)) {
+						continue;
+					}
+					AutoCompletionListItem item = new AutoCompletionListItem();
+					item.setValue(l.getValue());
+					item.setPriority(AutoCompletionItemPritority.IS_IN_STANDARD);
+					items.add(item);
+				}
+			}
+		}
+		return items;
+	}
+	
+	
+	/**
+	 * replies a list of {@see KeyValuePair}s for all {@see TagSpecification}s and
+	 * {@see LableSpecification}s.
+	 * 
+	 * @return the list 
+	 */
+	public ArrayList<KeyValuePair> asList() {
+		ArrayList<KeyValuePair> entries = new ArrayList<KeyValuePair>();
+		
+		for (TagSpecification s : tagSpecifications) {
+			for (LableSpecification l : s.getLables()) {
+				entries.add(new KeyValuePair(s.getKey(), l.getValue()));
+			}
+		}
+		return entries; 
+	}
+	
+	
+	
+	/**
+	 * The SAX handler for reading XML files with tag specifications 
+	 * 
+	 * @author gubaer 
+	 *
+	 */
+	class Handler extends DefaultHandler {
+		
+		/**  the current tag specification. Not null, while parsing the content
+		 * between &lt;tag&gt; ... &lt;/tag&gt;
+		 */
+		private TagSpecification currentTagSpecification  = null;
+		
+		
+		@Override
+		public void endDocument() throws SAXException {
+			logger.log(Level.FINE,"END");
+		}
+
+		
+
+		@Override
+		public void error(SAXParseException e) throws SAXException {
+			logger.log(Level.SEVERE, "XML parsing error", e);
+		}
+
+		@Override
+		public void fatalError(SAXParseException e) throws SAXException {
+			logger.log(Level.SEVERE, "XML parsing error", e);
+		}
+
+		@Override
+		public void startDocument() throws SAXException {
+			logger.log(Level.FINE,"START");
+		}
+
+
+		/**
+		 * parses a string value consisting of 'yes' or 'no' (exactly, case
+		 * sensitive)
+		 *  
+		 * @param value the string value
+		 * @return true, if value is <code>yes</code>; false, if value is <code>no</code>
+		 * @throws SAXException thrown, if value is neither <code>yes</code> nor <code>no</code>
+		 */
+		protected boolean parseYesNo(String value) throws SAXException {
+			if ("yes".equals(value)) {
+				return true;
+			} else if ("no".equals(value)) {
+				return false; 
+			} else {
+				throw new SAXException("expected 'yes' or 'no' as attribute value, got '" + value + "'");
+			}
+		}
+		
+		/**
+		 * handles a start element with name <code>osm-tag-definitions</code>
+		 * 
+		 * @param atts  the XML attributes 
+		 * @throws SAXException   
+		 */
+		protected void startElementOsmTagDefinitions(Attributes atts) throws SAXException {
+			tagSpecifications = new ArrayList<TagSpecification>();
+		}
+		
+		/**
+		 * handles an end element with name <code>osm-tag-specifications</code>
+		 * 
+		 * @throws SAXException
+		 */
+		protected void endElementOsmTagDefinitions() throws SAXException {
+			// do nothing
+		}
+		
+		/**
+		 * handles a start element with name <code>tag</code> 
+		 * 
+		 * @param atts the XML attributes of the element 
+		 * @throws SAXException
+		 */
+		protected void startElementTag(Attributes atts) throws SAXException {
+			currentTagSpecification = new TagSpecification();
+			for (int i=0; i< atts.getLength(); i++) {
+				String name = atts.getQName(i);
+				String value = atts.getValue(i);
+				
+				if (ATTR_KEY.equals(name)) {
+					currentTagSpecification.setKey(value);
+				} else if (ATTR_TYPE.equals(name)) {	
+					currentTagSpecification.setType(value);
+				} else if (ATTR_FOR_NODE.equals(name)) {
+					currentTagSpecification.setApplicableToNode(parseYesNo(value));
+				} else if (ATTR_FOR_WAY.equals(name)) {
+					currentTagSpecification.setApplicableToWay(parseYesNo(value));
+				} else if (ATTR_FOR_RELATION.equals(name)) {
+					currentTagSpecification.setApplicableToRelation(parseYesNo(value));
+				} else {
+					throw new SAXException("unknown attribut '" + name + "' on element 'tag'");
+				}				
+			}
+		}
+		
+		
+		/**
+		 * handles an end element with name <code>tag</code> 
+		 * @throws SAXException
+		 */
+		protected void endElementTag() throws SAXException {
+			tagSpecifications.add(currentTagSpecification);
+			currentTagSpecification = null;
+			
+		}
+		
+		
+		/**
+		 * handles a start element with name <code>label</code> 
+		 * 
+		 * @param atts the XML attributes 
+		 * @throws SAXException
+		 */
+		protected void startElementLabel(Attributes atts) throws SAXException {
+			LableSpecification ls = new LableSpecification(); 
+			for (int i=0; i< atts.getLength(); i++) {
+				String name = atts.getQName(i);
+				String value = atts.getValue(i);
+				
+				if (ATTR_VALUE.equals(name)) {
+					ls.setValue(value);
+				} else if (ATTR_FOR_NODE.equals(name)) {
+					ls.setApplicableToNode(parseYesNo(value));
+				} else if (ATTR_FOR_WAY.equals(name)) {
+					ls.setApplicableToWay(parseYesNo(value));
+				} else if (ATTR_FOR_RELATION.equals(name)) {
+					ls.setApplicableToRelation(parseYesNo(value));
+				} else {
+					throw new SAXException("unknown attribut '" + name + "' on element 'lable'");
+				}				
+			}
+			currentTagSpecification.addLable(ls);
+		}
+		
+		/**
+		 * handles an end element with name <code>label</code>
+		 * 
+		 * @throws SAXException
+		 */
+		protected void endElementLabel() throws SAXException {
+			// do nothing 
+		}
+		
+		@Override
+		public void startElement(String namespaceURI, String localName, String qName,
+				Attributes atts) throws SAXException {
+			if (ELEM_ROOT.equals(qName)) {
+				startElementOsmTagDefinitions(atts);
+			} else if (ELEM_TAG.equals(qName)) {
+				startElementTag(atts);
+			} else if (ELEM_LABEL.equals(qName)) {
+				startElementLabel(atts);
+			} else {
+				throw new SAXException("unknown element '" + qName + "'");
+			}
+		}
+		
+		@Override
+		public void endElement(String namespaceURI, String localName, String qName)
+				throws SAXException {
+			if (ELEM_ROOT.equals(qName)) {
+				endElementOsmTagDefinitions();
+			} else if (ELEM_TAG.equals(qName)) {
+				endElementTag();
+			} else if (ELEM_LABEL.equals(qName)) {
+				endElementLabel();
+			} else {
+				throw new SAXException("unknown element '" + qName + "'");
+			}
+		}
+
+		@Override
+		public void warning(SAXParseException e) throws SAXException {
+			// TODO Auto-generated method stub
+			logger.log(Level.WARNING, "XML parsing warning", e);
+		}
+		
+		
+		
+	}
+	
+	
+	/**
+	 *
+	 *
+	 */
+	class ResourceEntityResolver implements EntityResolver {
+
+		@Override
+		public InputSource resolveEntity(String publicId, String systemId)
+				throws SAXException, IOException {
+			if (systemId != null && systemId.endsWith(DTD)) {
+				return new InputSource(
+						TagSpecifications.class.getResourceAsStream(DTD)
+				);
+			} else {
+				throw new SAXException("couldn't load external DTD '" + systemId + "'");
+			}
+		}
+		
+	}
+	
+	
+	static public void main(String args[]) throws Exception{
+		TagSpecifications.loadFromResources();
+	}
+	
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/osm-tag-definitions.dtd
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/osm-tag-definitions.dtd	(revision 14329)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/tagspec/osm-tag-definitions.dtd	(revision 14329)
@@ -0,0 +1,20 @@
+<!ELEMENT osm-tag-definitions (tag*)>
+<!ATTLIST osm-tag-definitions
+     version CDATA #FIXED '0.9'
+     xmlns:xs CDATA #FIXED 'http://www.w3.org/2001/XMLSchema-datatypes'
+>
+<!ELEMENT tag (label*) >
+<!ATTLIST tag
+     key CDATA #REQUIRED
+     type CDATA #REQUIRED
+     for-way (yes|no) 'no' 
+     for-node (yes|no) 'no' 
+     for-relation (yes|no) 'no'
+>
+<!ELEMENT label EMPTY>
+<!ATTLIST label
+     value CDATA #REQUIRED 
+     for-way (yes|no) 'no' 
+     for-node (yes|no) 'no' 
+     for-relation (yes|no) 'no'
+>
