001    package org.whattf.checker;
002    
003    
004    import java.util.LinkedList;
005    import java.util.List;
006    import java.util.regex.Matcher;
007    import java.util.regex.Pattern;
008    
009    /**
010     * Static utilities for working with (X)HTML5 attribute values.
011     * 
012     * @version $Id: AttributeUtil.java 169 2007-05-25 07:21:55Z hsivonen $
013     * @author hsivonen
014     */
015    public class AttributeUtil {
016    
017        /**
018         * An empty string array instance.
019         */
020        private final static String[] EMPTY_STRING_ARRAY = {};
021    
022        /**
023         * The pattern for extracting an integer by skipping white space and ignoring 
024         * trailing garbage.
025         */
026        private static Pattern INTEGER_PATTERN = Pattern.compile("^[ \t\n\r]*(-?[0-9]+)");
027    
028        /**
029         * Private constructor to prevent instantiation.
030         */
031        private AttributeUtil() {
032            super();
033        }
034    
035        /**
036         * Returns the integer represented by <code>attrVal</code> or 
037         * <code>Integer.MIN_VALUE</code> on error.
038         * 
039         * @param attrVal a string representing an integer attribute 
040         * value (can be <code>null</code>)
041         * @return the integer represented by <code>attrVal</code> or 
042         * <code>Integer.MIN_VALUE</code> on error
043         */
044        public static int parseInteger(String attrVal) {
045            if (attrVal == null) {
046                return Integer.MIN_VALUE;
047            }
048            Matcher m = INTEGER_PATTERN.matcher(attrVal);
049            if (!m.matches()) {
050                return Integer.MIN_VALUE;
051            }
052            try {
053                return Integer.parseInt(m.group(1));
054            } catch (NumberFormatException e) {
055                return Integer.MIN_VALUE;
056            }
057        }
058    
059        /**
060         * Returns the non-negative integer represented by 
061         * <code>attrVal</code> or -1 on error.
062         * 
063         * @param attrVal a string representing a non-negative 
064         * integer attribute value (can be <code>null</code>)
065         * @return the integer represented by <code>attrVal</code> or 
066         * -1 on error
067         */
068        public static int parseNonNegativeInteger(String attrVal) {
069            int rv = parseInteger(attrVal);
070            if (rv < 0) {
071                return -1;
072            } else {
073                return rv;
074            }
075        }
076    
077        /**
078         * Returns the positive integer represented by 
079         * <code>attrVal</code> or -1 on error.
080         * 
081         * @param attrVal a string representing a positive 
082         * integer attribute value (can be <code>null</code>)
083         * @return the integer represented by <code>attrVal</code> or 
084         * -1 on error
085         */
086        public static int parsePositiveInteger(String attrVal) {
087            int rv = parseInteger(attrVal);
088            if (rv < 1) {
089                return -1;
090            } else {
091                return rv;
092            }
093        }
094    
095        /**
096         * Splits the argument on white space.
097         * 
098         * @param value the attribute value
099         * @return a string array with zero or more strings none of which 
100         * is the empty string and none of which contains white space characters.
101         */
102        public static String[] split(String value) {
103            if (value == null || "".equals(value)) {
104                return EMPTY_STRING_ARRAY;
105            }
106            int len = value.length();
107            List<String> list = new LinkedList<String>();
108            boolean collectingSpace = true;
109            int start = 0;
110            for (int i = 0; i < len; i++) {
111                char c = value.charAt(i);
112                if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
113                    if (!collectingSpace) {
114                        list.add(value.substring(start, i));
115                        collectingSpace = true;
116                    }
117                } else {
118                    if (collectingSpace) {
119                        start = i;
120                        collectingSpace = false;
121                    }
122                }
123            }
124            if (start < len) {
125                list.add(value.substring(start, len));
126            }
127            return list.toArray(EMPTY_STRING_ARRAY);
128        }
129    
130    }