nsresult txXPathOptimizer::optimizePath(Expr* aInExpr, Expr** aOutExpr) { PathExpr* path = static_cast<PathExpr*>(aInExpr); uint32_t i; Expr* subExpr; // look for steps like "//foo" that can be turned into "/descendant::foo" // and "//." that can be turned into "/descendant-or-self::node()" for (i = 0; (subExpr = path->getSubExprAt(i)); ++i) { if (path->getPathOpAt(i) == PathExpr::DESCENDANT_OP && subExpr->getType() == Expr::LOCATIONSTEP_EXPR && !subExpr->getSubExprAt(0)) { LocationStep* step = static_cast<LocationStep*>(subExpr); if (step->getAxisIdentifier() == LocationStep::CHILD_AXIS) { step->setAxisIdentifier(LocationStep::DESCENDANT_AXIS); path->setPathOpAt(i, PathExpr::RELATIVE_OP); } else if (step->getAxisIdentifier() == LocationStep::SELF_AXIS) { step->setAxisIdentifier(LocationStep::DESCENDANT_OR_SELF_AXIS); path->setPathOpAt(i, PathExpr::RELATIVE_OP); } } } // look for expressions that start with a "./" subExpr = path->getSubExprAt(0); LocationStep* step; if (subExpr->getType() == Expr::LOCATIONSTEP_EXPR && path->getSubExprAt(1) && path->getPathOpAt(1) != PathExpr::DESCENDANT_OP) { step = static_cast<LocationStep*>(subExpr); if (step->getAxisIdentifier() == LocationStep::SELF_AXIS && !step->getSubExprAt(0)) { txNodeTest* test = step->getNodeTest(); txNodeTypeTest* typeTest; if (test->getType() == txNodeTest::NODETYPE_TEST && (typeTest = static_cast<txNodeTypeTest*>(test))-> getNodeTestType() == txNodeTypeTest::NODE_TYPE) { // We have a '.' as first step followed by a single '/'. // Check if there are only two steps. If so, return the second // as resulting expression. if (!path->getSubExprAt(2)) { *aOutExpr = path->getSubExprAt(1); path->setSubExprAt(1, nullptr); return NS_OK; } // Just delete the '.' step and leave the rest of the PathExpr path->deleteExprAt(0); } } } return NS_OK; }
nsresult txXPathOptimizer::optimizeUnion(Expr* aInExpr, Expr** aOutExpr) { UnionExpr* uni = static_cast<UnionExpr*>(aInExpr); // Check for expressions like "foo | bar" and // "descendant::foo | descendant::bar" nsresult rv; uint32_t current; Expr* subExpr; for (current = 0; (subExpr = uni->getSubExprAt(current)); ++current) { if (subExpr->getType() != Expr::LOCATIONSTEP_EXPR || subExpr->getSubExprAt(0)) { continue; } LocationStep* currentStep = static_cast<LocationStep*>(subExpr); LocationStep::LocationStepType axis = currentStep->getAxisIdentifier(); txUnionNodeTest* unionTest = nullptr; // Check if there are any other steps with the same axis and merge // them with currentStep uint32_t i; for (i = current + 1; (subExpr = uni->getSubExprAt(i)); ++i) { if (subExpr->getType() != Expr::LOCATIONSTEP_EXPR || subExpr->getSubExprAt(0)) { continue; } LocationStep* step = static_cast<LocationStep*>(subExpr); if (step->getAxisIdentifier() != axis) { continue; } // Create a txUnionNodeTest if needed if (!unionTest) { nsAutoPtr<txNodeTest> owner(unionTest = new txUnionNodeTest); NS_ENSURE_TRUE(unionTest, NS_ERROR_OUT_OF_MEMORY); rv = unionTest->addNodeTest(currentStep->getNodeTest()); NS_ENSURE_SUCCESS(rv, rv); currentStep->setNodeTest(unionTest); owner.forget(); } // Merge the nodetest into the union rv = unionTest->addNodeTest(step->getNodeTest()); NS_ENSURE_SUCCESS(rv, rv); step->setNodeTest(nullptr); // Remove the step from the UnionExpr uni->deleteExprAt(i); --i; } // Check if all expressions were merged into a single step. If so, // return the step as the new expression. if (unionTest && current == 0 && !uni->getSubExprAt(1)) { // Make sure the step doesn't get deleted when the UnionExpr is uni->setSubExprAt(0, nullptr); *aOutExpr = currentStep; // Return right away since we no longer have a union return NS_OK; } } return NS_OK; }