package folioxml.css; import folioxml.core.Pair; import java.util.*; import java.util.Map.Entry; import java.util.regex.Pattern; public class CssUtils { /** * Jan 20, 09. Can't use posessive quantifiers here - sorry. */ public static String CommentRegex = "\\/\\*(.*?)\\*\\/"; /** * Matches a comment tag and any intermediate comments. Lazy, of course. */ private static Pattern rComment = Pattern.compile(CommentRegex, Pattern.DOTALL | Pattern.CASE_INSENSITIVE); public static Map<String, String> parseCss(String css, boolean expandBorderPaddingToParts) { HashMap<String, String> map = new HashMap<String, String>(); if (css == null) return map; //Empty css //Strip all comments css = rComment.matcher(css).replaceAll(" "); //Split into pairs (watch for escapes!) String[] pairs = css.split("(?!\\\\);"); for (String s : pairs) { s = s.trim(); if (s.length() == 0) continue; String[] parts = s.split("(?!\\\\):"); assert (parts.length == 2) : s; //Or we have invalid syntax. String key = parts[0].trim().toLowerCase(Locale.ENGLISH); String value = parts[1].trim(); if (expandBorderPaddingToParts && (key.equalsIgnoreCase("border") || key.equalsIgnoreCase("padding"))) { map.put(key + "-top", value); map.put(key + "-left", value); map.put(key + "-right", value); map.put(key + "-bottom", value); } else { map.put(key, value); } } return map; } public static List<Pair<String, String>> parseCssAsList(String css, boolean expandBorderPaddingToParts) { List<Pair<String, String>> pairs = new ArrayList<Pair<String, String>>(); if (css == null) return pairs; //Empty css //Strip all comments css = rComment.matcher(css).replaceAll(" "); //Split into pairs (watch for escapes!) String[] spairs = css.split("(?!\\\\);"); for (String s : spairs) { s = s.trim(); if (s.length() == 0) continue; String[] parts = s.split("(?!\\\\):"); assert (parts.length == 2) : s; //Or we have invalid syntax. String key = parts[0].trim().toLowerCase(Locale.ENGLISH); String value = parts[1].trim(); if (expandBorderPaddingToParts && (key.equalsIgnoreCase("border") || key.equalsIgnoreCase("padding"))) { pairs.add(new Pair<String, String>(key + "-top", value)); pairs.add(new Pair<String, String>(key + "-left", value)); pairs.add(new Pair<String, String>(key + "-right", value)); pairs.add(new Pair<String, String>(key + "-bottom", value)); } else { pairs.add(new Pair<String, String>(key, value)); } } return pairs; } /** * Combines matching padding-left,-right,-top, -bottom elements into a single pair. (Also handles border and margin). * Leaves them expaned if they * * @param map */ public static void coalesce(Map<String, String> map) { String[] names = new String[]{"border", "margin", "padding"}; String[] sides = new String[]{"-left", "-top", "-bottom", "-right"}; for (String name : names) { String shared = null; for (String side : sides) { String val = map.get(name + side); if (val == null) { shared = null; break; }//All sides must be non-null if (shared == null) shared = val; //First item must init the checker if (!val.equalsIgnoreCase(shared)) { shared = null; break; //They don't all match - quit for this name. } } if (shared != null) { if (map.containsKey(name) && !map.get(name).equalsIgnoreCase(shared)) { //The generic one already exists. skip name continue; } //Clean out the indiviudal mappings for (String side : sides) { map.remove(name + side); } //Add the generic mapping map.put(name, shared); } } } public static String writeCss(Map<String, String> map) { StringBuilder sb = new StringBuilder(); for (Entry<String, String> pair : map.entrySet()) { sb.append(pair.getKey() + ":" + pair.getValue() + ";"); } return sb.toString(); } }