35

I'm looking for a CSS Parser in java. In particular my requirement is, for a given node/element in an HTML document, to be able to ask/get the css styles for that element from the Parser.

I know there is the W3C SAC interface and one or 2 implementations based on this - but turorials/examples appear non-existant.

Any help/points in right direction much appreciated.

Thanks

2
  • 5
    Take a look at - cssparser.sourceforge.net Commented Oct 3, 2009 at 12:43
  • 1
    @adatapost: Repost your reply as an "answer" instead of a "comment" Commented Oct 5, 2009 at 4:38

8 Answers 8

17

I've used CSSParser and I like it- it gives good feedback on errors as well.

Here's some sample code I've found and modified:

package com.dlogic;

import com.steadystate.css.parser.CSSOMParser;
import org.w3c.css.sac.InputSource;
import org.w3c.dom.css.CSSStyleSheet;
import org.w3c.dom.css.CSSRuleList;
import org.w3c.dom.css.CSSRule;
import org.w3c.dom.css.CSSStyleRule;
import org.w3c.dom.css.CSSStyleDeclaration;
import java.io.*;


public class CSSParserTest 
{

    protected static CSSParserTest oParser;

    public static void main(String[] args) {

            oParser = new CSSParserTest();

            if (oParser.Parse("design.css")) {

                System.out.println("Parsing completed OK");

            } else {

                System.out.println("Unable to parse CSS");

            }   
    }


     public boolean Parse(String cssfile) 
     {

         FileOutputStream out = null; 
         PrintStream ps = null; 
         boolean rtn = false;

         try
         {

                // cssfile accessed as a resource, so must be in the pkg (in src dir).
                InputStream stream = oParser.getClass().getResourceAsStream(cssfile);

                 // overwrites and existing file contents
                 out = new FileOutputStream("log.txt");

                 if (out != null)
                 {
                     //log file
                     ps = new PrintStream( out );
                     System.setErr(ps); //redirects stderr to the log file as well

                 } else {

                     return rtn; 

                }


                InputSource source = new InputSource(new InputStreamReader(stream));
                CSSOMParser parser = new CSSOMParser();
                // parse and create a stylesheet composition
                CSSStyleSheet stylesheet = parser.parseStyleSheet(source, null, null);

                //ANY ERRORS IN THE DOM WILL BE SENT TO STDERR HERE!!
                // now iterate through the dom and inspect.

                CSSRuleList ruleList = stylesheet.getCssRules();

                ps.println("Number of rules: " + ruleList.getLength());


               for (int i = 0; i < ruleList.getLength(); i++) 
               {
                 CSSRule rule = ruleList.item(i);
                 if (rule instanceof CSSStyleRule) 
                 {
                     CSSStyleRule styleRule=(CSSStyleRule)rule;
                     ps.println("selector:" + i + ": " + styleRule.getSelectorText());
                     CSSStyleDeclaration styleDeclaration = styleRule.getStyle();


                     for (int j = 0; j < styleDeclaration.getLength(); j++) 
                     {
                          String property = styleDeclaration.item(j);
                          ps.println("property: " + property);
                          ps.println("value: " + styleDeclaration.getPropertyCSSValue(property).getCssText());
                          ps.println("priority: " + styleDeclaration.getPropertyPriority(property));   
                     }



                  }// end of StyleRule instance test
                } // end of ruleList loop

               if (out != null) out.close();
               if (stream != null) stream.close();
               rtn = true;
            }
            catch (IOException ioe)
            {
                System.err.println ("IO Error: " + ioe);
            }
            catch (Exception e)
            {
                System.err.println ("Error: " + e);

            }
            finally
            {
                if (ps != null) ps.close(); 
            }

            return rtn;

    }

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

3 Comments

Hi Gene, thanks for the info. I've been using CSSParser with not too many problems - except two small annoyances: 1) If there is an unrecognised or badly formatted rule the parser seems to barf on the whole file - as opposed to just dropping that 1 rule. Obviously with real-word css this happens quite a lot. Also, i think there is a bug with comments: multi-line comments seem to result in all subsequent css being dropped upto the next comment. have you noticed this?
Hi Richard, I've just started using CSSParser. I haven't noticed the dropped comments issue yet- I'm trying to find a <a href="stackoverflow.com/questions/1853379/…> to the issue that it removes IE hacks, at the moment. Have you any experience with this issue yourself?
not really - although could be the reason for some of the barfing i see. Without knowing what you're doing exactly, I would suggest doing some pre-processing on each css file before parsing. You could maybe set up some regexes for IE hacks and strip them out?
16

A CSS library for reading and writing CSS2 and CSS3 files in Java is ph-css from https://github.com/phax/ph-css It is based on a JavaCC grammar and supports both CSS2 as well as CSS3 and additionally lets you parse HTML style attributes.

