@Nonnull private CSSSelectorAttribute _createSelectorAttribute(@Nonnull final CSSNode aNode) { _expectNodeType(aNode, ECSSNodeType.ATTRIB); final int nChildren = aNode.jjtGetNumChildren(); // Check if a namespace prefix is present String sNamespacePrefix = null; int nOperatorIndex = 0; if (nChildren > 0 && ECSSNodeType.NAMESPACEPREFIX.isNode(aNode.jjtGetChild(0), m_eVersion)) { sNamespacePrefix = aNode.jjtGetChild(0).getText(); nOperatorIndex = 1; } final String sAttrName = aNode.getText(); CSSSelectorAttribute ret; if (nChildren == nOperatorIndex) { // Just check for existence of the attribute ret = new CSSSelectorAttribute(sNamespacePrefix, sAttrName); } else { final int nExpectedChildCount = nOperatorIndex + 2; if (nChildren != nExpectedChildCount) _throwUnexpectedChildrenCount( aNode, "Illegal number of children present (" + nChildren + ") - expected " + nExpectedChildCount); // With operator... final CSSNode aOperator = aNode.jjtGetChild(nOperatorIndex); _expectNodeType(aOperator, ECSSNodeType.ATTRIBOPERATOR); // ...and value final CSSNode aAttrValue = aNode.jjtGetChild(nOperatorIndex + 1); _expectNodeType(aAttrValue, ECSSNodeType.ATTRIBVALUE); ret = new CSSSelectorAttribute( sNamespacePrefix, sAttrName, ECSSAttributeOperator.getFromNameOrNull(aOperator.getText()), aAttrValue.getText()); } ret.setSourceLocation(aNode.getSourceLocation()); return ret; }
@Nullable private ICSSSelectorMember _createSelectorMember(final CSSNode aNode) { final int nChildCount = aNode.jjtGetNumChildren(); if (ECSSNodeType.NAMESPACEPREFIX.isNode(aNode, m_eVersion) || ECSSNodeType.ELEMENTNAME.isNode(aNode, m_eVersion) || ECSSNodeType.HASH.isNode(aNode, m_eVersion) || ECSSNodeType.CLASS.isNode(aNode, m_eVersion)) { if (nChildCount != 0) _throwUnexpectedChildrenCount( aNode, "CSS simple selector member expected 0 children and got " + nChildCount); final CSSSelectorSimpleMember ret = new CSSSelectorSimpleMember(aNode.getText()); ret.setSourceLocation(aNode.getSourceLocation()); return ret; } if (ECSSNodeType.ATTRIB.isNode(aNode, m_eVersion)) return _createSelectorAttribute(aNode); if (ECSSNodeType.SELECTORCOMBINATOR.isNode(aNode, m_eVersion)) { final String sText = aNode.getText(); final ECSSSelectorCombinator eCombinator = ECSSSelectorCombinator.getFromNameOrNull(sText); if (eCombinator == null) s_aLogger.error("Failed to parse CSS selector combinator '" + sText + "'"); return eCombinator; } if (ECSSNodeType.NEGATION.isNode(aNode, m_eVersion)) { // Note: no children don't make sense but are syntactically allowed! final List<CSSSelector> aNestedSelectors = new ArrayList<CSSSelector>(); for (int i = 0; i < nChildCount; ++i) { final CSSNode aChildNode = aNode.jjtGetChild(0); final CSSSelector aSelector = _createSelector(aChildNode); aNestedSelectors.add(aSelector); } final CSSSelectorMemberNot ret = new CSSSelectorMemberNot(aNestedSelectors); ret.setSourceLocation(aNode.getSourceLocation()); return ret; } if (ECSSNodeType.PSEUDO.isNode(aNode, m_eVersion)) { if (nChildCount == 0) { // E.g. ":focus" or ":hover" final CSSSelectorSimpleMember ret = new CSSSelectorSimpleMember(aNode.getText()); ret.setSourceLocation(aNode.getSourceLocation()); return ret; } if (nChildCount == 1) { final CSSNode aChildNode = aNode.jjtGetChild(0); if (ECSSNodeType.NTH.isNode(aChildNode, m_eVersion)) { // Handle nth. E.g. ":nth-child(even)" or ":nth-child(3n+1)" final CSSSelectorSimpleMember ret = new CSSSelectorSimpleMember(aNode.getText() + aChildNode.getText() + ")"); ret.setSourceLocation(aNode.getSourceLocation()); return ret; } // It's a function (e.g. ":lang(fr)") final CSSExpression aExpr = _createExpression(aChildNode); final CSSSelectorMemberFunctionLike ret = new CSSSelectorMemberFunctionLike(aNode.getText(), aExpr); ret.setSourceLocation(aNode.getSourceLocation()); return ret; } throw new UnsupportedOperationException( "Not supporting pseudo-selectors with functions and " + nChildCount + " args: " + aNode.toString()); } s_aLogger.error("Unsupported selector child: " + ECSSNodeType.getNodeName(aNode, m_eVersion)); return null; }