X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=php5-swig%2Fxml-template.swig;h=458296ef994e6d782a6f854854d57c921816298d;hb=7d1da52761b9ec9747c4400609658a379a34392c;hp=d70e223fec9d1355d7727247876bedf630105374;hpb=c106bd8b8b015aa433ff94a1c6ef63d82dfb4440;p=xml-template diff --git a/php5-swig/xml-template.swig b/php5-swig/xml-template.swig index d70e223..458296e 100644 --- a/php5-swig/xml-template.swig +++ b/php5-swig/xml-template.swig @@ -8,6 +8,7 @@ struct XmlDocPtrWrapper { %{ #include +#include #include "../c++11/xml-template.h" @@ -71,6 +72,16 @@ Directive* convert_php_objects_to_directive(zval *obj) char *str = Z_STRVAL_P(obj); return new Replace(str); } + case IS_LONG: { + char str[256]; + snprintf(str, sizeof(str), "%ld", Z_LVAL_P(obj)); + return new Replace(str); + } + case IS_DOUBLE: { + char str[256]; + snprintf(str, sizeof(str), "%f", Z_DVAL_P(obj)); + return new Replace(str); + } case IS_RESOURCE: { XmlDocPtrWrapper *doc; if (SWIG_ConvertPtr(obj, (void **)&doc, SWIGTYPE_p_XmlDocPtrWrapper, 0) < 0 || doc == NULL) { @@ -79,7 +90,7 @@ Directive* convert_php_objects_to_directive(zval *obj) return new ReplaceInclude(xmlCopyDoc((*doc)->ptr, 1)); } case IS_NULL: - return NULL; + return new Replace { "" }; default: printf("WARNING: Unknown type %d!\n", Z_TYPE_P(obj)); break; @@ -95,12 +106,10 @@ XmlDocPtrWrapper XML_Template_process_file(const std::string &input_filename, Di return XmlDocPtrWrapper(new XmlDocWrapper { ret }); } -XmlDocPtrWrapper XML_Template_process(XmlDocPtrWrapper doc, Directive *root_directive, bool clean) +void XML_Template_process(XmlDocPtrWrapper doc, Directive *root_directive, bool clean) { - xmlDocPtr new_doc = xmlCopyDoc(doc->ptr, 1); - root_directive->process(xmlDocGetRootElement(new_doc), clean); + root_directive->process(xmlDocGetRootElement(doc->ptr), clean); delete root_directive; - return XmlDocPtrWrapper(new XmlDocWrapper { new_doc }); } namespace { @@ -119,14 +128,118 @@ int close_string(void *context) } // namespace -std::string XML_Template_convert_doc_to_string(XmlDocPtrWrapper doc) +std::string XML_Template_convert_doc_to_string(XmlDocPtrWrapper doc, bool prettyprint) { + xmlIndentTreeOutput = prettyprint; std::string ret; xmlOutputBufferPtr buf = xmlOutputBufferCreateIO(write_to_string, close_string, &ret, NULL); - xmlSaveFileTo(buf, doc->ptr, NULL); + xmlSaveFormatFileTo(buf, doc->ptr, "UTF-8", prettyprint); return ret; } - + +namespace { + +// Remove document fragments (ie. move their content up in the parent node) +// and combine neighboring text nodes into one. +void normalize_node(xmlNodePtr node) +{ + xmlNode *next_child; + for (xmlNode *child = node->children; child != NULL; child = next_child) { + next_child = child->next; + if (child->type == XML_DOCUMENT_FRAG_NODE) { + while (child->children != NULL) { + xmlAddPrevSibling(child, child->children); + } + + xmlUnlinkNode(child); + xmlFreeNode(child); + } + } + + // xmlAddPrevSibling merges adjacent text nodes, but many other things + // (including xmlUnlinkNode) do not, so make an extra pass. + for (xmlNode *child = node->children; child != NULL; child = child->next) { + while (child->type == XML_TEXT_NODE && (child->next != NULL && child->next->type == XML_TEXT_NODE)) { + xmlNode *next_child = child->next; + + xmlChar *content = xmlNodeGetContent(next_child); + xmlNodeAddContent(child, content); + xmlFree(content); + + xmlUnlinkNode(next_child); + xmlFreeNode(next_child); + } + normalize_node(child); + } +} + +// Clean the page of non-necessary whitespace. Leaves whitespace alone if and +// only if xml:space="preserve" on the element. (IOW, it doesn't parse the DTDs, +// nor the CSS.) +void clean_node(xmlNodePtr node, bool preserve_whitespace, bool aggressive) +{ + if (node->type == XML_TEXT_NODE) { + std::string content = reinterpret_cast(xmlNodeGetContent(node)); + if (!preserve_whitespace) { + unsigned dstpos = 0; + for (unsigned srcpos = 0; srcpos < content.size(); ++srcpos, ++dstpos) { + if (content[srcpos] == '\n' || + content[srcpos] == '\t' || + content[srcpos] == ' ') { + content[dstpos] = ' '; + + // compress double spaces + if (dstpos > 0 && content[dstpos - 1] == ' ') { + --dstpos; + } + } else { + content[dstpos] = content[srcpos]; + } + } + content.resize(dstpos); + } + if (content.empty() || (aggressive && content == " ")) { + xmlUnlinkNode(node); + xmlFreeNode(node); + } else { + xmlNodeSetContentLen(node, reinterpret_cast(content.data()), content.size()); + } + } else { + if (node->type == XML_ELEMENT_NODE) { + xmlChar *space = xmlGetProp(node, reinterpret_cast("xml:space")); + preserve_whitespace = (space != NULL && strcmp(reinterpret_cast(space), "preserve") == 0); + } + + xmlNode *next_child; + for (xmlNode *child = node->children; child != NULL; child = next_child) { + next_child = child->next; + clean_node(child, preserve_whitespace, aggressive); + } + + if (node->type == XML_ELEMENT_NODE && node->children == NULL) { + std::string tag = reinterpret_cast(node->name); + + // These are the only elements allowed in XHTML to be EMPTY, + // so insert dummy nodes to prevent the output from using + // the syntax where not appropriate. + if (tag != "base" && tag != "meta" && tag != "link" && tag != "hr" && + tag != "br" && tag != "param" && tag != "img" && tag != "area" && + tag != "input" && tag != "col") { + xmlNode *text = xmlNewText(reinterpret_cast("")); + xmlAddChild(node, text); + } + } + } +} + +} // namespace + +void XML_Template_clean_whitespace(XmlDocPtrWrapper doc, bool aggressive) +{ + normalize_node(xmlDocGetRootElement(doc->ptr)); + clean_node(xmlDocGetRootElement(doc->ptr), false, aggressive); +} + %} %typemap(in) Directive* { @@ -134,6 +247,7 @@ std::string XML_Template_convert_doc_to_string(XmlDocPtrWrapper doc) } XmlDocPtrWrapper XML_Template_process_file(const std::string &input_filename, Directive *root_directive, bool clean); -XmlDocPtrWrapper XML_Template_process(XmlDocPtrWrapper doc, Directive *root_directive, bool clean); -std::string XML_Template_convert_doc_to_string(XmlDocPtrWrapper doc); +void XML_Template_process(XmlDocPtrWrapper doc, Directive *root_directive, bool clean); +void XML_Template_clean_whitespace(XmlDocPtrWrapper doc, bool aggressive); +std::string XML_Template_convert_doc_to_string(XmlDocPtrWrapper doc, bool prettyprint);