// ATTN: This function seriously needs re-organization, will be done // shortly. rw_yang_netconf_op_status_t XMLDocMerger::do_edit(XMLNode* new_node, XMLNode* delta_node, XMLNode* update_node, bool* update_required) { rw_yang_netconf_op_status_t status = RW_YANG_NETCONF_OP_STATUS_OK; YangNode* ynode = new_node->get_descend_yang_node(); XMLEditDefaultOperation parent_op = current_operation_; for(XMLNodeIter it = delta_node->child_begin(); it != delta_node->child_end(); ++it) { XMLNode* delta_child = &(*it); std::string child_name = delta_child->get_local_name(); std::string child_ns = delta_child->get_name_space(); YangNode* child_ynode = ynode->search_child(child_name.c_str(), child_ns.c_str()); if (child_ynode == nullptr) { // Incoming node is not in our model and thus is an error std::string const err_msg = "Cannot find child ("+child_name+") of node ("+delta_node->get_local_name()+")"; report_error(delta_node, RW_YANG_NETCONF_OP_STATUS_INVALID_VALUE, err_msg.c_str()); return RW_YANG_NETCONF_OP_STATUS_INVALID_VALUE; } // Set the current node operation (default=merge) status = set_current_operation(delta_child); if (status != RW_YANG_NETCONF_OP_STATUS_OK) { return status; } bool subtree_update = false; XMLNode* new_child = new_node->find(child_name.c_str(), child_ns.c_str()); if (new_child == nullptr) { // Node not found in existing config, edit-config on new node status = do_edit_new(child_ynode, new_node, delta_child, update_node, &subtree_update); } else { status = do_edit_existing(child_ynode, new_node, new_child, delta_child, update_node, &subtree_update); } *update_required = (*update_required || subtree_update); if (status != RW_YANG_NETCONF_OP_STATUS_OK) { return status; } current_operation_ = parent_op; } if (current_operation_ == XML_EDIT_OP_REPLACE) { // Iterate thru the config dom node and find the elements not in delta // Those are marked for deletion. do_delete_missing(new_node, delta_node); } // Add defaults fill_defaults(ynode, new_node, update_node, update_required); if (!(*update_required)) { // No updates on this subtree. Either it is delete/remove operation or // the config is not changed. So remove the update subtree. XMLNode* parent = update_node->get_parent(); if (parent) { parent->remove_child(update_node); } } if (new_node->get_first_child() == nullptr && ynode->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER && !ynode->is_presence()) { // No children for a non-presence container, they are only present to // maintain hierarchy. Remove it XMLNode* parent = new_node->get_parent(); if (parent) { parent->remove_child(new_node); } } return status; }
rw_tree_walker_status_t add_xml_child (XMLNode *parent, rw_confd_value_t *confd, XMLNode*& child) { confd_cs_node *cs_node = confd->cs_node; confd_value_t *child_src = confd->value; const char *name = confd_hash2str (confd->cs_node->tag); const char *ns = confd_hash2str (confd->cs_node->ns); YangNode *child_yn = nullptr; child = nullptr; YangNode *yn = parent->get_yang_node(); if (!yn) { return RW_TREE_WALKER_FAILURE; } child_yn = yn->search_child (name, ns); if (!child_yn) { return RW_TREE_WALKER_FAILURE; } if (!child_yn->is_leafy()) { child = parent->add_child(child_yn); if (child) { return RW_TREE_WALKER_SUCCESS; } return RW_TREE_WALKER_FAILURE; } char value[1024]; char *val_p = nullptr; switch (child_src->type) { default: case C_QNAME: case C_DATETIME: case C_DATE: case C_TIME: case C_DURATION: case C_NOEXISTS: case C_STR: case C_SYMBOL: case C_BIT32: case C_BIT64: case C_XMLBEGIN: case C_XMLEND: case C_OBJECTREF: case C_UNION: case C_PTR: case C_CDBBEGIN: case C_OID: case C_DEFAULT: case C_IDENTITYREF: case C_XMLBEGINDEL: case C_DQUAD: case C_HEXSTR: RW_CRASH(); break; case C_XMLTAG: break; case C_BUF: case C_INT8: case C_INT16: case C_INT32: case C_INT64: case C_UINT8: case C_UINT16: case C_UINT32: case C_UINT64: case C_DOUBLE: case C_BOOL: case C_ENUM_VALUE: case C_BINARY: case C_DECIMAL64: case C_IPV4: case C_IPV6: case C_IPV4PREFIX: case C_IPV4_AND_PLEN: case C_IPV6_AND_PLEN: case C_IPV6PREFIX: { struct confd_type *ct = cs_node->info.type; int len = confd_val2str (ct, child_src, value, sizeof (value)); if (len < 0) { return RW_TREE_WALKER_FAILURE; } val_p = &value[0]; } break; case C_LIST: { // ATTN: ATTN: // This code is inefficient. TAIL-F has been asked what the best method // for doing this is. Once TAILF responds, change this code. // ATTN: ATTN: // This also needs to change when protobuf representation of a leaf list // transitions to becoming a list of single elements struct confd_type *ct = confd_get_leaf_list_type (cs_node); RW_ASSERT(ct); int len = confd_val2str (ct, child_src, value, sizeof (value)); if (len < 0) { return RW_TREE_WALKER_FAILURE; } val_p = &value[0]; } break; } child = parent->add_child (child_yn, val_p); if (child) { return RW_TREE_WALKER_SUCCESS; } return RW_TREE_WALKER_FAILURE; }