34

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

Richard H
  • 38,037
  • 37
  • 111
  • 138

8 Answers8

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;

    }

}
Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
Gene Myers
  • 1,230
  • 1
  • 14
  • 31
  • 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? – Richard H Dec 07 '09 at 10:35
  • Hi Richard, I've just started using CSSParser. I haven't noticed the dropped comments issue yet- I'm trying to find a solution to the issue that it removes IE hacks, at the moment. Have you any experience with this issue yourself? – Gene Myers Dec 07 '09 at 11:22
  • 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? – Richard H Dec 07 '09 at 11:36
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

Philip Helger
  • 1,814
  • 18
  • 28
  • 1
    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. – Martin Apr 22 '13 at 12:18
  • It's such a waste that this nice project has poor documentation. With a little work, this could become a much more popular project. – Gili Mar 08 '14 at 06:05
  • This looks like the best one to me – Blake Miller Jun 21 '16 at 23:53
  • In the meantime Apache JMeter 3 is also using this library :) – Philip Helger Jun 22 '16 at 11:53
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

Community
  • 1
  • 1
corgrath
  • 11,673
  • 15
  • 68
  • 99
  • 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. – stepanian Mar 19 '12 at 21:57
  • 1
    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. – corgrath Apr 01 '12 at 18:48
  • Thanks. I am using it by the way and it's working perfectly for me. – stepanian Apr 11 '12 at 00:32
  • can i use it to start writing an scss parser or does it already work with scss? – dtrunk Jun 04 '12 at 06:42
  • 1
    This is the only parser that makes sense if you want to do something other than test that the CSS is valid. – Phil Nov 13 '13 at 20:43
4

an addition to cssparser.sourcefourge.net,

Cobra:

http://lobobrowser.org/cobra.jsp

Juraj Blahunka
  • 17,913
  • 6
  • 34
  • 52
4

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

CSSParser is a little bit out of date

Dmitry Negoda
  • 2,894
  • 2
  • 18
  • 15
1

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

radkovo
  • 868
  • 6
  • 10
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.

Espinosa
  • 2,491
  • 24
  • 28
1

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.
Community
  • 1
  • 1
Phil
  • 35,852
  • 23
  • 123
  • 164