/*
* $Id: CSSOMParser.java,v 1.2 2008/03/26 02:08:55 sdanig Exp $
*
* CSS Parser Project
*
* Copyright (C) 1999-2008 David Schweinsberg. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* To contact the authors of the library:
*
* http://cssparser.sourceforge.net/
* mailto:davidsch@users.sourceforge.net
*/
package com.steadystate.css.parser;
import java.io.IOException;
import java.util.Properties;
import java.util.Stack;
import org.w3c.css.sac.CSSException;
import org.w3c.css.sac.ErrorHandler;
import org.w3c.css.sac.InputSource;
import org.w3c.css.sac.LexicalUnit;
import org.w3c.css.sac.Parser;
import org.w3c.css.sac.SACMediaList;
import org.w3c.css.sac.SelectorList;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.css.CSSRule;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.css.CSSStyleSheet;
import org.w3c.dom.css.CSSValue;
import org.w3c.css.sac.helpers.ParserFactory;
import com.steadystate.css.dom.CSSCharsetRuleImpl;
import com.steadystate.css.dom.CSSFontFaceRuleImpl;
import com.steadystate.css.dom.CSSImportRuleImpl;
import com.steadystate.css.dom.CSSMediaRuleImpl;
import com.steadystate.css.dom.CSSOMObject;
import com.steadystate.css.dom.CSSPageRuleImpl;
import com.steadystate.css.dom.CSSRuleListImpl;
import com.steadystate.css.dom.CSSStyleDeclarationImpl;
import com.steadystate.css.dom.CSSStyleRuleImpl;
import com.steadystate.css.dom.CSSStyleSheetImpl;
import com.steadystate.css.dom.CSSUnknownRuleImpl;
import com.steadystate.css.dom.CSSValueImpl;
import com.steadystate.css.dom.MediaListImpl;
import com.steadystate.css.dom.Property;
import com.steadystate.css.sac.DocumentHandlerExt;
import com.steadystate.css.userdata.UserDataConstants;
/**
*
* @author <a href="mailto:davidsch@users.sourceforge.net">David Schweinsberg</a>
* @version $Id: CSSOMParser.java,v 1.2 2008/03/26 02:08:55 sdanig Exp $
*/
public class CSSOMParser {
private static final String PARSER = "com.steadystate.css.parser.SACParserCSS2";
private static boolean use_internal = false;
private Parser _parser = null;
private CSSStyleSheetImpl _parentStyleSheet = null;
// TODO what is this _parentRule for? It is not read locally.
//private CSSRule _parentRule = null;
/** Creates new CSSOMParser */
public CSSOMParser() {
try {
// use the direct method if we already failed once before
if(use_internal) {
this._parser = new SACParserCSS2();
} else {
setProperty("org.w3c.css.sac.parser", PARSER);
ParserFactory factory = new ParserFactory();
this._parser = factory.makeParser();
}
} catch (Exception e) {
use_internal = true;
System.err.println(e.getMessage());
e.printStackTrace();
System.err.println("using the default parser instead");
this._parser = new SACParserCSS2();
}
}
/**
* Creates new CSSOMParser
*
* @param parser the SAC Parser
*/
public CSSOMParser(Parser parser)
{
this._parser = parser;
}
public void setErrorHandler(ErrorHandler eh)
{
this._parser.setErrorHandler(eh);
}
/**
* Parses a SAC input source into a CSSOM style sheet.
*
* @param source the SAC input source
* @param ownerNode the owner node (see the definition of
* <code>ownerNode</code> in org.w3c.dom.css.StyleSheet)
* @param href the href (see the definition of <code>href</code> in
* org.w3c.dom.css.StyleSheet)
* @return the CSSOM style sheet
* @throws IOException if the underlying SAC parser throws an IOException
*/
public CSSStyleSheet parseStyleSheet(InputSource source, Node ownerNode,
String href) throws IOException {
CSSOMHandler handler = new CSSOMHandler();
handler.setOwnerNode(ownerNode);
handler.setHref(href);
this._parser.setDocumentHandler(handler);
this._parser.parseStyleSheet(source);
Object o = handler.getRoot();
if (o instanceof CSSStyleSheet)
{
return (CSSStyleSheet) handler.getRoot();
}
return null;
}
/**
* Parses a SAC input source into a CSSOM style declaration.
*
* @param source the SAC input source
* @return the CSSOM style declaration
* @throws IOException if the underlying SAC parser throws an IOException
*/
public CSSStyleDeclaration parseStyleDeclaration(InputSource source)
throws IOException {
CSSStyleDeclarationImpl sd = new CSSStyleDeclarationImpl(null);
parseStyleDeclaration(sd, source);
return sd;
}
public void parseStyleDeclaration(CSSStyleDeclaration sd, InputSource source)
throws IOException {
Stack nodeStack = new Stack();
nodeStack.push(sd);
CSSOMHandler handler = new CSSOMHandler(nodeStack);
this._parser.setDocumentHandler(handler);
this._parser.parseStyleDeclaration(source);
}
public CSSValue parsePropertyValue(InputSource source) throws IOException {
CSSOMHandler handler = new CSSOMHandler();
this._parser.setDocumentHandler(handler);
return new CSSValueImpl(this._parser.parsePropertyValue(source));
}
public CSSRule parseRule(InputSource source) throws IOException {
CSSOMHandler handler = new CSSOMHandler();
this._parser.setDocumentHandler(handler);
this._parser.parseRule(source);
return (CSSRule) handler.getRoot();
}
public SelectorList parseSelectors(InputSource source) throws IOException {
HandlerBase handler = new HandlerBase();
this._parser.setDocumentHandler(handler);
return this._parser.parseSelectors(source);
}
public void setParentStyleSheet(CSSStyleSheetImpl parentStyleSheet) {
this._parentStyleSheet = parentStyleSheet;
}
protected CSSStyleSheetImpl getParentStyleSheet()
{
return this._parentStyleSheet;
}
// See _parentRule
/*
public void setParentRule(CSSRule parentRule) {
_parentRule = parentRule;
}
*/
class CSSOMHandler implements DocumentHandlerExt {
private Stack _nodeStack;
private Object _root = null;
private Node ownerNode;
private String href;
private Node getOwnerNode()
{
return this.ownerNode;
}
private void setOwnerNode(Node ownerNode)
{
this.ownerNode = ownerNode;
}
private String getHref()
{
return this.href;
}
private void setHref(String href)
{
this.href = href;
}
public CSSOMHandler(Stack nodeStack) {
this._nodeStack = nodeStack;
}
public CSSOMHandler() {
this._nodeStack = new Stack();
}
public Object getRoot() {
return this._root;
}
public void startDocument(InputSource source) throws CSSException {
if (this._nodeStack.empty()) {
CSSStyleSheetImpl ss = new CSSStyleSheetImpl();
CSSOMParser.this.setParentStyleSheet(ss);
ss.setOwnerNode(this.getOwnerNode());
ss.setBaseUri(source.getURI());
ss.setHref(this.getHref());
ss.setMediaText(source.getMedia());
ss.setTitle(source.getTitle());
// Create the rule list
CSSRuleListImpl rules = new CSSRuleListImpl();
ss.setCssRules(rules);
this._nodeStack.push(ss);
this._nodeStack.push(rules);
} else {
// Error
}
}
public void endDocument(InputSource source) throws CSSException {
// Pop the rule list and style sheet nodes
this._nodeStack.pop();
this._root = this._nodeStack.pop();
}
public void comment(String text) throws CSSException {
}
public void ignorableAtRule(String atRule) throws CSSException {
// Create the unknown rule and add it to the rule list
CSSUnknownRuleImpl ir = new CSSUnknownRuleImpl(
CSSOMParser.this.getParentStyleSheet(),
this.getParentRule(),
atRule);
this.addLocator(ir);
if (!this._nodeStack.empty()) {
((CSSRuleListImpl)this._nodeStack.peek()).add(ir);
} else {
// _nodeStack.push(ir);
this._root = ir;
}
}
public void namespaceDeclaration(String prefix, String uri)
throws CSSException {
}
public void charset(String characterEncoding) throws CSSException
{
CSSCharsetRuleImpl cr = new CSSCharsetRuleImpl(CSSOMParser.this.getParentStyleSheet(),
this.getParentRule(),
characterEncoding);
this.addLocator(cr);
if (!this._nodeStack.empty())
{
((CSSRuleListImpl)this._nodeStack.peek()).add(cr);
}
else
{
this._root = cr;
}
}
public void importStyle(
String uri,
SACMediaList media,
String defaultNamespaceURI) throws CSSException {
// Create the import rule and add it to the rule list
CSSImportRuleImpl ir = new CSSImportRuleImpl(
CSSOMParser.this.getParentStyleSheet(),
this.getParentRule(),
uri,
new MediaListImpl(media));
this.addLocator(ir);
if (!this._nodeStack.empty()) {
((CSSRuleListImpl)this._nodeStack.peek()).add(ir);
} else {
// _nodeStack.push(ir);
this._root = ir;
}
}
public void startMedia(SACMediaList media) throws CSSException {
MediaListImpl ml = new MediaListImpl(media);
this.addLocator(ml);
// Create the media rule and add it to the rule list
CSSMediaRuleImpl mr = new CSSMediaRuleImpl(
CSSOMParser.this.getParentStyleSheet(),
this.getParentRule(),
ml);
this.addLocator(mr);
if (!this._nodeStack.empty()) {
((CSSRuleListImpl)this._nodeStack.peek()).add(mr);
}
// Create the rule list
CSSRuleListImpl rules = new CSSRuleListImpl();
mr.setRuleList(rules);
this._nodeStack.push(mr);
this._nodeStack.push(rules);
}
public void endMedia(SACMediaList media) throws CSSException {
// Pop the rule list and media rule nodes
this._nodeStack.pop();
this._root = this._nodeStack.pop();
}
public void startPage(String name, String pseudo_page) throws CSSException {
// Create the page rule and add it to the rule list
CSSPageRuleImpl pr = new CSSPageRuleImpl(
CSSOMParser.this.getParentStyleSheet(),
this.getParentRule(), name, pseudo_page);
this.addLocator(pr);
if (!this._nodeStack.empty()) {
((CSSRuleListImpl)this._nodeStack.peek()).add(pr);
}
// Create the style declaration
CSSStyleDeclarationImpl decl = new CSSStyleDeclarationImpl(pr);
pr.setStyle(decl);
this._nodeStack.push(pr);
this._nodeStack.push(decl);
}
public void endPage(String name, String pseudo_page) throws CSSException {
// Pop both the style declaration and the page rule nodes
this._nodeStack.pop();
this._root = this._nodeStack.pop();
}
public void startFontFace() throws CSSException {
// Create the font face rule and add it to the rule list
CSSFontFaceRuleImpl ffr = new CSSFontFaceRuleImpl(
CSSOMParser.this.getParentStyleSheet(),
this.getParentRule());
this.addLocator(ffr);
if (!this._nodeStack.empty()) {
((CSSRuleListImpl)this._nodeStack.peek()).add(ffr);
}
// Create the style declaration
CSSStyleDeclarationImpl decl = new CSSStyleDeclarationImpl(ffr);
ffr.setStyle(decl);
this._nodeStack.push(ffr);
this._nodeStack.push(decl);
}
public void endFontFace() throws CSSException {
// Pop both the style declaration and the font face rule nodes
this._nodeStack.pop();
this._root = this._nodeStack.pop();
}
public void startSelector(SelectorList selectors) throws CSSException {
// Create the style rule and add it to the rule list
CSSStyleRuleImpl sr = new CSSStyleRuleImpl(
CSSOMParser.this.getParentStyleSheet(),
this.getParentRule(), selectors);
this.addLocator(sr);
if (!this._nodeStack.empty()) {
Object o = this._nodeStack.peek();
((CSSRuleListImpl)/*this._nodeStack.peek()*/o).add(sr);
}
// Create the style declaration
CSSStyleDeclarationImpl decl = new CSSStyleDeclarationImpl(sr);
sr.setStyle(decl);
this._nodeStack.push(sr);
this._nodeStack.push(decl);
}
public void endSelector(SelectorList selectors) throws CSSException {
// Pop both the style declaration and the style rule nodes
this._nodeStack.pop();
this._root = this._nodeStack.pop();
}
public void property(String name, LexicalUnit value, boolean important)
throws CSSException {
CSSStyleDeclarationImpl decl =
(CSSStyleDeclarationImpl) this._nodeStack.peek();
try
{
Property property =
new Property(name, new CSSValueImpl(value), important);
this.addLocator(property);
decl.addProperty(property);
}
catch (DOMException e)
{
// call ErrorHandler?
}
}
private CSSRule getParentRule()
{
if (!this._nodeStack.empty() && this._nodeStack.size() > 1)
{
Object node = this._nodeStack.get(this._nodeStack.size() - 2);
if (node instanceof CSSRule)
{
return (CSSRule) node;
}
}
return null;
}
private void addLocator(CSSOMObject cssomObject)
{
cssomObject.setUserData(UserDataConstants.KEY_LOCATOR,
((AbstractSACParser) CSSOMParser.this._parser).getLocator());
}
}
public static void setProperty(String key, String val) {
Properties props = System.getProperties();
props.put(key, val);
System.setProperties(props);
}
}