Java tutorial
/* * Copyright 2013 LMAX Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.freud.analysed.css.jdom; import org.apache.commons.jxpath.JXPathContext; import org.freud.analysed.css.parser.CssTokenType; import org.freud.analysed.css.rule.CssRule; import org.freud.analysed.css.rule.declaration.CssDeclaration; import org.freud.analysed.css.rule.selector.CssSelector; import org.freud.core.parser.JdomTreeAdaptor; import org.jdom.Element; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; final class CssRuleJdom implements CssRule { private List<CssSelector> cssSelectorList; private List<CssDeclaration> cssDeclarationList; private final Element ruleElement; private final int commaSeparatedSelectorListIndex; private final int numberOfCommaSeparatedSelectorLists; CssRuleJdom(final Element ruleElement, final int commaSeparatedSelectorListIndex) { this.ruleElement = ruleElement; this.commaSeparatedSelectorListIndex = commaSeparatedSelectorListIndex; this.numberOfCommaSeparatedSelectorLists = ruleElement.getChildren(CssTokenType.COMMA.name()).size() + 1; } @Override public List<CssSelector> getCssSelectors() { if (cssSelectorList == null) { parseSelectors(); } return cssSelectorList; } @Override public List<CssDeclaration> getCssDeclarations() { if (cssDeclarationList == null) { parseDeclarations(); } return cssDeclarationList; } @SuppressWarnings("unchecked") private void parseSelectors() { cssSelectorList = new ArrayList<CssSelector>(); final List<Element> children = ruleElement.getChildren(); int index = 0; CssSelector.Combinator combinator = null; for (Element child : children) { if (CssTokenType.COMMA.name().equals(child.getName())) { index++; } else if (getCommaSeparatedSelectorListIndex() == index) { if (CssSelector.Type.isType(child.getName())) { final String selectorString = child.getAttributeValue(JdomTreeAdaptor.ID_ATTR); CssSelector.Type selectorType = CssSelector.Type.valueOf(child.getName()); if (selectorString != null) { Iterable<String> selectors = breakIdentToSelectors(selectorString); for (String selector : selectors) { cssSelectorList.add(new CssSelectorJdom(this, selector, selectorType, combinator)); combinator = CssSelector.Combinator.DESCENDANT; selectorType = CssSelector.Type.CLASS; } } else { cssSelectorList.add(new CssSelectorJdom(this, null, selectorType, combinator)); combinator = CssSelector.Combinator.DESCENDANT; } } else if (CssSelector.Combinator.isCombinator(child.getName())) { combinator = CssSelector.Combinator.valueOf(child.getName()); } } } } // antlr grammar should have solved it but doesn't private Iterable<String> breakIdentToSelectors(final String selectorString) { if (selectorString.contains(".")) { List<String> selectors = new LinkedList<String>(); char insideQuote = 0; int start = 0; for (int i = 0, size = selectorString.length(); i < size; i++) { char c = selectorString.charAt(i); if (insideQuote != 0) { if (c == insideQuote) { insideQuote = 0; } } else { if (c == '\'' || c == '\"') { insideQuote = c; } else if (c == '.') { selectors.add(selectorString.substring(start, i)); start = i + 1; } } } selectors.add(selectorString.substring(start, selectorString.length())); return selectors; } else { return Collections.singleton(selectorString); } } int getCommaSeparatedSelectorListIndex() { return commaSeparatedSelectorListIndex; } @SuppressWarnings("unchecked") private void parseDeclarations() { cssDeclarationList = new ArrayList<CssDeclaration>(); JXPathContext context = JXPathContext.newContext(ruleElement); List<Element> cssSelectorElementList = (List<Element>) context .selectNodes("/" + CssTokenType.PROPERTY.name()); for (Element element : cssSelectorElementList) { cssDeclarationList.add(new CssDeclarationJdom(this, element)); } } @Override public String toString() { return "CSS Rule: " + getCssSelectors().toString(); } public int getNumberOfCommaSeparatedSelectorLists() { return numberOfCommaSeparatedSelectorLists; } }