#ifdef MLVIEW_WITH_LIBXML_EXPERIMENTAL_COMPLETION #include #include #include "mlview-utils.h" #include #include enum InsertionScheme { NO_SCHEME = 0, INSERT_PREV, INSERT_NEXT, APPEND_CHILD, PREPEND_CHILD, CURRENT_ELEMENT, } ; struct Options { gboolean display_usage ; gboolean compute_completion ; gchar *dtd_path ; gchar *instance_path ; gchar *xpath_expr ; enum InsertionScheme insertion_scheme ; } ; static void display_usage (char * a_progname) { g_print ("usage: %s [--help | [options]\n" "where options are:\n" "--dtd provides a dtd\n" "--instance \n" "--xpath specify a ref xml node for insertion completion\n" "--insert-prev display a completion list for previous node insertion\n" "--insert-next display a completion list for next node insertion\n" "--append-child display a completion list for child node addition\n" "--current-element display the currently selected element\n", a_progname) ; } static void init_options (struct Options *a_options) { g_return_if_fail (a_options) ; a_options->display_usage = FALSE ; a_options->dtd_path = NULL ; a_options->instance_path = NULL ; a_options->compute_completion = FALSE ; } static int parse_command_line (int a_argc, char **a_argv, struct Options *a_options) { int i = 0 ; g_return_val_if_fail (a_options, -1) ; if (a_argc < 2) a_options->display_usage = TRUE ; for (i = 1 ; i < a_argc ;i++) { if (a_argv[i][0] != '-') break ; if (!strcmp (a_argv[i], "--help") || !strcmp (a_argv[i], "-h")) { } else if (!strcmp (a_argv[i], "--dtd")) { if (i + 1 >= a_argc || a_argv[i + 1][0] == '-') { a_options->display_usage = TRUE ; break ; } a_options->dtd_path = a_argv[i +1] ; i++ ; }else if (!strcmp (a_argv[i], "--instance")) { if (i + 1 >= a_argc || a_argv[i + 1][0] == '-') { a_options->display_usage = TRUE ; break ; } a_options->instance_path = a_argv[i + 1] ; i++ ; } else if (!strcmp (a_argv[i], "--xpath")) { if (i + 1 >= a_argc || a_argv[i + 1][0] == '-') { a_options->display_usage = TRUE ; break ; } a_options->xpath_expr = a_argv[i + 1] ; i++ ; a_options->compute_completion = TRUE ; } else if (!strcmp (a_argv[i], "--insert-prev")) { a_options->insertion_scheme = INSERT_PREV ; a_options->compute_completion = TRUE ; } else if (!strcmp (a_argv[i], "--insert-next")) { a_options->insertion_scheme = INSERT_NEXT ; a_options->compute_completion = TRUE ; } else if (!strcmp (a_argv[i], "--append-child")) { a_options->insertion_scheme = APPEND_CHILD ; a_options->compute_completion = TRUE ; } else if (!strcmp (a_argv[i], "--prepend-child")) { a_options->insertion_scheme = PREPEND_CHILD ; a_options->compute_completion = TRUE ; }else if (!strcmp (a_argv[i], "--current-element")) { a_options->insertion_scheme = CURRENT_ELEMENT ; a_options->compute_completion = TRUE ; }else { a_options->display_usage = TRUE ; } } return 0 ; } static int compute_completion_list (xmlDoc *a_doc, xmlDtd *a_dtd, char *a_xpath_expr, enum InsertionScheme a_insertion_scheme, char ***a_completion_list, int *a_completion_list_len) { xmlXPathContext *xpath_ctxt = NULL ; xmlXPathObject * xpath_object = NULL ; char *element_names[200] = {0} ; xmlNode *ref_node = NULL ; xmlCompletionListType completionType = XML_PREV_SIBLING_LIST_COMPLETION_TYPE ; long len = 0 ; long result = 0, i= 0 ; g_return_val_if_fail (a_doc && a_xpath_expr && a_completion_list, -1) ; xpath_ctxt = xmlXPathNewContext (a_doc) ; if (!xpath_ctxt) { mlview_utils_trace_info ("Could not instanciate xpath context\n") ; goto cleanup ; } xpath_object = xmlXPathEvalExpression (a_xpath_expr, xpath_ctxt) ; if (!xpath_object || xpath_object->type != XPATH_NODESET || !xpath_object->nodesetval || !xpath_object->nodesetval->nodeTab || !xpath_object->nodesetval->nodeNr) { mlview_utils_trace_info ("Please provide an xpath expression that resolves to a node(set)\n") ; result = -2 ; goto cleanup ; } /* *get the first node of the nodeset returned *and compute it's node insertion completion list. */ ref_node = xpath_object->nodesetval->nodeTab[0] ; a_doc->extSubset = a_dtd ; /*xmlValidGetValidElements () ;*/ switch (a_insertion_scheme) { case INSERT_PREV: completionType = XML_PREV_SIBLING_LIST_COMPLETION_TYPE ; break ; case INSERT_NEXT: completionType = XML_NEXT_SIBLING_LIST_COMPLETION_TYPE ; break ; case APPEND_CHILD: completionType = XML_APPEND_CHILD_LIST_COMPLETION_TYPE ; break ; case PREPEND_CHILD: completionType = XML_PREPEND_CHILD_LIST_COMPLETION_TYPE ; break ; case CURRENT_ELEMENT: completionType = XML_CURRENT_ELEMENT_LIST_COMPLETION_TYPE ; break ; default: result = -1 ; mlview_utils_trace_info ("Unknown type of insertion scheme") ; break ; } if (!result) { len = xmlValidGetElementNameCompletionList (ref_node, NULL, completionType, (const xmlChar**)element_names, 50) ; } else { goto cleanup ; } if (len > 0) { *a_completion_list = g_try_malloc (sizeof (char*) * (len + 1)) ; if (!*a_completion_list) { mlview_utils_trace_info ("System out of memory\n") ; goto cleanup ; } memset (*a_completion_list, 0, (len + 1) * sizeof (char*)) ; for (i=0 ; i < len ; i++) { (*a_completion_list)[i] = element_names[i] ; } *a_completion_list_len = len ; result = 0 ; } else if (len == 0) { *a_completion_list_len = 0 ; } else if (len < 0){ mlview_utils_trace_info ("Completion list computing failed\n") ; result = -1 ; goto cleanup ; } cleanup: if (xpath_ctxt) { xmlXPathFreeContext (xpath_ctxt) ; xpath_ctxt = NULL ; } if (xpath_object) { xmlXPathFreeObject (xpath_object) ; xpath_object = NULL ; } a_doc->extSubset = NULL ; return result ; } int main (int argc, char **argv) { struct Options options = {0} ; int error = 0, i= 0 ; xmlParserCtxt *parser = NULL ; xmlDoc *doc = NULL ; xmlDtd *dtd = NULL ; xmlValidCtxt validator = {0} ; int status = 0, is_valid = 0, completion_list_len = 0 ; char **completion_list = NULL ; init_options (&options) ; error = parse_command_line (argc, argv, &options) ; if (error || !options.instance_path || !options.dtd_path) { display_usage (argv[0]) ; return -1 ; } parser = xmlCreateURLParserCtxt (options.instance_path, XML_PARSE_NONET) ; if (!parser) { mlview_utils_trace_info ("Could not instanciate a parser context\n") ; return -1 ; } error = xmlParseDocument (parser) ; if (error) { mlview_utils_trace_info ("XML doc Parsing failed\n") ; status = 1 ; goto cleanup ; } dtd = xmlParseDTD (NULL, options.dtd_path) ; if (!dtd) { mlview_utils_trace_info ("Dtd parsing failed\n") ; status = -1 ; goto cleanup ; } doc = parser->myDoc ; parser->myDoc = NULL ; is_valid = xmlValidateDtd (&validator, doc, dtd) ; if (!is_valid) { g_print ("\n========= The document is not valid =========== \n") ; } else { g_print ("\n========= The document is valid =========== \n") ; } if (options.compute_completion == TRUE) { if (!options.xpath_expr || options.insertion_scheme == NO_SCHEME) { mlview_utils_trace_info ("Please, provide and xpath expression *and* an insertion scheme") ; display_usage (argv[0]) ; status = -1 ; goto cleanup ; } error = compute_completion_list (doc, dtd, options.xpath_expr, options.insertion_scheme, &completion_list, &completion_list_len) ; if (error) { g_print ("Got an error when computing the completion list\n") ; status = -1 ; goto cleanup ; } for (i= 0 ; i < completion_list_len ; i++) { g_print ("%s\n", completion_list[i]) ; } } cleanup: if (parser) { xmlFreeParserCtxt (parser) ; parser = NULL ; } if (doc) { xmlFreeDoc (doc) ; doc = NULL ; } if (dtd) { xmlFreeDtd (dtd) ; dtd = NULL ; } if (completion_list) { g_free (completion_list) ; completion_list = NULL ; } xmlCleanupParser () ; return status ; } #else int main (int argc, char **argv) { return -1 ; } #endif /*MLVIEW_WITH_LIBXML_EXPERIMENTAL_COMPLETION*/