  • It supports the most common hacks "*", "_" and "$" which are not spec compliant
  • It supports CSS math - the calc() expression
  • It supports the @page rule
  • It supports the CSS3 media queries
  • It supports @viewport rules
  • It supports @keyframes rules
  • It supports @supports rules - quite new
  • It supports the @namespace rules
  • You can get source location information for the different elements (line + column number for start and end - both for the tag as well as for the complete construct)

Since May 21st, 2013 a JDK 1.5 version is also available, which makes it more interesting for Android development

4 Comments

I did use it, and since the question was asked, it did evolve nicely. Nice API, a visitor to fetch just the elements you need, just lack some documentation (but the API docs are rather nice). Recommended.
It's such a waste that this nice project has poor documentation. With a little work, this could become a much more popular project.
This looks like the best one to me
In the meantime Apache JMeter 3 is also using this library :)
12

I needed a CSS parser for an own project, but I found "CSSParser" to be too tedious and inflexible to work with (but that could have just been me), so I ended up writing my own simple but functional CSS parser.

Feel free to use it if you want to :-)

OSBCP CSS Parser

5 Comments

I looked at your project quickly and it seems like your parser is very powerful and functional. I am seriously thinking about using it in one of my projects. Are there any issues I need to know about? Also, can the CSS rules be modified in memory and then saved again into a CSS file? Thanks.
Yea. It parses the rules into a list of Rules, which can be modified and then written back to String/File using toString(). I hope that answers your question.
Thanks. I am using it by the way and it's working perfectly for me.
can i use it to start writing an scss parser or does it already work with scss?
This is the only parser that makes sense if you want to do something other than test that the CSS is valid.
4

an addition to cssparser.sourcefourge.net,

Cobra:

http://lobobrowser.org/cobra.jsp

1 Comment

Also uses the old CSSParser project
4

Check out SAC and its implementstions here: http://www.w3.org/Style/CSS/SAC/

CSSParser is a little bit out of date

Comments

2

I just rolled out my own CSS Stream Parser for Java, available on github. What sets this parser apart includes:

  • It is a stream parser, so the parser handler will receive notification of all new content immediately after each item has been parsed
  • Full support for all currently-documented At-Rules
  • Custom classes TokenSequence and Token simplify processes for handling selectors, etc.
  • Easy to use and to understand
  • Useful for validation or for more advanced applications
  • Scalable: designed to be able to handle changes to CSS definitions.

Comments

1

jStyleParser provides exactly this functionality. It parses all the referenced style sheets and maps them to the DOM tree nodes.

Comments

1

If you struggle with CSSParser, because there seems to be no documentation at all, and you perhaps want to parse just a CSS String, like value from style parameter, here is my simple sample of use:

import org.junit.Test;
import org.w3c.css.sac.InputSource;
import org.w3c.dom.css.CSSRule;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.css.CSSValue;

import com.steadystate.css.parser.CSSOMParser;

public class ParseCssTest {

@Test
public void testParseStyleDeclaration() throws IOException {
    String cssSample = "margin-top: 0cm; margin-bottom: 0cm; background: #e6e6e6";
    CSSOMParser parser = new CSSOMParser();
    CSSStyleDeclaration o = parser.parseStyleDeclaration(new InputSource(new StringReader(cssSample)));
    assertEquals("margin-top: 0cm; margin-bottom: 0cm; background: rgb(230, 230, 230)", o.toString());
    assertEquals("0cm", o.getPropertyCSSValue("margin-bottom").toString());
    assertEquals("0cm", o.getPropertyCSSValue("margin-bottom").getCssText());
    assertEquals(null, o.getPropertyCSSValue("foo"));
}

@Test
public void testParseARule() throws IOException {
    String cssSample = "r1 { margin-top: 0cm; margin-bottom: 0cm; background: #e6e6e6 }";
    CSSOMParser parser = new CSSOMParser();
    CSSRule o = parser.parseRule(new InputSource(new StringReader(cssSample)));
    assertEquals("r1 { margin-top: 0cm; margin-bottom: 0cm; background: rgb(230, 230, 230) }", o.toString());
}

@Test
public void parseStyleDeclarationWithAdvancedTests() throws IOException {
    String cssSample = "margin-top: 0 cm; margin-bottom: 0cm; background: #e6e6e6";
    CSSOMParser parser = new CSSOMParser();
    CSSStyleDeclaration o = parser.parseStyleDeclaration(new InputSource(new StringReader(cssSample)));
    assertEquals("margin-top: 0 cm; margin-bottom: 0cm; background: rgb(230, 230, 230)", o.toString());

    assertEquals("0cm", o.getPropertyCSSValue("margin-bottom").toString());
    assertEquals("0cm", o.getPropertyCSSValue("margin-bottom").getCssText());
    assertEquals(CSSValue.CSS_VALUE_LIST, o.getPropertyCSSValue("margin-top").getCssValueType());

    assertEquals("0 cm", o.getPropertyCSSValue("margin-top").toString());
    assertEquals("0 cm", o.getPropertyCSSValue("margin-top").getCssText());
    assertEquals(CSSValue.CSS_VALUE_LIST, o.getPropertyCSSValue("margin-top").getCssValueType());
}
}

Big advantage of CSSParser is that it is currently in Maven. So if you look for something rather simple and straightforwardly usable CSSParser seems to be good option.

Notes: it does automatic conversion for colors from hex format to rgb() format, but provides no help with sizes with units, it sees them as list of values! Not so good.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.