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; }
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; }