Simple XML subset parser comparable to glib's Markup parser, but without any dependencies in one self contained file. Forked from https://github.com/ooxi/xml.c
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

182 líneas
3.9 KiB

  1. #include <stdbool.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "./xml.h"
  6. /**
  7. * Will halt the program iff assertion fails
  8. */
  9. static void _assert_that(_Bool condition, char const* message, char const* func, char const* file, int line) {
  10. if (!condition) {
  11. fprintf(stderr, "Assertion failed: %s, in %s (%s:%i)\n", message, func, file, line);
  12. exit(EXIT_FAILURE);
  13. }
  14. }
  15. #define assert_that(condition, message) \
  16. _assert_that(condition, message, __func__, __FILE__, __LINE__)
  17. /**
  18. * Behaves similar to `getElementsByTagName`, however returns just the first and
  19. * not all elements with a given tag name
  20. *
  21. * @param base Node in tree which should be the start of te recursive search
  22. * @param 0-terminated tag name, case sensitive
  23. *
  24. * @return First node below `base` iff found, otherwise 0
  25. * @warning Depth-First search!
  26. *
  27. * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName
  28. */
  29. static struct xml_node* get_node_by_name(struct xml_node* base, uint8_t* name) {
  30. /* Check whether `base` already has the tag name we are searching for
  31. */
  32. size_t const name_length = strlen(name);
  33. uint8_t* base_name = xml_easy_name(base);
  34. size_t const base_name_length = strlen(base_name);
  35. /* Length of `name` and `base_name` do match, we should now do a real
  36. * comparison
  37. */
  38. if (name_length == base_name_length) {
  39. int const rs = memcmp(name, base_name, name_length);
  40. /* Names match! We have found an element which fullfills our
  41. * search criteria
  42. */
  43. if (!rs) {
  44. free(base_name);
  45. return base;
  46. }
  47. }
  48. /* Unfortunately, `base` is not the element we are looking for :-(
  49. */
  50. free(base_name);
  51. /* Let's take a look at the children of `base`
  52. */
  53. size_t const number_of_children = xml_node_children(base);
  54. /* No children → No luck with base
  55. */
  56. if (!number_of_children) {
  57. return 0;
  58. }
  59. /* Recursivly look through all children
  60. */
  61. size_t child = 0; for (; child < number_of_children; ++child) {
  62. struct xml_node* child_node = xml_node_child(base, child);
  63. /* Maybe this child does contain the element we are looking for?
  64. */
  65. struct xml_node* search_result = get_node_by_name(
  66. child_node, name
  67. );
  68. /* We are lucky!
  69. */
  70. if (search_result) {
  71. return search_result;
  72. }
  73. }
  74. /* No luck :-(
  75. */
  76. return 0;
  77. }
  78. int main(int argc, char** argv) {
  79. /* XML source, could be read from disk
  80. */
  81. uint8_t* source = ""
  82. "<Root>"
  83. "<Hello>World</Hello>"
  84. "<Functions>"
  85. "<Function>"
  86. "<as>testas one</as>"
  87. "<os>testos</os>"
  88. "</Function>"
  89. "<Function>"
  90. "<is>testis</is>"
  91. "<us>testus</us>"
  92. "<ls>testls</ls>"
  93. "</Function>"
  94. "<Function>"
  95. "<mn>testmn</mn>"
  96. "<as>testas two</as>"
  97. "</Function>"
  98. "</Functions>"
  99. "</Root>"
  100. ;
  101. struct xml_document* document = xml_parse_document(source, strlen(source));
  102. if (!document) {
  103. printf("Could parse document\n");
  104. exit(EXIT_FAILURE);
  105. }
  106. struct xml_node* root = xml_document_root(document);
  107. /* We expect to find Root / Functions / Function#1 / us
  108. */
  109. struct xml_node* us = get_node_by_name(root, "us");
  110. assert_that(us, "Did not find element by tag name `us'");
  111. uint8_t* us_content = xml_easy_content(us);
  112. assert_that(us_content, "`us' should have content");
  113. assert_that(!strcmp(us_content, "testus"), "Unexpected content for node `us'");
  114. free(us_content);
  115. /* We expect to find Root / Functions / Function#0 / as
  116. */
  117. struct xml_node* as = get_node_by_name(root, "as");
  118. assert_that(as, "Did not find element by tag name `as'");
  119. uint8_t* as_content = xml_easy_content(as);
  120. assert_that(as_content, "`as' should have content");
  121. assert_that(!strcmp(as_content, "testas one"), "Unexpected content for first `as' node");
  122. free(as_content);
  123. /* We do not expect do find a node with tag name `does_not_exist'
  124. */
  125. struct xml_node* does_not_exist = get_node_by_name(root, "does_not_exist");
  126. assert_that(!does_not_exist, "Found node that should not exist");
  127. xml_document_free(document, false);
  128. }