|
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "./xml.h"
-
-
-
-
-
- /**
- * Will halt the program iff assertion fails
- */
- static void _assert_that(_Bool condition, char const* message, char const* func, char const* file, int line) {
- if (!condition) {
- fprintf(stderr, "Assertion failed: %s, in %s (%s:%i)\n", message, func, file, line);
- exit(EXIT_FAILURE);
- }
- }
-
- #define assert_that(condition, message) \
- _assert_that(condition, message, __func__, __FILE__, __LINE__)
-
-
-
-
-
- /**
- * Behaves similar to `getElementsByTagName`, however returns just the first and
- * not all elements with a given tag name
- *
- * @param base Node in tree which should be the start of te recursive search
- * @param 0-terminated tag name, case sensitive
- *
- * @return First node below `base` iff found, otherwise 0
- * @warning Depth-First search!
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName
- */
- static struct xml_node* get_node_by_name(struct xml_node* base, uint8_t* name) {
-
-
- /* Check whether `base` already has the tag name we are searching for
- */
- size_t const name_length = strlen(name);
-
- uint8_t* base_name = xml_easy_name(base);
- size_t const base_name_length = strlen(base_name);
-
-
- /* Length of `name` and `base_name` do match, we should now do a real
- * comparison
- */
- if (name_length == base_name_length) {
- int const rs = memcmp(name, base_name, name_length);
-
- /* Names match! We have found an element which fullfills our
- * search criteria
- */
- if (!rs) {
- free(base_name);
- return base;
- }
- }
-
-
- /* Unfortunately, `base` is not the element we are looking for :-(
- */
- free(base_name);
-
-
- /* Let's take a look at the children of `base`
- */
- size_t const number_of_children = xml_node_children(base);
-
-
- /* No children → No luck with base
- */
- if (!number_of_children) {
- return 0;
- }
-
-
- /* Recursivly look through all children
- */
- size_t child = 0; for (; child < number_of_children; ++child) {
- struct xml_node* child_node = xml_node_child(base, child);
-
- /* Maybe this child does contain the element we are looking for?
- */
- struct xml_node* search_result = get_node_by_name(
- child_node, name
- );
-
- /* We are lucky!
- */
- if (search_result) {
- return search_result;
- }
- }
-
-
- /* No luck :-(
- */
- return 0;
- }
-
-
-
-
-
- int main(int argc, char** argv) {
-
- /* XML source, could be read from disk
- */
- uint8_t* source = ""
- "<Root>"
- "<Hello>World</Hello>"
-
- "<Functions>"
- "<Function>"
- "<as>testas one</as>"
- "<os>testos</os>"
- "</Function>"
-
- "<Function>"
- "<is>testis</is>"
- "<us>testus</us>"
- "<ls>testls</ls>"
- "</Function>"
-
- "<Function>"
- "<mn>testmn</mn>"
- "<as>testas two</as>"
- "</Function>"
- "</Functions>"
- "</Root>"
- ;
-
- struct xml_document* document = xml_parse_document(source, strlen(source));
-
- if (!document) {
- printf("Could parse document\n");
- exit(EXIT_FAILURE);
- }
- struct xml_node* root = xml_document_root(document);
-
-
-
- /* We expect to find Root / Functions / Function#1 / us
- */
- struct xml_node* us = get_node_by_name(root, "us");
- assert_that(us, "Did not find element by tag name `us'");
-
- uint8_t* us_content = xml_easy_content(us);
- assert_that(us_content, "`us' should have content");
- assert_that(!strcmp(us_content, "testus"), "Unexpected content for node `us'");
- free(us_content);
-
-
- /* We expect to find Root / Functions / Function#0 / as
- */
- struct xml_node* as = get_node_by_name(root, "as");
- assert_that(as, "Did not find element by tag name `as'");
-
- uint8_t* as_content = xml_easy_content(as);
- assert_that(as_content, "`as' should have content");
- assert_that(!strcmp(as_content, "testas one"), "Unexpected content for first `as' node");
- free(as_content);
-
-
- /* We do not expect do find a node with tag name `does_not_exist'
- */
- struct xml_node* does_not_exist = get_node_by_name(root, "does_not_exist");
- assert_that(!does_not_exist, "Found node that should not exist");
-
-
-
- xml_document_free(document, false);
- }
|