Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of LibDOM.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  *
  6.  * Copyright 2010 - 2011 Michael Drake <tlsa@netsurf-browser.org>
  7.  */
  8.  
  9. /*
  10.  * Load an HTML file into LibDOM with Hubbub and print out the DOM structure.
  11.  *
  12.  * This example demonstrates the following:
  13.  *
  14.  * 1. Using LibDOM's Hubbub binding to read an HTML file into LibDOM.
  15.  * 2. Walking around the DOM tree.
  16.  * 3. Accessing DOM node attributes.
  17.  *
  18.  * Example input:
  19.  *      <html><body><h1 class="woo">NetSurf</h1>
  20.  *      <p>NetSurf is <em>awesome</em>!</p>
  21.  *      <div><h2>Hubbub</h2><p>Hubbub is too.</p>
  22.  *      <p>Big time.</p></div></body></html>
  23.  *
  24.  * Example output:
  25.  *
  26.  * HTML
  27.  * +-BODY
  28.  * | +-H1 class="woo"
  29.  * | +-P
  30.  * | | +-EM
  31.  * | +-DIV
  32.  * | | +-H2
  33.  * | | +-P
  34.  * | | +-P
  35.  *
  36.  */
  37.  
  38. #include <assert.h>
  39. #include <stdarg.h>
  40. #include <stdbool.h>
  41. #include <stdint.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45.  
  46. #include <dom/dom.h>
  47. #include <dom/bindings/hubbub/parser.h>
  48.  
  49.  
  50. /**
  51.  * Generate a LibDOM document DOM from an HTML file
  52.  *
  53.  * \param file  The file path
  54.  * \return  pointer to DOM document, or NULL on error
  55.  */
  56. dom_document *create_doc_dom_from_file(char *file)
  57. {
  58.         size_t buffer_size = 1024;
  59.         dom_hubbub_parser *parser = NULL;
  60.         FILE *handle;
  61.         int chunk_length;
  62.         dom_hubbub_error error;
  63.         dom_hubbub_parser_params params;
  64.         dom_document *doc;
  65.         unsigned char buffer[buffer_size];
  66.  
  67.         params.enc = NULL;
  68.         params.fix_enc = true;
  69.         params.enable_script = false;
  70.         params.msg = NULL;
  71.         params.script = NULL;
  72.         params.ctx = NULL;
  73.         params.daf = NULL;
  74.  
  75.         /* Create Hubbub parser */
  76.         error = dom_hubbub_parser_create(&params, &parser, &doc);
  77.         if (error != DOM_HUBBUB_OK) {
  78.                 printf("Can't create Hubbub Parser\n");
  79.                 return NULL;
  80.         }
  81.  
  82.         /* Open input file */
  83.         handle = fopen(file, "rb");
  84.         if (handle == NULL) {
  85.                 dom_hubbub_parser_destroy(parser);
  86.                 printf("Can't open test input file: %s\n", file);
  87.                 return NULL;
  88.         }
  89.  
  90.         /* Parse input file in chunks */
  91.         chunk_length = buffer_size;
  92.         while (chunk_length == buffer_size) {
  93.                 chunk_length = fread(buffer, 1, buffer_size, handle);
  94.                 error = dom_hubbub_parser_parse_chunk(parser, buffer,
  95.                                 chunk_length);
  96.                 if (error != DOM_HUBBUB_OK) {
  97.                         dom_hubbub_parser_destroy(parser);
  98.                         printf("Parsing errors occur\n");
  99.                         return NULL;
  100.                 }
  101.         }
  102.  
  103.         /* Done parsing file */
  104.         error = dom_hubbub_parser_completed(parser);
  105.         if (error != DOM_HUBBUB_OK) {
  106.                 dom_hubbub_parser_destroy(parser);
  107.                 printf("Parsing error when construct DOM\n");
  108.                 return NULL;
  109.         }
  110.  
  111.         /* Finished with parser */
  112.         dom_hubbub_parser_destroy(parser);
  113.  
  114.         /* Close input file */
  115.         if (fclose(handle) != 0) {
  116.                 printf("Can't close test input file: %s\n", file);
  117.                 return NULL;
  118.         }
  119.  
  120.         return doc;
  121. }
  122.  
  123.  
  124. /**
  125.  * Dump attribute/value for an element node
  126.  *
  127.  * \param node       The element node to dump attribute details for
  128.  * \param attribute  The attribute to dump
  129.  * \return  true on success, or false on error
  130.  */
  131. bool dump_dom_element_attribute(dom_node *node, char *attribute)
  132. {
  133.         dom_exception exc;
  134.         dom_string *attr = NULL;
  135.         dom_string *attr_value = NULL;
  136.         dom_node_type type;
  137.         const char *string;
  138.         size_t length;
  139.  
  140.         /* Should only have element nodes here */
  141.         exc = dom_node_get_node_type(node, &type);
  142.         if (exc != DOM_NO_ERR) {
  143.                 printf(" Exception raised for node_get_node_type\n");
  144.                 return false;
  145.         }
  146.         assert(type == DOM_ELEMENT_NODE);
  147.  
  148.         /* Create a dom_string containing required attribute name. */
  149.         exc = dom_string_create_interned((uint8_t *)attribute,
  150.                         strlen(attribute), &attr);
  151.         if (exc != DOM_NO_ERR) {
  152.                 printf(" Exception raised for dom_string_create\n");
  153.                 return false;
  154.         }
  155.  
  156.         /* Get class attribute's value */
  157.         exc = dom_element_get_attribute(node, attr, &attr_value);
  158.         if (exc != DOM_NO_ERR) {
  159.                 printf(" Exception raised for element_get_attribute\n");
  160.                 dom_string_unref(attr);
  161.                 return false;
  162.         } else if (attr_value == NULL) {
  163.                 /* Element lacks required attribute */
  164.                 dom_string_unref(attr);
  165.                 return true;
  166.         }
  167.  
  168.         /* Finished with the attr dom_string */
  169.         dom_string_unref(attr);
  170.  
  171.         /* Get attribute value's string data */
  172.         string = dom_string_data(attr_value);
  173.         length = dom_string_byte_length(attr_value);
  174.  
  175.         /* Print attribute info */
  176.         printf(" %s=\"%.*s\"", attribute, (int)length, string);
  177.  
  178.         /* Finished with the attr_value dom_string */
  179.         dom_string_unref(attr_value);
  180.  
  181.         return true;
  182. }
  183.  
  184.  
  185. /**
  186.  * Print a line in a DOM structure dump for an element
  187.  *
  188.  * \param node   The node to dump
  189.  * \param depth  The node's depth
  190.  * \return  true on success, or false on error
  191.  */
  192. bool dump_dom_element(dom_node *node, int depth)
  193. {
  194.         dom_exception exc;
  195.         dom_string *node_name = NULL;
  196.         dom_node_type type;
  197.         int i;
  198.         const char *string;
  199.         size_t length;
  200.  
  201.         /* Only interested in element nodes */
  202.         exc = dom_node_get_node_type(node, &type);
  203.         if (exc != DOM_NO_ERR) {
  204.                 printf("Exception raised for node_get_node_type\n");
  205.                 return false;
  206.         } else if (type != DOM_ELEMENT_NODE) {
  207.                 /* Nothing to print */
  208.                 return true;
  209.         }
  210.  
  211.         /* Get element name */
  212.         exc = dom_node_get_node_name(node, &node_name);
  213.         if (exc != DOM_NO_ERR) {
  214.                 printf("Exception raised for get_node_name\n");
  215.                 return false;
  216.         } else if (node_name == NULL) {
  217.                 printf("Broken: root_name == NULL\n");
  218.                 return false;
  219.         }
  220.  
  221.         /* Print ASCII tree structure for current node */
  222.         if (depth > 0) {
  223.                 for (i = 0; i < depth; i++) {
  224.                         printf("| ");
  225.                 }
  226.                 printf("+-");
  227.         }
  228.  
  229.         /* Get string data and print element name */
  230.         string = dom_string_data(node_name);
  231.         length = dom_string_byte_length(node_name);
  232.         printf("[%.*s]", (int)length, string);
  233.        
  234.         if (length == 5 && strncmp(string, "title", 5) == 0) {
  235.                 /* Title tag, gather the title */
  236.                 dom_string *str;
  237.                 exc = dom_node_get_text_content(node, &str);
  238.                 if (exc == DOM_NO_ERR && str != NULL) {
  239.                         printf(" $%.*s$", (int)dom_string_byte_length(str),
  240.                                dom_string_data(str));
  241.                         dom_string_unref(str);
  242.                 }
  243.         }
  244.  
  245.         /* Finished with the node_name dom_string */
  246.         dom_string_unref(node_name);
  247.  
  248.         /* Print the element's id & class, if it has them */
  249.         if (dump_dom_element_attribute(node, "id") == false ||
  250.                         dump_dom_element_attribute(node, "class") == false) {
  251.                 /* Error occured */
  252.                 printf("\n");
  253.                 return false;
  254.         }
  255.  
  256.         printf("\n");
  257.         return true;
  258. }
  259.  
  260.  
  261. /**
  262.  * Walk though a DOM (sub)tree, in depth first order, printing DOM structure.
  263.  *
  264.  * \param node   The root node to start from
  265.  * \param depth  The depth of 'node' in the (sub)tree
  266.  */
  267. bool dump_dom_structure(dom_node *node, int depth)
  268. {
  269.         dom_exception exc;
  270.         dom_node *child;
  271.  
  272.         /* Print this node's entry */
  273.         if (dump_dom_element(node, depth) == false) {
  274.                 /* There was an error; return */
  275.                 return false;
  276.         }
  277.  
  278.         /* Get the node's first child */
  279.         exc = dom_node_get_first_child(node, &child);
  280.         if (exc != DOM_NO_ERR) {
  281.                 printf("Exception raised for node_get_first_child\n");
  282.                 return false;
  283.         } else if (child != NULL) {
  284.                 /* node has children;  decend to children's depth */
  285.                 depth++;
  286.  
  287.                 /* Loop though all node's children */
  288.                 do {
  289.                         dom_node *next_child;
  290.  
  291.                         /* Visit node's descendents */
  292.                         if (dump_dom_structure(child, depth) == false) {
  293.                                 /* There was an error; return */
  294.                                 dom_node_unref(child);
  295.                                 return false;
  296.                         }
  297.  
  298.                         /* Go to next sibling */
  299.                         exc = dom_node_get_next_sibling(child, &next_child);
  300.                         if (exc != DOM_NO_ERR) {
  301.                                 printf("Exception raised for "
  302.                                                 "node_get_next_sibling\n");
  303.                                 dom_node_unref(child);
  304.                                 return false;
  305.                         }
  306.  
  307.                         dom_node_unref(child);
  308.                         child = next_child;
  309.                 } while (child != NULL); /* No more children */
  310.         }
  311.  
  312.         return true;
  313. }
  314.  
  315.  
  316. /**
  317.  * Main entry point from OS.
  318.  */
  319. int main(int argc, char **argv)
  320. {
  321.         dom_exception exc; /* returned by libdom functions */
  322.         dom_document *doc = NULL; /* document, loaded into libdom */
  323.         dom_node *root = NULL; /* root element of document */
  324.  
  325.         /* Load up the input HTML file */
  326.         doc = create_doc_dom_from_file((argc > 1) ? (argv[1]) : "files/test.html");
  327.         if (doc == NULL) {
  328.                 printf("Failed to load document.\n");
  329.                 return EXIT_FAILURE;
  330.         }
  331.  
  332.         /* Get root element */
  333.         exc = dom_document_get_document_element(doc, &root);
  334.         if (exc != DOM_NO_ERR) {
  335.                 printf("Exception raised for get_document_element\n");
  336.                 dom_node_unref(doc);
  337.                 return EXIT_FAILURE;
  338.         } else if (root == NULL) {
  339.                 printf("Broken: root == NULL\n");
  340.                 dom_node_unref(doc);
  341.                 return EXIT_FAILURE;
  342.         }
  343.  
  344.         /* Dump DOM structure */
  345.         if (dump_dom_structure(root, 0) == false) {
  346.                 printf("Failed to complete DOM structure dump.\n");
  347.                 dom_node_unref(root);
  348.                 dom_node_unref(doc);
  349.                 return EXIT_FAILURE;
  350.         }
  351.  
  352.         dom_node_unref(root);
  353.  
  354.         /* Finished with the dom_document */
  355.         dom_node_unref(doc);
  356.  
  357.         return EXIT_SUCCESS;
  358. }
  359.  
  360.