示例#1
0
nsresult
txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
                           txPattern* aFromPattern, LevelType aLevel,
                           txIEvalContext* aContext, txList& aValues,
                           nsAString& aValueString)
{
    aValueString.Truncate();
    nsresult rv = NS_OK;

    // If the value attribute exists then use that
    if (aValueExpr) {
        nsRefPtr<txAExprResult> result;
        rv = aValueExpr->evaluate(aContext, getter_AddRefs(result));
        NS_ENSURE_SUCCESS(rv, rv);

        double value = result->numberValue();

        if (MOZ_DOUBLE_IS_INFINITE(value) || MOZ_DOUBLE_IS_NaN(value) ||
            value < 0.5) {
            txDouble::toString(value, aValueString);
            return NS_OK;
        }
        
        aValues.add(NS_INT32_TO_PTR((int32_t)floor(value + 0.5)));
        return NS_OK;
    }


    // Otherwise use count/from/level

    txPattern* countPattern = aCountPattern;
    bool ownsCountPattern = false;
    const txXPathNode& currNode = aContext->getContextNode();

    // Parse count- and from-attributes

    if (!aCountPattern) {
        ownsCountPattern = true;
        txNodeTest* nodeTest;
        uint16_t nodeType = txXPathNodeUtils::getNodeType(currNode);
        switch (nodeType) {
            case txXPathNodeType::ELEMENT_NODE:
            {
                nsCOMPtr<nsIAtom> localName =
                    txXPathNodeUtils::getLocalName(currNode);
                int32_t namespaceID = txXPathNodeUtils::getNamespaceID(currNode);
                nodeTest = new txNameTest(0, localName, namespaceID,
                                          txXPathNodeType::ELEMENT_NODE);
                break;
            }
            case txXPathNodeType::TEXT_NODE:
            case txXPathNodeType::CDATA_SECTION_NODE:
            {
                nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
                break;
            }
            case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
            {
                txNodeTypeTest* typeTest;
                typeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
                if (typeTest) {
                    nsAutoString nodeName;
                    txXPathNodeUtils::getNodeName(currNode, nodeName);
                    typeTest->setNodeName(nodeName);
                }
                nodeTest = typeTest;
                break;
            }
            case txXPathNodeType::COMMENT_NODE:
            {
                nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
                break;
            }
            case txXPathNodeType::DOCUMENT_NODE:
            case txXPathNodeType::ATTRIBUTE_NODE:
            default:
            {
                // this won't match anything as we walk up the tree
                // but it's what the spec says to do
                nodeTest = new txNameTest(0, nsGkAtoms::_asterix, 0,
                                          nodeType);
                break;
            }
        }
        NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);

        countPattern = new txStepPattern(nodeTest, false);
        if (!countPattern) {
            // XXX error reporting
            delete nodeTest;
            return NS_ERROR_OUT_OF_MEMORY;
        }
    }


    // Generate list of values depending on the value of the level-attribute

    // level = "single"
    if (aLevel == eLevelSingle) {
        txXPathTreeWalker walker(currNode);
        do {
            if (aFromPattern && !walker.isOnNode(currNode) &&
                aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                break;
            }

            if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
                aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
                                                            aContext)));
                break;
            }

        } while (walker.moveToParent());

        // Spec says to only match ancestors that are decendants of the
        // ancestor that matches the from-pattern, so keep going to make
        // sure that there is an ancestor that does.
        if (aFromPattern && aValues.getLength()) {
            bool hasParent;
            while ((hasParent = walker.moveToParent())) {
                if (aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                    break;
                }
            }

            if (!hasParent) {
                aValues.clear();
            }
        }
    }
    // level = "multiple"
    else if (aLevel == eLevelMultiple) {
        // find all ancestor-or-selfs that matches count until...
        txXPathTreeWalker walker(currNode);
        bool matchedFrom = false;
        do {
            if (aFromPattern && !walker.isOnNode(currNode) &&
                aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                //... we find one that matches from
                matchedFrom = true;
                break;
            }

            if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
                aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
                                                            aContext)));
            }
        } while (walker.moveToParent());

        // Spec says to only match ancestors that are decendants of the
        // ancestor that matches the from-pattern, so if none did then
        // we shouldn't search anything
        if (aFromPattern && !matchedFrom) {
            aValues.clear();
        }
    }
    // level = "any"
    else if (aLevel == eLevelAny) {
        int32_t value = 0;
        bool matchedFrom = false;

        txXPathTreeWalker walker(currNode);
        do {
            if (aFromPattern && !walker.isOnNode(currNode) &&
                aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                matchedFrom = true;
                break;
            }

            if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
                ++value;
            }

        } while (getPrevInDocumentOrder(walker));

        // Spec says to only count nodes that follows the first node that
        // matches the from pattern. So so if none did then we shouldn't
        // count any
        if (aFromPattern && !matchedFrom) {
            value = 0;
        }

        if (value) {
            aValues.add(NS_INT32_TO_PTR(value));
        }
    }

    if (ownsCountPattern) {
        delete countPattern;
    }
    
    return NS_OK;
}
示例#2
0
nsresult
txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator,
                          Expr* aFormat, txIEvalContext* aContext,
                          txList& aCounters, nsAString& aHead,
                          nsAString& aTail)
{
    aHead.Truncate();
    aTail.Truncate();

    nsresult rv = NS_OK;

    nsAutoString groupSeparator;
    int32_t groupSize = 0;
    if (aGroupSize && aGroupSeparator) {
        nsAutoString sizeStr;
        rv = aGroupSize->evaluateToString(aContext, sizeStr);
        NS_ENSURE_SUCCESS(rv, rv);

        double size = txDouble::toDouble(sizeStr);
        groupSize = (int32_t)size;
        if ((double)groupSize != size) {
            groupSize = 0;
        }

        rv = aGroupSeparator->evaluateToString(aContext, groupSeparator);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    nsAutoString format;
    if (aFormat) {
        rv = aFormat->evaluateToString(aContext, format);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    uint32_t formatLen = format.Length();
    uint32_t formatPos = 0;
    PRUnichar ch = 0;

    // start with header
    while (formatPos < formatLen &&
           !isAlphaNumeric(ch = format.CharAt(formatPos))) {
        aHead.Append(ch);
        ++formatPos;
    }

    // If there are no formatting tokens we need to create a default one.
    if (formatPos == formatLen) {
        txFormattedCounter* defaultCounter;
        rv = txFormattedCounter::getCounterFor(NS_LITERAL_STRING("1"), groupSize,
                                               groupSeparator, defaultCounter);
        NS_ENSURE_SUCCESS(rv, rv);

        defaultCounter->mSeparator.AssignLiteral(".");
        rv = aCounters.add(defaultCounter);
        if (NS_FAILED(rv)) {
            // XXX ErrorReport: out of memory
            delete defaultCounter;
            return rv;
        }

        return NS_OK;
    }

    while (formatPos < formatLen) {
        nsAutoString sepToken;
        // parse separator token
        if (!aCounters.getLength()) {
            // Set the first counters separator to default value so that if
            // there is only one formatting token and we're formatting a
            // value-list longer then one we use the default separator. This
            // won't be used when formatting the first value anyway.
            sepToken.AssignLiteral(".");
        }
        else {
            while (formatPos < formatLen &&
                   !isAlphaNumeric(ch = format.CharAt(formatPos))) {
                sepToken.Append(ch);
                ++formatPos;
            }
        }

        // if we're at the end of the string then the previous token was the tail
        if (formatPos == formatLen) {
            aTail = sepToken;
            return NS_OK;
        }

        // parse formatting token
        nsAutoString numToken;
        while (formatPos < formatLen &&
               isAlphaNumeric(ch = format.CharAt(formatPos))) {
            numToken.Append(ch);
            ++formatPos;
        }
        
        txFormattedCounter* counter = 0;
        rv = txFormattedCounter::getCounterFor(numToken, groupSize,
                                               groupSeparator, counter);
        if (NS_FAILED(rv)) {
            txListIterator iter(&aCounters);
            while (iter.hasNext()) {
                delete (txFormattedCounter*)iter.next();
            }
            aCounters.clear();
            return rv;
        }

        // Add to list of counters
        counter->mSeparator = sepToken;
        rv = aCounters.add(counter);
        if (NS_FAILED(rv)) {
            // XXX ErrorReport: out of memory
            txListIterator iter(&aCounters);
            while (iter.hasNext()) {
                delete (txFormattedCounter*)iter.next();
            }
            aCounters.clear();
            return rv;
        }
    }
    
    return NS_OK;
}