001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import org.openstreetmap.josm.tools.CheckParameterUtil;
005import org.openstreetmap.josm.tools.Utils;
006
007/**
008 * Tag represents an immutable key/value-pair. Both the key and the value may
009 * be empty, but not null.
010 *
011 */
012public class Tag {
013
014    private String key;
015    private String value;
016
017    /**
018     * Create an empty tag whose key and value are empty.
019     */
020    public Tag() {
021        this("", "");
022    }
023
024    /**
025     * Create a tag whose key is <code>key</code> and whose value is
026     * empty.
027     *
028     * @param key the key. If null, it is set to the empty key.
029     */
030    public Tag(String key) {
031        this(key, "");
032    }
033
034    /**
035     * Creates a tag for a key and a value. If key and/or value are null,
036     * the empty value "" is assumed.
037     *
038     * @param key the key
039     * @param value  the value
040     */
041    public Tag(String key, String value) {
042        this.key = key == null ? "" : key;
043        this.value = value == null ? "" : value;
044    }
045
046    /**
047     * Creates clone of the tag <code>tag</code>.
048     *
049     * @param tag the tag.
050     */
051    public Tag(Tag tag) {
052        this(tag.getKey(), tag.getValue());
053    }
054
055    /**
056     * Replies the key of the tag. This is never null.
057     *
058     * @return the key of the tag
059     */
060    public String getKey() {
061        return key;
062    }
063
064    /**
065     * Replies the value of the tag. This is never null.
066     *
067     * @return the value of the tag
068     */
069    public String getValue() {
070        return value;
071    }
072
073    /**
074     * Replies true if the key of this tag is equal to <code>key</code>.
075     * If <code>key</code> is null, assumes the empty key.
076     *
077     * @param key the key
078     * @return true if the key of this tag is equal to <code>key</code>
079     */
080    public boolean matchesKey(String key) {
081        return this.key.equals(key);
082    }
083
084    @Override
085    public int hashCode() {
086        final int prime = 31;
087        int result = 1;
088        result = prime * result + key.hashCode();
089        result = prime * result + value.hashCode();
090        return result;
091    }
092
093    @Override
094    public boolean equals(Object obj) {
095        if (obj instanceof Tag) {
096            Tag other = (Tag) obj;
097            return key.equals(other.getKey()) && value.equals(other.getValue());
098        } else
099            return false;
100    }
101
102    /**
103     * This constructs a {@link Tag} by splitting {@code s} on the first equality sign.
104     * @see org.openstreetmap.josm.tools.TextTagParser
105     * @param s the string to convert
106     * @return the constructed tag
107     */
108    public static Tag ofString(String s) {
109        CheckParameterUtil.ensureParameterNotNull(s, "s");
110        final String[] x = s.split("=", 2);
111        if (x.length == 2) {
112            return new Tag(x[0], x[1]);
113        } else {
114            throw new IllegalArgumentException("'" + s + "' does not contain '='");
115        }
116    }
117
118    @Override
119    public String toString() {
120        return key + "=" + value;
121    }
122
123    /**
124     * Removes leading, trailing, and multiple inner whitespaces from the given string, to be used as a key or value.
125     * @param s The string
126     * @return The string without leading, trailing or multiple inner whitespaces
127     * @since 6699
128     */
129    public static String removeWhiteSpaces(String s) {
130        if (s == null || s.isEmpty()) {
131            return s;
132        }
133        return Utils.strip(s).replaceAll("\\s+", " ");
134    }
135}