0

I'm about creating a java class for parsing and storing the content of a simple CSS stylesheet. This class will be used to paint a non-html object using the CSS selectors. My naive approach is to basically use a

Map<String,Map<String,Object>>

to store this stylesheet. Would it be any (clever) other way for storing this information ?

6
  • I don't really understand what you're trying to do. How do you "paint a non-html object using the CSS selectors"? What Strings and Objects would be in your Map? Commented Jul 27, 2009 at 14:09
  • with that approach, how would you quickly know what styles to apply to your current element? Commented Jul 27, 2009 at 14:10
  • 1
    @Michael: he is trying to use css to "skin" his ui. Commented Jul 27, 2009 at 14:11
  • non html: I want to draw a genetic map of the human genome. Genes related to a given disease/class would be green , etc... Color fill =(Color)map.get("disease").get("fill"); Commented Jul 27, 2009 at 14:12
  • 1
    Then it has nothing to do with "C"SS as you completely lost the cascading aspect with this approach. Commented Jul 27, 2009 at 14:23

7 Answers 7

4

the question of course is: why?

A CSS parser (at least a robust one) is non-trivial. You'd need to cater for things like imports, @media, browser-specific directives and so on. But I gather you're not after something that robust.

So what are you after?

Object is too general for the value too. Have some common base class and then subclasses to represent:

  • Single values (number plus optional units of measurement, including percentages);
  • Lists of strings (eg font-family);
  • Composite/complex values (such as border and background support);
  • URLs;
  • Enumerated values (eg collapse or separate for border-collapse); and
  • so on.

That is, assuming you want to validate the result.

Sign up to request clarification or add additional context in comments.

Comments

1

I would recommend something like:

Map<String, Map<String, CSSValue>>

Where CSSValue is an abstract class or interface that you will extend with things like CSSColor, CSSNumber, CSSString, CSSList<CSSValue>.

This will make your code much cleaner.

Comments

1

That is an extremely naive solution. Here are the flaws with it I can think of off the top of my head:

  • If you use String as for the CSS selector, it will be difficult to determine whether it is a valid selector for a given item. Better to wrap that functionality up in a class.
  • The built-in maps will only you give you one one matching element, but the very point of CSS is that you can cascade multiple styles that all apply to one element. You need a way to retrieve all matching styles.
  • Using Object is a bad idea. Create an interface or abstract class to extend all of your styles from. You'll have less type-casting and have the added benefit of being able to push down the shared functionality.

In all, I'd do something like CSSMap<CSSSelector, List<CSSStyle>>.

Comments

1

I don't think it makes sense to pretend you're using CSS; you're not. CSS selectors are much, much more complex that what you describe, and even if you could use a real CSS parser/matcher you'd probably run into a lot of open questions and contradictions trying to apply real CSS to your non-HTML data.

So what you want is a small subset of CSS-like functionality, i.e. only direct selectors. For that, your nested map structure is OK, though as Pesto and jjnguy said it would be better to go for more type safety.

The remaining question, which only you can answer is: does it really make sense to represent the styling information in a pseudo-CSS syntax that you'll have to write your own parser for? Who will write the styling information? Are they familiar with CSS? If yes, won't they be irritated at not being able to use more complex selectors? If no, why go through all the effort to make it look like CSS? Why not use something simpler like a properties file, or if you want more structure, something with existing parsers, like XML or JSON?

Comments

1

You're modelling this as a Map, but it's not a Map. You need a CSS object that contains (say) CSSSelectors and CSSStyles and all the surrounding functionality.

It will provide extra functionality such as determining how styles cascade. handling different measurements, validating inputs etc. All the functionality associated with CSS sheets would go in this object. Perhaps parsing a .css as part of it's construction (we'll get into discussions about factories if we're not careful).

The underlying implementation may involve a Map, but I think you need to think first about what this object is required to do.

If (however) you simply have a Map, then there's no additional functionality. Or rather, where does it go?

Comments

1

I did something similar on a small scale that was suitable for what I need to do at the time.

first I used enums for all the common style attributes I was interested in

example

private enum TextAlignment {

    LEFT,
    RIGHT,
    CENTER,
    JUSTIFY,
    NONE;
}  

private enum TextDecoration {
    BLINK,
    UNDERLYIN,
    OVERLINE,
    LINE_THROUGH,
    NONE;
}

I should have put this into a class hierarchy but for my purpose it wasn't necessary before formatting the tag I simply sent my formatter function a list of styles to apply to the tag.

A series of case statements then adds the style into the style element and returns the tag in html format back as a string.

private String tag(String tag ,String data, TextAlignment aline, boolean bold, Color bgColor, Color fgColor, boolean blink) {
    StringBuilder sb = new StringBuilder(data.length() + 128);
    sb.append("<");
    sb.append(tag); 
    sb.append(" style=\"");

    switch (aline) {
        case NONE:
            break;
        default:
            sb.append("text-align:");
            sb.append(aline.toString().toLowerCase());
            sb.append(";");
            break;

    }

    if (fgColor != null) {
        sb.append("color:");
        String rgb = Integer.toHexString(fgColor.getRGB());
        sb.append(rgb.substring(2, rgb.length()));
        sb.append(";");

    }

    if (bgColor != null) {
        sb.append("background-color:");
        String rgb = Integer.toHexString(bgColor.getRGB());
        sb.append(rgb.substring(2, rgb.length()));
        sb.append(";");
    }

..........

you get the idea

Comments

0

This should be quite enough if you: 1. plan on building up class hierarchy around your "Object", e.g. "Color", "BackgroundInformation" etc, since there is a lot of possibilites of what can appear on the right side 2. I think you should replace first "String" with some Object which is able to parse the CSS selectors and build up logic around it, similar to (1)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.