001 /*
002 * Copyright (c) 2006 Henri Sivonen
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a
005 * copy of this software and associated documentation files (the "Software"),
006 * to deal in the Software without restriction, including without limitation
007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
008 * and/or sell copies of the Software, and to permit persons to whom the
009 * Software is furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
017 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020 * DEALINGS IN THE SOFTWARE.
021 */
022
023 package fi.iki.hsivonen.xml;
024
025 import java.util.LinkedList;
026 import java.util.List;
027 import java.util.regex.Matcher;
028 import java.util.regex.Pattern;
029
030 /**
031 * Static utilities for working with (X)HTML5 attribute values.
032 *
033 * @version $Id: AttributeUtil.java,v 1.4 2006/11/29 18:13:33 hsivonen Exp $
034 * @author hsivonen
035 */
036 public class AttributeUtil {
037
038 /**
039 * An empty string array instance.
040 */
041 private final static String[] EMPTY_STRING_ARRAY = {};
042
043 /**
044 * The pattern for extracting an integer by skipping white space and ignoring
045 * trailing garbage.
046 */
047 private static Pattern INTEGER_PATTERN = Pattern.compile("^[ \t\n\r]*(-?[0-9]+)");
048
049 /**
050 * Private constructor to prevent instantiation.
051 */
052 private AttributeUtil() {
053 super();
054 }
055
056 /**
057 * Returns the integer represented by <code>attrVal</code> or
058 * <code>Integer.MIN_VALUE</code> on error.
059 *
060 * @param attrVal a string representing an integer attribute
061 * value (can be <code>null</code>)
062 * @return the integer represented by <code>attrVal</code> or
063 * <code>Integer.MIN_VALUE</code> on error
064 */
065 public static int parseInteger(String attrVal) {
066 if (attrVal == null) {
067 return Integer.MIN_VALUE;
068 }
069 Matcher m = INTEGER_PATTERN.matcher(attrVal);
070 if (!m.matches()) {
071 return Integer.MIN_VALUE;
072 }
073 try {
074 return Integer.parseInt(m.group(1));
075 } catch (NumberFormatException e) {
076 return Integer.MIN_VALUE;
077 }
078 }
079
080 /**
081 * Returns the non-negative integer represented by
082 * <code>attrVal</code> or -1 on error.
083 *
084 * @param attrVal a string representing a non-negative
085 * integer attribute value (can be <code>null</code>)
086 * @return the integer represented by <code>attrVal</code> or
087 * -1 on error
088 */
089 public static int parseNonNegativeInteger(String attrVal) {
090 int rv = parseInteger(attrVal);
091 if (rv < 0) {
092 return -1;
093 } else {
094 return rv;
095 }
096 }
097
098 /**
099 * Returns the positive integer represented by
100 * <code>attrVal</code> or -1 on error.
101 *
102 * @param attrVal a string representing a positive
103 * integer attribute value (can be <code>null</code>)
104 * @return the integer represented by <code>attrVal</code> or
105 * -1 on error
106 */
107 public static int parsePositiveInteger(String attrVal) {
108 int rv = parseInteger(attrVal);
109 if (rv < 1) {
110 return -1;
111 } else {
112 return rv;
113 }
114 }
115
116 /**
117 * Splits the argument on white space.
118 *
119 * @param value the attribute value
120 * @return a string array with zero or more strings none of which
121 * is the empty string and none of which contains white space characters.
122 */
123 public static String[] split(String value) {
124 if (value == null || "".equals(value)) {
125 return EMPTY_STRING_ARRAY;
126 }
127 int len = value.length();
128 List<String> list = new LinkedList<String>();
129 boolean collectingSpace = true;
130 int start = 0;
131 for (int i = 0; i < len; i++) {
132 char c = value.charAt(i);
133 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
134 if (!collectingSpace) {
135 list.add(value.substring(start, i));
136 collectingSpace = true;
137 }
138 } else {
139 if (collectingSpace) {
140 start = i;
141 collectingSpace = false;
142 }
143 }
144 }
145 if (start < len) {
146 list.add(value.substring(start, len));
147 }
148 return list.toArray(EMPTY_STRING_ARRAY);
149 }
150
151 }