Jabberd14-1.6.0/jabberd/lib/xmlnode.c/xmlnode_get_tags

Last-modified: 2007-03-18 (日) 23:06:36

このページを編集する際は,編集に関する方針に従ってください.

概要

* at all xmlnodes that match a path
*
* The valid paths are a very small subset of xpath.
*
* The only predicates we support is for existence of attributes, or for attribute values,
* we only support steps in the axis child and the axis must be ommited,
* we support text() as a step.
*
* Examples:
* - foo/bar/text()
* - foo/bar[@baz='true']/text()
* - foobar
* - foobar[@attribute]
* - *[@attribute='value']
  • 妥当なpathはxpahtのサブセットだ。

引数

* @param parent the xmlnode where to start the path
* @param path the path (xpath like syntax, but only a small subset)
* @param xht hashtable mapping namespace prefixes to namespace IRIs
* @return first item in the list of xmlnodes, or NULL if no xmlnode matched the path

実装

xmlnode_list_item xmlnode_get_tags(xmlnode context_node, const char *path, xht namespaces) {
    char *this_step = NULL;
    const char *ns_iri = NULL;
    char *next_step = NULL;
    char *start_predicate = NULL;
    char *end_predicate = NULL;
    char *predicate = NULL;
    char *end_prefix = NULL;
    int axis = 0;	/* 0 = child, 1 = parent, 2 = attribute */
    xmlnode_list_item result_first = NULL;
    xmlnode_list_item result_last = NULL;
    xmlnode iter = NULL;
    /* sanity check */
    if (context_node == NULL || path == NULL || namespaces == NULL)
	 return NULL;
    /* check if there is an axis */
    if (j_strncmp(path, "child::", 7) == 0) {
	 path = path+7;
    } else if (j_strncmp(path, "parent::", 8) == 0) {
	 axis = 1;
	 path = path+8;
    } else if (j_strncmp(path, "attribute::", 11) == 0) {
	 axis = 2;
	 path = path+11;
    }
    /* separate this step from the next one, and check for a predicate in this step */
    start_predicate = strchr(path, '[');
    next_step = strchr(path, '/');
  • '['と'/'両方共無い
        if (start_predicate == NULL && next_step == NULL) {
    	 this_step = pstrdup(xmlnode_pool(context_node), path);
  • [が無いか、"/["の順である。
        } else if (start_predicate == NULL || start_predicate > next_step && next_step != NULL) {
    	 this_step = pmalloco(xmlnode_pool(context_node), next_step - path + 1);
    	 snprintf(this_step, next_step - path + 1, "%s", path);
    	 if (next_step != NULL)
    	     next_step++;
    } else {
	 end_predicate = strchr(start_predicate, ']');
	 if (end_predicate == NULL) {
	     /* error in predicate syntax */
	     return NULL;
	 }
	 if (next_step != NULL) {
	     if (next_step < end_predicate)
		 next_step = strchr(end_predicate, '/');
	     if (next_step != NULL)
		 next_step++;
	 }
	 predicate = pmalloco(xmlnode_pool(context_node), end_predicate - start_predicate);
	 snprintf(predicate, end_predicate - start_predicate, "%s", start_predicate+1);
	 this_step = pmalloco(xmlnode_pool(context_node), start_predicate - path + 1);
	 snprintf(this_step, start_predicate - path + 1, "%s", path);
    }
    /* check for the namespace IRI we have to match the node */
    end_prefix = strchr(this_step, ':');
    if (end_prefix == NULL) {
	 /* default prefix (or NULL if axis is attribute::) */
	 ns_iri = axis == 2 ? NULL : xhash_get(namespaces, "");
    } else {
	 /* prefixed name */
	 *end_prefix = 0;
	 ns_iri = xhash_get(namespaces, this_step);
	 this_step = end_prefix+1;
    }
    /* iterate over all child nodes, checking if this step matches them */
    for (
	     iter = axis == 0 ? xmlnode_get_firstchild(context_node) :
		 axis == 1 ? xmlnode_get_parent(context_node) :
		 axis == 2 ? xmlnode_get_firstattrib(context_node) :
		 NULL;
	     iter != NULL;
	     iter = axis == 0 ? xmlnode_get_nextsibling(iter) :
		 axis == 1 ? NULL :
		 axis == 2 ? xmlnode_get_nextsibling(iter) :
		 NULL) {
	 if (this_step != NULL && this_step[0] == '*' && this_step[1] == 0) {
	     /* matching all nodes */
	     /* match ns_iri if prefix has been specified */
	     if (end_prefix != NULL) {
		 if (iter->type == NTYPE_CDATA || j_strcmp(ns_iri, iter->ns_iri) != 0) {
		     continue;
		 }
	     }
	     /* merging if it is a text node */
	     if (iter->type == NTYPE_CDATA)
		 _xmlnode_merge(iter);
	     /* append to the result */
	     _xmlnode_append_if_predicate(&result_first, &result_last, iter, predicate, next_step, namespaces);
	     continue;
	 }
	 if (iter->type == NTYPE_CDATA && j_strcmp(this_step, "text()") == 0) {
	     /* matching text node */
	     /* merge all text nodes, that are direct siblings with this one */
	     _xmlnode_merge(iter);
	     /* append to the result */
	     _xmlnode_append_if_predicate(&result_first, &result_last, iter, predicate, next_step, namespaces);
	     continue;
	 }
  • 要素か属性を探す。
	 if ( iter->type != NTYPE_CDATA &&
             (ns_iri == NULL && iter->ns_iri == NULL || j_strcmp(ns_iri, iter->ns_iri) == 0) &&
             j_strcmp(this_step, iter->name) == 0
           ) {
  • ノードがCDATAでなく、ns_iriがともに等しく、ステップがノード名である場合。
	     /* matching element or attribute */
	     /* append to the result */
	     _xmlnode_append_if_predicate(&result_first, &result_last, iter, predicate, next_step, namespaces);
	     continue;
	 }
    }
    return result_first;
}

呼出元

void mio_init(void)

#related: relatedプラグインは廃止されました。