| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <axiom_xpath.h> |
| #include "xpath_internals.h" |
| #include "xpath_internals_parser.h" |
| #include "xpath_internals_engine.h" |
| #include "xpath_functions.h" |
| #include "xpath_streaming.h" |
| |
| /* Create XPath context */ |
| AXIS2_EXTERN axiom_xpath_context_t * AXIS2_CALL |
| axiom_xpath_context_create( |
| const axutil_env_t *env, |
| axiom_node_t * root_node) |
| { |
| axiom_xpath_context_t* context; |
| |
| /*HACK: xpath impl requires a dummy root node in order to process properly.*/ |
| axiom_node_t * dummy_root; |
| dummy_root = axiom_node_create(env); |
| axiom_node_add_child(dummy_root, env, root_node); |
| |
| context = AXIS2_MALLOC(env->allocator, |
| sizeof(axiom_xpath_context_t)); |
| |
| context->env = env; |
| context->root_node = dummy_root; |
| context->node = dummy_root; |
| context->expr = NULL; |
| context->attribute = NULL; |
| context->namespaces = NULL; |
| context->functions = NULL; |
| |
| axiom_xpath_register_default_functions_set(context); |
| |
| return context; |
| } |
| |
| /* Compile XPath expression */ |
| AXIS2_EXTERN axiom_xpath_expression_t * AXIS2_CALL |
| axiom_xpath_compile_expression( |
| const axutil_env_t *env, |
| const axis2_char_t* xpath_expr) |
| { |
| axiom_xpath_expression_t* expr; |
| |
| expr = AXIS2_MALLOC(env->allocator, |
| sizeof(axiom_xpath_expression_t)); |
| |
| expr->expr_str = axutil_strdup(env, xpath_expr); |
| |
| if (axiom_xpath_compile(env, expr) == AXIOM_XPATH_PARSE_ERROR) |
| { |
| axiom_xpath_free_expression(env, expr); |
| return NULL; |
| } |
| else |
| { |
| return expr; |
| } |
| } |
| |
| /* Evaluate compiled XPath expression */ |
| AXIS2_EXTERN axiom_xpath_result_t * AXIS2_CALL |
| axiom_xpath_evaluate( |
| axiom_xpath_context_t *context, |
| axiom_xpath_expression_t *xpath_expr) |
| { |
| axiom_xpath_expression_copy(context, xpath_expr); |
| |
| context->streaming = AXIS2_FALSE; |
| |
| return axiom_xpath_run(context); |
| } |
| |
| AXIS2_EXTERN axiom_xpath_result_t * AXIS2_CALL |
| axiom_xpath_evaluate_streaming( |
| axiom_xpath_context_t *context, |
| axiom_xpath_expression_t *xpath_expr) |
| { |
| axiom_xpath_result_t *res; |
| |
| axiom_xpath_expression_copy(context, xpath_expr); |
| |
| if (axiom_xpath_streaming_check(context->env, xpath_expr)) |
| { |
| context->streaming = AXIS2_TRUE; |
| return axiom_xpath_run(context); |
| } |
| else |
| { |
| res = AXIS2_MALLOC( |
| context->env->allocator, sizeof(axiom_xpath_result_t)); |
| res->nodes = NULL; |
| res->flag = AXIOM_XPATH_ERROR_STREAMING_NOT_SUPPORTED; |
| |
| return res; |
| } |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_register_default_functions_set( |
| axiom_xpath_context_t *context) |
| { |
| axiom_xpath_register_function( |
| context, "count", axiom_xpath_function_count); |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_register_function( |
| axiom_xpath_context_t *context, |
| axis2_char_t *name, |
| axiom_xpath_function_t func) |
| { |
| if (name && func) |
| { |
| if (!context->functions) |
| { |
| context->functions = axutil_hash_make(context->env); |
| } |
| |
| axutil_hash_set(context->functions, name, AXIS2_HASH_KEY_STRING, (const void *)func); |
| } |
| } |
| |
| AXIS2_EXTERN axiom_xpath_function_t AXIS2_CALL |
| axiom_xpath_get_function( |
| axiom_xpath_context_t *context, |
| axis2_char_t *name) |
| { |
| axiom_xpath_function_t func = NULL; |
| |
| if(context->functions) |
| { |
| func = (axiom_xpath_function_t)axutil_hash_get(context->functions, name, AXIS2_HASH_KEY_STRING); |
| } |
| |
| return func; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_register_namespace( |
| axiom_xpath_context_t *context, |
| axiom_namespace_t *ns) |
| { |
| axis2_char_t *prefix = NULL; |
| |
| if (!context->namespaces) |
| { |
| context->namespaces = axutil_hash_make(context->env); |
| } |
| |
| prefix = axiom_namespace_get_prefix(ns, context->env); |
| |
| if (prefix) |
| { |
| axutil_hash_set(context->namespaces, prefix, AXIS2_HASH_KEY_STRING, (const void *)ns); |
| } |
| } |
| |
| AXIS2_EXTERN axiom_namespace_t * AXIS2_CALL |
| axiom_xpath_get_namespace( |
| axiom_xpath_context_t *context, |
| axis2_char_t *prefix) |
| { |
| axiom_namespace_t *ns = NULL; |
| |
| if (context->namespaces) |
| { |
| ns = (axiom_namespace_t *)axutil_hash_get(context->namespaces, prefix, AXIS2_HASH_KEY_STRING); |
| } |
| |
| return ns; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_clear_namespaces( |
| axiom_xpath_context_t *context) |
| { |
| axutil_hash_index_t *hi; |
| void *val; |
| |
| if (context->namespaces) |
| { |
| for (hi = axutil_hash_first(context->namespaces, context->env); |
| hi; |
| hi = axutil_hash_next(context->env, hi)) |
| { |
| axutil_hash_this(hi, NULL, NULL, &val); |
| axiom_namespace_free((axiom_namespace_t *)val, context->env); |
| } |
| |
| axutil_hash_free(context->namespaces, context->env); |
| } |
| |
| context->namespaces = NULL; |
| } |
| |
| /* Cast to boolean */ |
| AXIS2_EXTERN axis2_bool_t AXIS2_CALL |
| axiom_xpath_cast_node_to_boolean( |
| const axutil_env_t *env, |
| axiom_xpath_result_node_t * node) |
| { |
| if(node->type == AXIOM_XPATH_TYPE_BOOLEAN) |
| { |
| return *(axis2_bool_t *)node->value; |
| } |
| else if(node->type == AXIOM_XPATH_TYPE_NUMBER) |
| { |
| /* Cannot evaluate as *(double *)(node->value) == 1e-12 |
| since there might be an precision error */ |
| if(*(double *)(node->value) > 1e-12 || *(double *)(node->value) < -1e-12) |
| { |
| return AXIS2_TRUE; |
| } |
| else |
| { |
| return AXIS2_FALSE; |
| } |
| } |
| else if(node->value) |
| { |
| return AXIS2_TRUE; |
| } |
| else |
| { |
| return AXIS2_FALSE; |
| } |
| } |
| |
| /* Cast to double */ |
| AXIS2_EXTERN double AXIS2_CALL |
| axiom_xpath_cast_node_to_number( |
| const axutil_env_t *env, |
| axiom_xpath_result_node_t * node) |
| { |
| if (node->type == AXIOM_XPATH_TYPE_BOOLEAN) |
| { |
| if (*(axis2_bool_t *)(node->value) == AXIS2_TRUE) |
| { |
| return 1.0; |
| } |
| else |
| { |
| return 0.0; |
| } |
| } |
| else if (node->type == AXIOM_XPATH_TYPE_NUMBER) |
| { |
| return *(double *)node->value; |
| } |
| else if (node->value) |
| { |
| return 1.0; |
| } |
| else |
| { |
| return 0.0; |
| } |
| } |
| |
| /* Cast to text */ |
| AXIS2_EXTERN axis2_char_t * AXIS2_CALL |
| axiom_xpath_cast_node_to_string( |
| const axutil_env_t *env, |
| axiom_xpath_result_node_t * node) |
| { |
| axiom_element_t *ele; |
| axis2_char_t *res; |
| |
| if (!node->value) |
| { |
| return NULL; |
| } |
| |
| if (node->type == AXIOM_XPATH_TYPE_BOOLEAN) |
| { |
| if (*(axis2_bool_t *)(node->value) == AXIS2_TRUE) |
| { |
| return axutil_strdup(env, "true"); |
| } |
| else |
| { |
| return axutil_strdup(env, "false"); |
| } |
| } |
| else if (node->type == AXIOM_XPATH_TYPE_NUMBER) |
| { |
| /* Allocate 50 bytes */ |
| res = AXIS2_MALLOC(env->allocator, sizeof(axis2_char_t) * 50); |
| |
| sprintf(res, "%lf", *(double *)(node->value)); |
| |
| return res; |
| } |
| else if (node->type == AXIOM_XPATH_TYPE_TEXT) |
| { |
| return (axis2_char_t *)node->value; |
| } |
| else if (node->type == AXIOM_XPATH_TYPE_NODE) |
| { |
| ele = (axiom_element_t *)axiom_node_get_data_element( |
| (axiom_node_t *)(node->value), env); |
| |
| if (ele) |
| { |
| return axiom_element_get_text( |
| ele, env, (axiom_node_t *)(node->value)); |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| else if (node->type == AXIOM_XPATH_TYPE_ATTRIBUTE) |
| { |
| return axiom_attribute_get_value( |
| (axiom_attribute_t *)(node->value), env); |
| } |
| else if (node->type == AXIOM_XPATH_TYPE_NAMESPACE) |
| { |
| return axiom_namespace_get_prefix( |
| (axiom_namespace_t *)(node->value), env); |
| } |
| |
| return NULL; |
| } |
| |
| /* Cast to axiom node */ |
| AXIS2_EXTERN axiom_node_t * AXIS2_CALL |
| axiom_xpath_cast_node2axiom_node( |
| const axutil_env_t *env, |
| axiom_xpath_result_node_t * node) |
| { |
| if (node->type == AXIOM_XPATH_TYPE_NODE && node->value) |
| { |
| return (axiom_node_t *)node->value; |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| /* Free context */ |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_free_context( |
| const axutil_env_t *env, |
| axiom_xpath_context_t *context) |
| { |
| if (context) |
| { |
| /* Free the expression if not freed */ |
| if (context->expr) |
| { |
| axiom_xpath_free_expression(env, context->expr); |
| |
| context->expr = NULL; |
| } |
| |
| if (context->root_node) |
| { |
| axiom_node_detach(axiom_node_get_first_child(context->root_node, context->env), context->env); |
| axiom_node_free_tree(context->root_node, context->env); |
| context->root_node = NULL; |
| } |
| |
| if (context->functions) |
| { |
| axutil_hash_free(context->functions, context->env); |
| context->functions = NULL; |
| } |
| |
| if(context->namespaces) |
| { |
| axiom_xpath_clear_namespaces(context); |
| context->namespaces = NULL; |
| } |
| |
| if(context->attribute) |
| { |
| axiom_attribute_free(context->attribute, context->env); |
| context->attribute = NULL; |
| } |
| |
| AXIS2_FREE(env->allocator, context); |
| } |
| } |
| |
| /* Free expression */ |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_free_expression( |
| const axutil_env_t *env, |
| axiom_xpath_expression_t * xpath_expr) |
| { |
| int num = 0; |
| int i = 0; |
| axiom_xpath_operation_t * op = NULL; |
| axiom_xpath_node_test_t * node_test = NULL; |
| |
| if (xpath_expr) |
| { |
| if (xpath_expr->expr_str) |
| { |
| AXIS2_FREE(env->allocator, xpath_expr->expr_str); |
| |
| xpath_expr->expr_str = NULL; |
| } |
| |
| if (xpath_expr->operations) |
| { |
| num = axutil_array_list_size(xpath_expr->operations, env); |
| for (i=0; i<num; i++) |
| { |
| op = (axiom_xpath_operation_t *) axutil_array_list_get(xpath_expr->operations, env, i); |
| if (op) |
| { |
| if(op->opr) |
| { |
| if (op->opr != AXIOM_XPATH_OPERATION_LITERAL) |
| { |
| if ((op->par1) && (op->par1 != AXIOM_XPATH_PARSE_END)) |
| { |
| node_test = (axiom_xpath_node_test_t *)op->par1; |
| if (node_test) |
| { |
| if (node_test->type >= 1 && node_test->type <= 6) |
| { |
| if (node_test->name) |
| { |
| AXIS2_FREE(env->allocator, node_test->name); |
| } |
| |
| if (node_test->prefix) |
| { |
| AXIS2_FREE(env->allocator, node_test->prefix); |
| } |
| |
| if (node_test->lit) |
| { |
| AXIS2_FREE(env->allocator, node_test->lit); |
| } |
| } |
| } |
| } |
| } |
| AXIS2_FREE(env->allocator, op->par1); |
| } |
| |
| if ((op->par2) && (op->par2 != AXIOM_XPATH_PARSE_END)) |
| { |
| AXIS2_FREE(env->allocator, op->par2); |
| } |
| AXIS2_FREE(env->allocator, op); |
| } |
| } |
| axutil_array_list_free(xpath_expr->operations, env); |
| xpath_expr->operations = NULL; |
| } |
| |
| AXIS2_FREE(env->allocator, xpath_expr); |
| xpath_expr = NULL; |
| } |
| } |
| |
| /* Free result set */ |
| AXIS2_EXTERN void AXIS2_CALL |
| axiom_xpath_free_result( |
| const axutil_env_t *env, |
| axiom_xpath_result_t* result) |
| { |
| if (result) |
| { |
| if (result->nodes) |
| { |
| axiom_xpath_result_node_t *node = NULL; |
| while(axutil_array_list_size(result->nodes, env)) { |
| node = axutil_array_list_remove(result->nodes, env, 0); |
| if (node) |
| { |
| if (node->value) |
| { |
| if (node->type != AXIOM_XPATH_TYPE_NODE && |
| node->type != AXIOM_XPATH_TYPE_ATTRIBUTE && |
| node->type != AXIOM_XPATH_TYPE_NAMESPACE) |
| { |
| AXIS2_FREE(env->allocator, node->value); |
| } |
| } |
| AXIS2_FREE(env->allocator, node); |
| } |
| } |
| axutil_array_list_free(result->nodes, env); |
| } |
| |
| AXIS2_FREE(env->allocator, result); |
| } |
| } |
| |
| /* Check if the expression can be evaluated on streaming XML */ |
| AXIS2_EXTERN axis2_bool_t AXIS2_CALL |
| axiom_xpath_streaming_check( |
| const axutil_env_t *env, |
| axiom_xpath_expression_t* expr) |
| { |
| axiom_xpath_streaming_t r = AXIOM_XPATH_CHECK(expr->start); |
| |
| if(r == AXIOM_XPATH_STREAMING_NOT_SUPPORTED) |
| { |
| return AXIS2_FALSE; |
| } |
| else |
| { |
| return AXIS2_TRUE; |
| } |
| } |
| |