nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
                                            txIParseContext* aContext,
                                            txPattern*& aPattern)
{
    nsresult rv = NS_OK;
    bool isAttr = false;
    Token* tok = aLexer.peek();
    if (tok->mType == Token::AXIS_IDENTIFIER) {
        if (TX_StringEqualsAtom(tok->Value(), nsGkAtoms::attribute)) {
            isAttr = true;
        }
        else if (!TX_StringEqualsAtom(tok->Value(), nsGkAtoms::child)) {
            // all done already for CHILD_AXIS, for all others
            // XXX report unexpected axis error
            return NS_ERROR_XPATH_PARSE_FAILURE;
        }
        aLexer.nextToken();
    }
    else if (tok->mType == Token::AT_SIGN) {
        aLexer.nextToken();
        isAttr = true;
    }

    txNodeTest* nodeTest;
    if (aLexer.peek()->mType == Token::CNAME) {
        tok = aLexer.nextToken();

        // resolve QName
        RefPtr<nsAtom> prefix, lName;
        int32_t nspace;
        rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
                          getter_AddRefs(lName), nspace, true);
        if (NS_FAILED(rv)) {
            // XXX error report namespace resolve failed
            return rv;
        }

        uint16_t nodeType = isAttr ?
                            (uint16_t)txXPathNodeType::ATTRIBUTE_NODE :
                            (uint16_t)txXPathNodeType::ELEMENT_NODE;
        nodeTest = new txNameTest(prefix, lName, nspace, nodeType);
    }
    else {
        rv = createNodeTypeTest(aLexer, &nodeTest);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    nsAutoPtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr));
    rv = parsePredicates(step, aLexer, aContext);
    NS_ENSURE_SUCCESS(rv, rv);

    aPattern = step.forget();

    return NS_OK;
}
Example #2
0
//static
bool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode)
{
    nsAutoString value;
    txXPathTreeWalker walker(aNode);
    do {
        if (walker.getAttr(nsGkAtoms::space, kNameSpaceID_XML, value)) {
            if (TX_StringEqualsAtom(value, nsGkAtoms::preserve)) {
                return true;
            }
            if (TX_StringEqualsAtom(value, nsGkAtoms::_default)) {
                return false;
            }
        }
    } while (walker.moveToParent());

    return false;
}
nsresult
txAttribute::execute(txExecutionState& aEs)
{
    nsAutoString name;
    nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name);
    NS_ENSURE_SUCCESS(rv, rv);

    const PRUnichar* colon;
    if (!XMLUtils::isValidQName(name, &colon) ||
            TX_StringEqualsAtom(name, nsGkAtoms::xmlns)) {
        return NS_OK;
    }

    nsCOMPtr<nsIAtom> prefix;
    PRUint32 lnameStart = 0;
    if (colon) {
        prefix = do_GetAtom(Substring(name.get(), colon));
        lnameStart = colon - name.get() + 1;
    }

    PRInt32 nsId = kNameSpaceID_None;
    if (mNamespace) {
        nsAutoString nspace;
        rv = mNamespace->evaluateToString(aEs.getEvalContext(),
                                          nspace);
        NS_ENSURE_SUCCESS(rv, rv);

        if (!nspace.IsEmpty()) {
            nsId = txNamespaceManager::getNamespaceID(nspace);
        }
    }
    else if (colon) {
        nsId = mMappings->lookupNamespace(prefix);
    }

    nsAutoPtr<txTextHandler> handler(
        static_cast<txTextHandler*>(aEs.popResultHandler()));

    // add attribute if everything was ok
    return nsId != kNameSpaceID_Unknown ?
           aEs.mResultHandler->attribute(prefix, Substring(name, lnameStart),
                                         nsId, handler->mValue) :
           NS_OK;
}
nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
                                            txIParseContext* aContext,
                                            txPattern*& aPattern)
{
    nsresult rv = NS_OK;
    MBool isAttr = MB_FALSE;
    Token* tok = aLexer.peek();
    if (tok->mType == Token::AXIS_IDENTIFIER) {
        if (TX_StringEqualsAtom(tok->Value(), txXPathAtoms::attribute)) {
            isAttr = MB_TRUE;
        }
        else if (!TX_StringEqualsAtom(tok->Value(), txXPathAtoms::child)) {
            // all done already for CHILD_AXIS, for all others
            // XXX report unexpected axis error
            return NS_ERROR_XPATH_PARSE_FAILURE;
        }
        aLexer.nextToken();
    }
    else if (tok->mType == Token::AT_SIGN) {
        aLexer.nextToken();
        isAttr = MB_TRUE;
    }
    tok = aLexer.nextToken();

    txNodeTest* nodeTest;
    if (tok->mType == Token::CNAME) {
        // resolve QName
        nsCOMPtr<nsIAtom> prefix, lName;
        PRInt32 nspace;
        rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
                          getter_AddRefs(lName), nspace, PR_TRUE);
        if (NS_FAILED(rv)) {
            // XXX error report namespace resolve failed
            return rv;
        }

        PRUint16 nodeType = isAttr ?
                            (PRUint16)txXPathNodeType::ATTRIBUTE_NODE :
                            (PRUint16)txXPathNodeType::ELEMENT_NODE;
        nodeTest = new txNameTest(prefix, lName, nspace, nodeType);
        if (!nodeTest) {
            return NS_ERROR_OUT_OF_MEMORY;
        }
    }
    else {
        aLexer.pushBack();
        rv = createNodeTypeTest(aLexer, &nodeTest);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    nsAutoPtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr));
    if (!step) {
        delete nodeTest;
        return NS_ERROR_OUT_OF_MEMORY;
    }

    rv = parsePredicates(step, aLexer, aContext);
    NS_ENSURE_SUCCESS(rv, rv);

    aPattern = step.forget();

    return NS_OK;
}
nsresult
txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr,
                             Expr* aDataTypeExpr, Expr* aOrderExpr,
                             Expr* aCaseOrderExpr, txIEvalContext* aContext)
{
    nsAutoPtr<SortKey> key(new SortKey);
    NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
    nsresult rv = NS_OK;

    // Select
    key->mExpr = aSelectExpr;

    // Order
    MBool ascending = MB_TRUE;
    if (aOrderExpr) {
        nsAutoString attrValue;
        rv = aOrderExpr->evaluateToString(aContext, attrValue);
        NS_ENSURE_SUCCESS(rv, rv);

        if (TX_StringEqualsAtom(attrValue, txXSLTAtoms::descending)) {
            ascending = MB_FALSE;
        }
        else if (!TX_StringEqualsAtom(attrValue, txXSLTAtoms::ascending)) {
            // XXX ErrorReport: unknown value for order attribute
            return NS_ERROR_XSLT_BAD_VALUE;
        }
    }


    // Create comparator depending on datatype
    nsAutoString dataType;
    if (aDataTypeExpr) {
        rv = aDataTypeExpr->evaluateToString(aContext, dataType);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    if (!aDataTypeExpr || TX_StringEqualsAtom(dataType, txXSLTAtoms::text)) {
        // Text comparator
        
        // Language
        nsAutoString lang;
        if (aLangExpr) {
            rv = aLangExpr->evaluateToString(aContext, lang);
            NS_ENSURE_SUCCESS(rv, rv);
        }

        // Case-order 
        MBool upperFirst = PR_FALSE;
        if (aCaseOrderExpr) {
            nsAutoString attrValue;

            rv = aCaseOrderExpr->evaluateToString(aContext, attrValue);
            NS_ENSURE_SUCCESS(rv, rv);

            if (TX_StringEqualsAtom(attrValue, txXSLTAtoms::upperFirst)) {
                upperFirst = PR_TRUE;
            }
            else if (!TX_StringEqualsAtom(attrValue,
                                          txXSLTAtoms::lowerFirst)) {
                // XXX ErrorReport: unknown value for case-order attribute
                return NS_ERROR_XSLT_BAD_VALUE;
            }
        }

        key->mComparator = new txResultStringComparator(ascending,
                                                        upperFirst,
                                                        lang);
        NS_ENSURE_TRUE(key->mComparator, NS_ERROR_OUT_OF_MEMORY);
    }
    else if (TX_StringEqualsAtom(dataType, txXSLTAtoms::number)) {
        // Number comparator
        key->mComparator = new txResultNumberComparator(ascending);
        NS_ENSURE_TRUE(key->mComparator, NS_ERROR_OUT_OF_MEMORY);
    }
    else {
        // XXX ErrorReport: unknown data-type
        return NS_ERROR_XSLT_BAD_VALUE;
    }

    // mSortKeys owns key now. 
    rv = mSortKeys.add(key);
    NS_ENSURE_SUCCESS(rv, rv);

    key.forget();
    mNKeys++;

    return NS_OK;
}
nsresult
txStylesheetCompiler::startElementInternal(PRInt32 aNamespaceID,
                                           nsIAtom* aLocalName,
                                           nsIAtom* aPrefix,
                                           txStylesheetAttr* aAttributes,
                                           PRInt32 aAttrCount,
                                           PRInt32 aIDOffset)
{
    nsresult rv = NS_OK;
    PRInt32 i;
    for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
        ++mInScopeVariables[i]->mLevel;
    }

    // Update the elementcontext if we have special attributes
    for (i = 0; i < aAttrCount; ++i) {
        txStylesheetAttr* attr = aAttributes + i;

        // xml:space
        if (attr->mNamespaceID == kNameSpaceID_XML &&
            attr->mLocalName == nsGkAtoms::space) {
            rv = ensureNewElementContext();
            NS_ENSURE_SUCCESS(rv, rv);

            if (TX_StringEqualsAtom(attr->mValue, nsGkAtoms::preserve)) {
                mElementContext->mPreserveWhitespace = MB_TRUE;
            }
            else if (TX_StringEqualsAtom(attr->mValue, nsGkAtoms::_default)) {
                mElementContext->mPreserveWhitespace = MB_FALSE;
            }
            else {
                return NS_ERROR_XSLT_PARSE_FAILURE;
            }
        }

        // xml:base
        if (attr->mNamespaceID == kNameSpaceID_XML &&
            attr->mLocalName == nsGkAtoms::base &&
            !attr->mValue.IsEmpty()) {
            rv = ensureNewElementContext();
            NS_ENSURE_SUCCESS(rv, rv);
            
            nsAutoString uri;
            URIUtils::resolveHref(attr->mValue, mElementContext->mBaseURI, uri);
            mElementContext->mBaseURI = uri;
        }

        // extension-element-prefixes
        if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
             attr->mLocalName == nsGkAtoms::extensionElementPrefixes &&
             aNamespaceID != kNameSpaceID_XSLT) ||
            (attr->mNamespaceID == kNameSpaceID_None &&
             attr->mLocalName == nsGkAtoms::extensionElementPrefixes &&
             aNamespaceID == kNameSpaceID_XSLT &&
             (aLocalName == nsGkAtoms::stylesheet ||
              aLocalName == nsGkAtoms::transform))) {
            rv = ensureNewElementContext();
            NS_ENSURE_SUCCESS(rv, rv);

            nsWhitespaceTokenizer tok(attr->mValue);
            while (tok.hasMoreTokens()) {
                PRInt32 namespaceID = mElementContext->mMappings->
                    lookupNamespaceWithDefault(tok.nextToken());
                
                if (namespaceID == kNameSpaceID_Unknown)
                    return NS_ERROR_XSLT_PARSE_FAILURE;

                if (!mElementContext->mInstructionNamespaces.
                        AppendElement(namespaceID)) {
                    return NS_ERROR_OUT_OF_MEMORY;
                }
            }

            attr->mLocalName = nsnull;
        }

        // version
        if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
             attr->mLocalName == nsGkAtoms::version &&
             aNamespaceID != kNameSpaceID_XSLT) ||
            (attr->mNamespaceID == kNameSpaceID_None &&
             attr->mLocalName == nsGkAtoms::version &&
             aNamespaceID == kNameSpaceID_XSLT &&
             (aLocalName == nsGkAtoms::stylesheet ||
              aLocalName == nsGkAtoms::transform))) {
            rv = ensureNewElementContext();
            NS_ENSURE_SUCCESS(rv, rv);

            if (attr->mValue.EqualsLiteral("1.0")) {
                mElementContext->mForwardsCompatibleParsing = MB_FALSE;
            }
            else {
                mElementContext->mForwardsCompatibleParsing = MB_TRUE;
            }
        }
    }

    // Find the right elementhandler and execute it
    MBool isInstruction = MB_FALSE;
    PRInt32 count = mElementContext->mInstructionNamespaces.Length();
    for (i = 0; i < count; ++i) {
        if (mElementContext->mInstructionNamespaces[i] == aNamespaceID) {
            isInstruction = MB_TRUE;
            break;
        }
    }

    if (mEmbedStatus == eNeedEmbed) {
        // handle embedded stylesheets
        if (aIDOffset >= 0 && aAttributes[aIDOffset].mValue.Equals(mTarget)) {
            // We found the right ID, signal to compile the 
            // embedded stylesheet.
            mEmbedStatus = eInEmbed;
        }
    }
    const txElementHandler* handler;
    do {
        handler = isInstruction ?
                  mHandlerTable->find(aNamespaceID, aLocalName) :
                  mHandlerTable->mLREHandler;

        rv = (handler->mStartFunction)(aNamespaceID, aLocalName, aPrefix,
                                       aAttributes, aAttrCount, *this);
    } while (rv == NS_XSLT_GET_NEW_HANDLER);

    NS_ENSURE_SUCCESS(rv, rv);

    if (!fcp()) {
        for (i = 0; i < aAttrCount; ++i) {
            txStylesheetAttr& attr = aAttributes[i];
            if (attr.mLocalName &&
                (attr.mNamespaceID == kNameSpaceID_XSLT ||
                 (aNamespaceID == kNameSpaceID_XSLT &&
                  attr.mNamespaceID == kNameSpaceID_None))) {
                // XXX ErrorReport: unknown attribute
                return NS_ERROR_XSLT_PARSE_FAILURE;
            }
        }
    }

    rv = pushPtr(const_cast<txElementHandler*>(handler));
    NS_ENSURE_SUCCESS(rv, rv);

    mElementContext->mDepth++;

    return NS_OK;
}