001: /*
002: * XML input/output support for FindBugs
003: * Copyright (C) 2004, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.xml;
021:
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.List;
025:
026: import edu.umd.cs.findbugs.annotations.CheckForNull;
027: import edu.umd.cs.findbugs.annotations.NonNull;
028:
029: /**
030: * Helper class to format attributes in an XML tag.
031: *
032: * @author David Hovemeyer
033: */
034: public class XMLAttributeList {
035: public static class NameValuePair {
036: private String name;
037: private String value;
038:
039: public NameValuePair(String name, String value) {
040: this .name = name;
041: this .value = value;
042: }
043:
044: public String getName() {
045: return name;
046: }
047:
048: public String getValue() {
049: return value;
050: }
051: }
052:
053: private static class StringBufferQuoteMetaCharacters extends
054: QuoteMetaCharacters {
055: private StringBuffer buf;
056:
057: public StringBufferQuoteMetaCharacters(String text,
058: MetaCharacterMap map, StringBuffer buf) {
059: super (text, map);
060: this .buf = buf;
061: }
062:
063: @Override
064: public void process() {
065: try {
066: super .process();
067: } catch (java.io.IOException e) {
068: // This can't actually happen - we're writing to a StringBuffer
069: }
070: }
071:
072: @Override
073: public void emitLiteral(String s) {
074: buf.append(s);
075: }
076: }
077:
078: // The "<", ">", and "&" must be escaped in
079: // attribute values. I have no idea why this is useful,
080: // but that's standards for you.
081: private static final MetaCharacterMap attrMetaCharacterMap = new MetaCharacterMap();
082: static {
083: attrMetaCharacterMap.addMeta('<', "<");
084: attrMetaCharacterMap.addMeta('>', ">");
085: attrMetaCharacterMap.addMeta('&', "&");
086: attrMetaCharacterMap.addMeta('"', """);
087: }
088:
089: // Fields
090: private List<NameValuePair> nameValuePairList;
091:
092: /**
093: * Constructor.
094: * Creates an empty object.
095: */
096: public XMLAttributeList() {
097: this .nameValuePairList = new LinkedList<NameValuePair>();
098: }
099:
100: /**
101: * Add a single attribute name and value.
102: *
103: * @param name the attribute name
104: * @param value the attribute value
105: * @return this object (so calls to addAttribute() can be chained)
106: */
107: public XMLAttributeList addAttribute(@NonNull
108: String name, @NonNull
109: String value) {
110: if (name == null)
111: throw new NullPointerException("name must be nonnull");
112: if (value == null)
113: throw new NullPointerException("value must be nonnull");
114: nameValuePairList.add(new NameValuePair(name, value));
115: return this ;
116: }
117:
118: /**
119: * Add a single attribute name and value.
120: *
121: * @param name the attribute name
122: * @param value the attribute value
123: * @return this object (so calls to addAttribute() can be chained)
124: */
125: public XMLAttributeList addOptionalAttribute(@NonNull
126: String name, @CheckForNull
127: String value) {
128: if (value == null)
129: return this ;
130: return addAttribute(name, value);
131: }
132:
133: /**
134: * Return the attribute list as a String which can be
135: * directly output as part of an XML tag.
136: */
137: @Override
138: public String toString() {
139: StringBuffer buf = new StringBuffer();
140: for (NameValuePair pair : nameValuePairList) {
141: buf.append(' ');
142: buf.append(pair.getName());
143: buf.append('=');
144: buf.append(getQuotedAttributeValue(pair.getValue()));
145: }
146: return buf.toString();
147: }
148:
149: /**
150: * Return an Iterator over NameValuePairs.
151: */
152: public Iterator<NameValuePair> iterator() {
153: return nameValuePairList.iterator();
154: }
155:
156: /**
157: * Return a properly quoted form for an attribute value.
158: * @param rawValue the raw value of the attribute
159: * @return a properly quoted representation of the value
160: */
161: public static String getQuotedAttributeValue(@NonNull
162: String rawValue) {
163: if (rawValue == null)
164: throw new NullPointerException("rawValue must be nonnull");
165: StringBuffer buf = new StringBuffer();
166: buf.append('"');
167: new StringBufferQuoteMetaCharacters(rawValue,
168: attrMetaCharacterMap, buf).process();
169: buf.append('"');
170: return buf.toString();
171: }
172: }
173:
174: // vim:ts=4
|