void XMLSubstitute::substitute( xmlNodePtr original, xmlNodePtr substitutionRules, std::map< std::string, std::string> &dictionary) { std::list< ::fwRuntime::io::Substitute > substitutions = getSubstitutions( substitutionRules ); for ( std::list< ::fwRuntime::io::Substitute >::iterator iter = substitutions.begin(); iter != substitutions.end(); ++iter ) { std::string xpath = iter->xpath; std::string dictEntry = iter->dictEntry; std::string status = iter->status; bool entryInDictionary = dictionary.find(dictEntry) != dictionary.end(); if ( status=="required" && !entryInDictionary ) { OSLM_FATAL("XML substitution required dictEntry [" << dictEntry << "] missing for xpath " << xpath ); } // optional and not in dictionary if ( status=="optional" && !entryInDictionary ) { OSLM_INFO("XML substitution optional dictEntry [" << dictEntry << "] not modified for xpath " << xpath ); continue; } OSLM_INFO("XML substitution dictEntry [" << dictEntry << "] modified with xpath " << xpath << " with the value : " << dictionary[dictEntry] ); // create the context for xpath xmlXPathContextPtr xpathCtx; xpathCtx = xmlXPathNewContext(original->doc); SLM_ASSERT("xpathCtx not instanced", xpathCtx); // search xmlChar *xpathExpr= BAD_CAST xpath.c_str(); xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); SLM_ASSERT("xpathObj not instanced", xpathObj); int NbNodesFound = xpathObj->nodesetval->nodeNr; for (int i=NbNodesFound-1; i >= 0; --i ) { xmlNodePtr node = xpathObj->nodesetval->nodeTab[i]; // substitution if (node->type == XML_ATTRIBUTE_NODE ) { xmlSetProp( node->parent, node->name, BAD_CAST dictionary[dictEntry].c_str() ); } if (node->type == XML_ELEMENT_NODE ) { xmlNodeSetName( node , BAD_CAST dictionary[dictEntry].c_str() ); } if (node->type == XML_TEXT_NODE ) { xmlNodeSetContent( node , BAD_CAST dictionary[dictEntry].c_str() ); } } xmlXPathFreeObject(xpathObj ); } }
GenericAnswer* SchemaQueryHandler::handleQuery(Query* query) { const uint8_t max_depth = query->max_depth; const uint32_t max_total = query->attrResultMaxSize; MeaningDictionary dict; // using a HarvestEncoder to be able to fill // the MeaningDictonary on the fly, so we don't require an index for ids HarvestEncoder encoder(&dict); vector<EncodedFormula> exprs; exprs.reserve(query->tokens.size()); vector<const CmmlToken*> exprsTokens; exprsTokens.reserve(query->tokens.size()); for (const CmmlToken* tok : query->tokens) { EncodedFormula encTok; if (encoder.encode(_encodingConfig, tok, &encTok, nullptr) == 0) { exprs.push_back(std::move(encTok)); exprsTokens.push_back(tok); } } SchemaEngine::Config engineConfig; switch (query->cutoff_mode) { case 'A': engineConfig.cutoffHeuristic = SchemaEngine::ABSOLUTE; break; case 'R': engineConfig.cutoffHeuristic = SchemaEngine::RELATIVE; break; default: PRINT_WARN("Invalid cutoff heuristic %c\n. Using default.", query->cutoff_mode); engineConfig.cutoffHeuristic = SchemaEngine::ABSOLUTE; // default break; } SchemaEngine schemaEngine(dict, engineConfig); SchemaAnswset* result = schemaEngine.getSchemata(exprs, exprsTokens, max_total, max_depth); /* we can't deduce the substitutions in SchemaEngine because we need * the original query, so we will do it here */ for (ExprSchema& sch : result->schemata) { /* As a heuristic, * we choose the first formula in this class to be schematized */ const uint32_t representativeId = sch.formulae.front(); CmmlToken* exprRoot = query->tokens[representativeId]; getSubstitutions(exprRoot, sch.root, &sch.subst); } return result; }
void SchemaQueryHandler::getSubstitutions(CmmlToken* exprRoot, CmmlToken* schemaRoot, vector<string>* subst) { if (exprRoot == nullptr || schemaRoot == nullptr || subst == nullptr) { PRINT_WARN("nullptr pased. Skipping..."); return; } auto exprChildren = exprRoot->getChildNodes(); auto schemaChildren = schemaRoot->getChildNodes(); const string& currSchemaTag = schemaRoot->getTag(); if (currSchemaTag == types::QVAR_TAG) { const string& xref = exprRoot->getAttribute("xref"); if (xref == "") { PRINT_LOG("Missing href attribute. Skipping..."); return; } subst->push_back(xref); return; } if (exprChildren.size() != schemaChildren.size()) { PRINT_WARN("Expression and schema are incompatible. Skipping..."); return; } auto expr_it = exprChildren.begin(); auto schema_it = schemaChildren.begin(); const string& currExprTag = exprRoot->getTag(); if (currExprTag != currSchemaTag) { PRINT_WARN("Expression and schema are incompatible. Skipping..."); return; } // Done with this token? if (exprChildren.size() == 0) { return; } // disregard the first child of apply if (currExprTag == "apply") { expr_it++; schema_it++; } /* we know that both exprChildren and schemaChildren have the same length, * so it is enough to check for one */ while (expr_it != exprChildren.end()) { getSubstitutions(*expr_it, *schema_it, subst); ++expr_it; ++schema_it; } }