void XMLDocMerger::fill_defaults( YangNode* ynode, XMLNode* new_node, XMLNode* update_node, bool* update_required ) { YangNode* yn = nullptr; XMLNode* xchild = nullptr; for (YangNodeIter it = ynode->child_begin(); it != ynode->child_end(); ++it) { yn = &(*it); const char* default_val = yn->get_default_value(); if (!default_val && !yn->has_default()) { // Only default values or containers with default leaf descendents continue; } // Default values may be within a choice/case. Check if the choice has // another case. If the same case is present YangNode* ychoice = yn->get_choice(); YangNode* ycase = yn->get_case(); YangNode* other_choice = nullptr; YangNode* other_case = nullptr; bool add_default = true; bool subtree_update = false; if (ychoice && ycase && (ychoice->get_default_case() != ycase)) { add_default = false; } for (XMLNodeIter xit = new_node->child_begin(); xit != new_node->child_end(); ++xit) { xchild = &(*xit); if (xchild->get_local_name() == yn->get_name() && xchild->get_name_space() == yn->get_ns()) { if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER) { // The container has a default descendant node XMLNode* update_child = nullptr; bool created = false; if ((update_child = update_node->find( yn->get_name(), yn->get_ns())) == nullptr) { update_child = update_node->add_child(yn); created = true; } fill_defaults(yn, xchild, update_child, &subtree_update); if (!subtree_update && created) { update_node->remove_child(update_child); } *update_required = (*update_required || subtree_update); } // Default node already present in the new-dom add_default = false; break; } if (!ychoice) { // Not part of a choice continue; } other_choice = xchild->get_yang_node()->get_choice(); if (!other_choice || (other_choice != ychoice)) { // Other node is not a choice, or not the same choice, not conflicting continue; } other_case = xchild->get_yang_node()->get_case(); if (other_case && (ycase != other_case)) { // There is a node with conflicting case. Hence no default add_default = false; break; } // Same case, in-case the case is not default, some-other node in the same // case is set. Then add this default, unless the same node is found in // the new-dom. add_default = true; } if (add_default) { XMLNode* xn = new_node->add_child(yn, default_val); RW_ASSERT(xn); XMLNode* un = update_node->add_child(yn, default_val); if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER) { // The container has a default descendant node fill_defaults(yn, xn, un, &subtree_update); if (!subtree_update) { new_node->remove_child(xn); update_node->remove_child(un); } *update_required = (*update_required || subtree_update); } else { *update_required = true; } } } }
rw_yang_netconf_op_status_t XMLDocMerger::do_delete( YangNode* child_ynode, XMLNode* new_node, XMLNode* new_child, XMLNode* delta_child) { rw_yang_netconf_op_status_t status = RW_YANG_NETCONF_OP_STATUS_OK; // The deletion of last case node should add default-case default-values // This is taken care by fill_defaults() XMLNode* remove_node = new_child; xml_data_presence_t data_presence = check_if_data_exists(child_ynode, new_node, delta_child, &remove_node); switch(data_presence) { case XML_DATA_MISSING: { if (current_operation_ == XML_EDIT_OP_DELETE) { std::string const error_msg = "Node (" + new_node->get_local_name() + ") has missing data"; report_error(delta_child, RW_YANG_NETCONF_OP_STATUS_DATA_MISSING, error_msg.c_str()); return RW_YANG_NETCONF_OP_STATUS_DATA_MISSING; } return status; } case XML_DATA_EXISTS: { // If a leaf node has default value and is deleted, then don't report it, // just delete the node, the default value will added when fill_defaults // is invoked. if (child_ynode->get_default_value() == nullptr) { // Neither a leaf nor a leaf with default value report_delete(remove_node); } else { // has default value, if it is part of a case and is the last node, and // is not part of the default case then report deletion YangNode* ycase = child_ynode->get_case(); YangNode* ychoice = child_ynode->get_choice(); if (ychoice && ycase != ychoice->get_default_case()) { bool found = false; // Iterate thru the subtree to find if any node in the existing case // exists. If so, don't report for (XMLNodeIter it = new_node->child_begin(); it != new_node->child_end(); ++it) { XMLNode* xnode = &(*it); if (xnode != remove_node && xnode->get_yang_node()->get_case() == ycase) { found = true; } } if (!found) { report_delete(remove_node); } } } new_node->remove_child(remove_node); break; } case XML_DATA_LIST_EXISTS: { // remove all the data with the list name for (XMLNode* xchild = new_node->get_first_child(); xchild; ) { if (xchild->get_local_name() == child_ynode->get_name() && xchild->get_name_space() == child_ynode->get_ns()) { XMLNode* next_node = xchild->get_next_sibling(); // Multiple keyspecs, report the deletion and remove it from dom report_delete(xchild); new_node->remove_child(xchild); xchild = next_node; } else { xchild = xchild->get_next_sibling(); } } break; } } return status; }