#include #include #include #include #include #include "xml.h" #include "dom.h" static void indent(int level); struct node * dom_parse(const char *file, char *entity_path) { struct dom_parse_info dpi; dpi.dpi_pi.pi_start_element = dom_start_element; dpi.dpi_pi.pi_end_element = dom_end_element; dpi.dpi_pi.pi_characters = dom_characters; TAILQ_INIT(&dpi.dpi_nodes); xml_parse(file, entity_path, (struct parse_info *)&dpi); return (dpi.dpi_root); } struct node * node_new(int type, const char *name, const char *value, int len) { struct node *n; char *p; n = malloc(sizeof(*n)); TAILQ_INIT(&n->n_children); TAILQ_INIT(&n->n_attributes); n->n_parent = NULL; n->n_type = type; n->n_name = strdup(name); if (value != NULL) { p = malloc(len + 1); bcopy(value, p, len); p[len] = '\0'; n->n_value = p; } return (n); } struct node * node_copy(struct node *tn) { struct node *n, *n1, *n2; n = node_new(tn->n_type, tn->n_name, tn->n_value, strlen(tn->n_value)); TAILQ_FOREACH(n1, &tn->n_attributes, n_child) { n2 = node_copy(n1); TAILQ_INSERT_TAIL(&n->n_attributes, n2, n_child); n2->n_parent = n; } TAILQ_FOREACH(n1, &tn->n_children, n_child) { n2 = node_copy(n1); TAILQ_INSERT_TAIL(&n->n_children, n2, n_child); n2->n_parent = n; } return (n); } struct node * node_find_attribute_by_name(struct node *root, const char *name) { struct node *n; TAILQ_FOREACH(n, &root->n_attributes, n_child) if (strcmp(n->n_name, name) == 0) break; return (n); } void node_find_children_by_attribute_value(struct node *root, struct node_list *list, const char *name, const char *value, int recurse) { struct node *n; const char *s; TAILQ_FOREACH(n, &root->n_children, n_child) { s = node_get_attribute_value(n, name); if (s != NULL && strcmp(s, value) == 0) TAILQ_INSERT_TAIL(list, n, n_link); if (recurse) { node_find_children_by_attribute_value(n, list, name, value, recurse); } } } struct node * node_find_child_by_name(struct node *root, const char *name, int recurse) { struct node *n; TAILQ_FOREACH(n, &root->n_children, n_child) { if (strcmp(n->n_name, name) == 0) return (n); if (recurse) return node_find_child_by_name(root, name, 1); } return (NULL); } void node_find_children_by_name(struct node *root, struct node_list *list, const char *name, int recurse) { struct node *n; TAILQ_FOREACH(n, &root->n_children, n_child) { if (strcmp(n->n_name, name) == 0) TAILQ_INSERT_TAIL(list, n, n_link); if (recurse) node_find_children_by_name(n, list, name, 1); } } const char * node_get_attribute_value(struct node *root, const char *name) { struct node *n; TAILQ_FOREACH(n, &root->n_attributes, n_child) if (strcmp(n->n_name, name) == 0) return (n->n_value); return (NULL); } void node_get_children(struct node *root, struct node_list *list) { struct node *n; TAILQ_FOREACH(n, &root->n_children, n_child) TAILQ_INSERT_TAIL(list, n, n_link); } void node_get_xpath(struct node *n, char *path) { struct node *nb[64]; char *p; int i; nb[0] = NULL; i = 1; for (;;) { nb[i] = n; if (n->n_parent == NULL) break; n = n->n_parent; i++; } for (p = path; nb[i] != NULL; i--) p += sprintf(p, "/%s", nb[i]->n_name); } void node_print(struct node *n, int level) { struct node *an, *cn; int i; switch (n->n_type) { case ELEMENT_NODE: indent(level); printf("<%s", n->n_name); TAILQ_FOREACH(an, &n->n_attributes, n_child) node_print(an, level + 1); if (!TAILQ_EMPTY(&n->n_children)) { printf(">\n"); TAILQ_FOREACH(cn, &n->n_children, n_child) node_print(cn, level + 1); indent(level); printf("\n", n->n_name); } else printf("/>\n"); break; case ATTRIBUTE_NODE: printf(" %s=\"%s\"", an->n_name, an->n_value); break; case TEXT_NODE: indent(level); printf("%s\n", n->n_value); break; } } void dom_start_element(void *userData, const XML_Char *name, const XML_Char **atts) { struct dom_parse_info *dpi = userData; struct node *att; struct node *n; int i; n = node_new(ELEMENT_NODE, name, "", 0); for (i = 0; atts[i] != NULL; i += 2) { att = node_new(ATTRIBUTE_NODE, atts[i], atts[i + 1], strlen(atts[i + 1])); TAILQ_INSERT_TAIL(&n->n_attributes, att, n_child); att->n_parent = n; } TAILQ_INSERT_HEAD(&dpi->dpi_nodes, n, n_link); } void dom_end_element(void *userData, const XML_Char *name) { struct dom_parse_info *dpi = userData; struct node *parent; struct node *n; n = TAILQ_FIRST(&dpi->dpi_nodes); TAILQ_REMOVE(&dpi->dpi_nodes, n, n_link); if (!TAILQ_EMPTY(&dpi->dpi_nodes)) { struct node *parent = TAILQ_FIRST(&dpi->dpi_nodes); TAILQ_INSERT_TAIL(&parent->n_children, n, n_child); n->n_parent = parent; } else dpi->dpi_root = n; } void dom_characters(void *userData, const XML_Char *s, int len) { struct dom_parse_info *dpi = userData; struct node *parent; struct node *n; int i; for (i = 0; i < len; i++) if (!isspace(s[i])) break; if (i == len) return; n = node_new(TEXT_NODE, "#text", s, len); parent = TAILQ_FIRST(&dpi->dpi_nodes); TAILQ_INSERT_TAIL(&parent->n_children, n, n_child); } static void indent(level) { int i; for (i = 0; i < level; i++) printf(" "); }