From b134f8403b4b38e4539488547ca84fc47e7f06ca Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Sun, 22 Jul 2007 21:46:06 +0000 Subject: Further work on libxml binding. This is now has support for enough node types to allow the XML-based testsuite to run sensibly. (The core library is missing a bunch of functionality that the testsuite requires, like the creation of nodes) Insertion of DocumentType nodes into a Document is mostly there -- the remainder is waiting on a suitable API in the core library. svn path=/trunk/dom/; revision=3461 --- bindings/xml/xmlparser.c | 354 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 325 insertions(+), 29 deletions(-) (limited to 'bindings/xml') diff --git a/bindings/xml/xmlparser.c b/bindings/xml/xmlparser.c index 21a6580..5c63b29 100644 --- a/bindings/xml/xmlparser.c +++ b/bindings/xml/xmlparser.c @@ -38,6 +38,14 @@ static void xml_parser_add_element_node(xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static void xml_parser_add_text_node(xml_parser *parser, struct dom_node *parent, xmlNodePtr child); +static void xml_parser_add_cdata_section(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); +static void xml_parser_add_entity_reference(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); +static void xml_parser_add_comment(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); +static void xml_parser_add_document_type(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); static void xml_parser_internal_subset(void *ctx, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); @@ -82,6 +90,8 @@ struct xml_parser { struct dom_string *udkey; /**< Key for DOM node user data */ + struct dom_implementation *impl;/**< DOM implementation */ + xml_alloc alloc; /**< Memory (de)allocation function */ void *pw; /**< Pointer to client data */ }; @@ -141,6 +151,7 @@ xml_parser *xml_parser_create(const char *enc, const char *int_enc, xml_alloc alloc, void *pw) { xml_parser *parser; + struct dom_string *features; dom_exception err; UNUSED(enc); @@ -162,7 +173,7 @@ xml_parser *xml_parser_create(const char *enc, const char *int_enc, parser->complete = false; /* Create key for user data registration */ - err = dom_string_create_from_ptr_no_doc(alloc, pw, + err = dom_string_create_from_ptr_no_doc((dom_alloc) alloc, pw, (const uint8_t *) "__xmlnode", SLEN("__xmlnode"), &parser->udkey); if (err != DOM_NO_ERR) { @@ -171,6 +182,31 @@ xml_parser *xml_parser_create(const char *enc, const char *int_enc, return NULL; } + /* Get DOM implementation */ + /* Create a string representation of the features we want */ + err = dom_string_create_from_ptr_no_doc((dom_alloc) alloc, pw, + (const uint8_t *) "XML", SLEN("XML"), &features); + if (err != DOM_NO_ERR) { + dom_string_unref(parser->udkey); + xmlFreeParserCtxt(parser->xml_ctx); + alloc(parser, 0, pw); + return NULL; + } + + /* Now, try to get an appropriate implementation from the registry */ + err = dom_implregistry_get_dom_implementation(features, + &parser->impl, (dom_alloc) alloc, pw); + if (err != DOM_NO_ERR) { + dom_string_unref(features); + dom_string_unref(parser->udkey); + xmlFreeParserCtxt(parser->xml_ctx); + alloc(parser, 0, pw); + return NULL; + } + + /* No longer need the features string */ + dom_string_unref(features); + parser->alloc = alloc; parser->pw = pw; @@ -184,6 +220,8 @@ xml_parser *xml_parser_create(const char *enc, const char *int_enc, */ void xml_parser_destroy(xml_parser *parser) { + dom_implementation_unref(parser->impl); + dom_string_unref(parser->udkey); xmlFreeParserCtxt(parser->xml_ctx); @@ -257,48 +295,29 @@ struct dom_document *xml_parser_get_document(xml_parser *parser) void xml_parser_start_document(void *ctx) { xml_parser *parser = (xml_parser *) ctx; - struct dom_implementation *impl; - struct dom_string *features; struct dom_document *doc; dom_exception err; /* Invoke libxml2's default behaviour */ xmlSAX2StartDocument(parser->xml_ctx); - /* Create a string representation of the features we want */ - err = dom_string_create_from_ptr_no_doc((dom_alloc) parser->alloc, - parser->pw, (const uint8_t *) "XML", SLEN("XML"), - &features); - if (err != DOM_NO_ERR) - return; - - /* Now, try to get an appropriate implementation from the registry */ - err = dom_implregistry_get_dom_implementation(features, &impl, - (dom_alloc) parser->alloc, parser->pw); - if (err != DOM_NO_ERR) { - dom_string_unref(features); - return; - } - - /* No longer need the features string */ - dom_string_unref(features); - /* Attempt to create a document */ - err = dom_implementation_create_document(impl, /* namespace */ NULL, - /* qname */ NULL, /* doctype */ NULL, - &doc, (dom_alloc) parser->alloc, parser->pw); + err = dom_implementation_create_document(parser->impl, + /* namespace */ NULL, + /* qname */ NULL, + /* doctype */ NULL, + &doc, + (dom_alloc) parser->alloc, + parser->pw); if (err != DOM_NO_ERR) { - dom_implementation_unref(impl); return; } - /* No longer need the implementation */ - dom_implementation_unref(impl); - /* Link nodes together */ err = xml_parser_link_nodes(parser, (struct dom_node *) doc, (xmlNodePtr) parser->xml_ctx->myDoc); if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) doc); return; } @@ -514,6 +533,31 @@ dom_exception xml_parser_link_nodes(xml_parser *parser, struct dom_node *dom, void xml_parser_add_node(xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { + static const char *node_types[] = { + "THIS_IS_NOT_A_NODE", + "XML_ELEMENT_NODE", + "XML_ATTRIBUTE_NODE", + "XML_TEXT_NODE", + "XML_CDATA_SECTION_NODE", + "XML_ENTITY_REF_NODE", + "XML_ENTITY_NODE", + "XML_PI_NODE", + "XML_COMMENT_NODE", + "XML_DOCUMENT_NODE", + "XML_DOCUMENT_TYPE_NODE", + "XML_DOCUMENT_FRAG_NODE", + "XML_NOTATION_NODE", + "XML_HTML_DOCUMENT_NODE", + "XML_DTD_NODE", + "XML_ELEMENT_DECL", + "XML_ATTRIBUTE_DECL", + "XML_ENTITY_DECL", + "XML_NAMESPACE_DECL", + "XML_XINCLUDE_START", + "XML_XINCLUDE_END", + "XML_DOCB_DOCUMENT_NODE" + }; + switch (child->type) { case XML_ELEMENT_NODE: xml_parser_add_element_node(parser, parent, child); @@ -522,11 +566,20 @@ void xml_parser_add_node(xml_parser *parser, struct dom_node *parent, xml_parser_add_text_node(parser, parent, child); break; case XML_CDATA_SECTION_NODE: + xml_parser_add_cdata_section(parser, parent, child); + break; case XML_ENTITY_REF_NODE: + xml_parser_add_entity_reference(parser, parent, child); + break; case XML_COMMENT_NODE: + xml_parser_add_comment(parser, parent, child); + break; case XML_DTD_NODE: + xml_parser_add_document_type(parser, parent, child); + break; default: - fprintf(stderr, "Unsupported node type: %d\n", child->type); + fprintf(stderr, "Unsupported node type: %s\n", + node_types[child->type]); } } @@ -809,6 +862,249 @@ void xml_parser_add_text_node(xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) text); } +/** + * Add a cdata section to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + */ +void xml_parser_add_cdata_section(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) +{ + struct dom_text *cdata, *ins_cdata; + struct dom_string *data; + dom_exception err; + + /* Create DOM string data for cdata section */ + err = dom_string_create_from_const_ptr(parser->doc, child->content, + strlen((const char *) child->content), &data); + if (err != DOM_NO_ERR) + return; + + /* Create text node */ + err = dom_document_create_cdata_section(parser->doc, data, &cdata); + if (err != DOM_NO_ERR) { + dom_string_unref(data); + return; + } + + /* No longer need data */ + dom_string_unref(data); + + /* Append cdata section to parent */ + err = dom_node_append_child(parent, (struct dom_node *) cdata, + (struct dom_node **) &ins_cdata); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) cdata); + return; + } + + /* We're not interested in the inserted cdata section */ + if (ins_cdata != NULL) + dom_node_unref((struct dom_node *) ins_cdata); + + /* Link nodes together */ + err = xml_parser_link_nodes(parser, (struct dom_node *) cdata, + child); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) cdata); + return; + } + + /* No longer interested in cdata section */ + dom_node_unref((struct dom_node *) cdata); +} + +/** + * Add an entity reference to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + */ +void xml_parser_add_entity_reference(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) +{ + struct dom_node *entity, *ins_entity; + struct dom_string *name; + xmlNodePtr c; + dom_exception err; + + /* Create name of entity reference */ + err = dom_string_create_from_const_ptr(parser->doc, child->name, + strlen((const char *) child->name), &name); + if (err != DOM_NO_ERR) + return; + + /* Create text node */ + err = dom_document_create_entity_reference(parser->doc, name, + &entity); + if (err != DOM_NO_ERR) { + dom_string_unref(name); + return; + } + + /* No longer need name */ + dom_string_unref(name); + + /* Mirror subtree (reference value) */ + for (c = child->children; c != NULL; c = c->next) { + xml_parser_add_node(parser, (struct dom_node *) entity, c); + } + + /* Append entity reference to parent */ + err = dom_node_append_child(parent, (struct dom_node *) entity, + (struct dom_node **) &ins_entity); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) entity); + return; + } + + /* We're not interested in the inserted entity reference */ + if (ins_entity != NULL) + dom_node_unref((struct dom_node *) ins_entity); + + /* Link nodes together */ + err = xml_parser_link_nodes(parser, (struct dom_node *) entity, + child); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) entity); + return; + } + + /* No longer interested in entity reference */ + dom_node_unref((struct dom_node *) entity); +} + +/** + * Add a comment to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + */ +void xml_parser_add_comment(xml_parser *parser, struct dom_node *parent, + xmlNodePtr child) +{ + struct dom_characterdata *comment, *ins_comment; + struct dom_string *data; + dom_exception err; + + /* Create DOM string data for comment */ + err = dom_string_create_from_const_ptr(parser->doc, child->content, + strlen((const char *) child->content), &data); + if (err != DOM_NO_ERR) + return; + + /* Create comment */ + err = dom_document_create_comment(parser->doc, data, &comment); + if (err != DOM_NO_ERR) { + dom_string_unref(data); + return; + } + + /* No longer need data */ + dom_string_unref(data); + + /* Append comment to parent */ + err = dom_node_append_child(parent, (struct dom_node *) comment, + (struct dom_node **) &ins_comment); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) comment); + return; + } + + /* We're not interested in the inserted comment */ + if (ins_comment != NULL) + dom_node_unref((struct dom_node *) ins_comment); + + /* Link nodes together */ + err = xml_parser_link_nodes(parser, (struct dom_node *) comment, + child); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) comment); + return; + } + + /* No longer interested in comment */ + dom_node_unref((struct dom_node *) comment); +} + +/** + * Add a document type to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + */ +void xml_parser_add_document_type(xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) +{ + xmlDtdPtr dtd = (xmlDtdPtr) child; + struct dom_document_type *doctype; + struct dom_string *qname, *public_id, *system_id; + dom_exception err; + + /* Create qname for doctype */ + err = dom_string_create_from_const_ptr(parser->doc, dtd->name, + strlen((const char *) dtd->name), &qname); + if (err != DOM_NO_ERR) + return; + + /* Create public ID for doctype */ + err = dom_string_create_from_const_ptr(parser->doc, + dtd->ExternalID, + strlen((const char *) dtd->ExternalID), + &public_id); + if (err != DOM_NO_ERR) { + dom_string_unref(qname); + return; + } + + /* Create system ID for doctype */ + err = dom_string_create_from_const_ptr(parser->doc, + dtd->SystemID, + strlen((const char *) dtd->SystemID), + &system_id); + if (err != DOM_NO_ERR) { + dom_string_unref(public_id); + dom_string_unref(qname); + return; + } + + /* Create doctype */ + err = dom_implementation_create_document_type(parser->impl, + qname, public_id, system_id, &doctype, + (dom_alloc) parser->alloc, parser->pw); + if (err != DOM_NO_ERR) { + dom_string_unref(system_id); + dom_string_unref(public_id); + dom_string_unref(qname); + return; + } + + /* No longer need qname, public_id, system_id */ + dom_string_unref(system_id); + dom_string_unref(public_id); + dom_string_unref(qname); + + /** \todo Add doctype to document (requires some libdom-internal API + * -- doctypes are immutable in the DOM) */ + UNUSED(parent); + + /* Link nodes together */ + err = xml_parser_link_nodes(parser, (struct dom_node *) doctype, + child); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) doctype); + return; + } + + /* No longer interested in doctype */ + dom_node_unref((struct dom_node *) doctype); +} + /* */ /* ------------------------------------------------------------------------*/ /* */ -- cgit v1.2.3