]> git.sesse.net Git - xml-template/blobdiff - c++0x/xml-template.cpp
Tweak C++0x API a bit, to prepare for include. Also, output to stdout instead of...
[xml-template] / c++0x / xml-template.cpp
index c1d43edb421bada23f539026b60f60577d6f5124..e8fc0edb086678d12ebea5eddc04fe355478d7e9 100644 (file)
@@ -23,9 +23,17 @@ void clean_node(xmlNode *node)
        }
 }
 
+// Does A begin with B?
+bool begins_with(const string &a, const string &b)
+{
+       return (a.compare(0, b.size(), b) == 0);
+}
+
 }  // namespace
 
 Directive::~Directive() {}
+       
+string Directive::get_contents() { return ""; }
 
 Replace::Replace(const string &str)
        : str(str) {}
@@ -37,9 +45,18 @@ void Replace::process(xmlNode *node, bool clean) {
        }
 }
 
+string Replace::get_contents() { return str; }
+
 Clone::Clone(const vector<Directive *> &subdirectives)
        : subdirectives(subdirectives) {}
-       
+
+Clone::Clone(const vector<Substitute *> &subdirectives_subs)
+{
+       for (auto it : subdirectives_subs) {
+               subdirectives.push_back(static_cast<Directive *>(it));
+       }
+}
+
 Clone::Clone(initializer_list<Directive *> subdirectives)
        : subdirectives(subdirectives) {}
 
@@ -57,6 +74,9 @@ void Clone::process(xmlNode *node, bool clean)
        vector<xmlNode *> new_nodes;
 
        for (auto it : subdirectives) {
+               if (it == NULL) {
+                       continue;
+               }
                xmlNode *new_node;
                xmlDOMWrapCloneNode(NULL, node->doc, node, &new_node, node->doc, NULL, 1, 0);
                it->process(new_node, clean);
@@ -79,6 +99,23 @@ void Clone::process(xmlNode *node, bool clean)
                clean_node(node);
        }
 }
+       
+Alternate::Alternate(const string &attribute,
+                    const vector<Substitute *> &subdirectives_subs,
+                    const vector<string> &alternatives)
+    : Clone(subdirectives_subs)
+{
+       unsigned jx = 0;
+       for (unsigned ix = 0; ix < subdirectives_subs.size(); ++ix) {
+               if (subdirectives_subs[ix] == NULL) {
+                       continue;
+               }
+               string value = alternatives[jx++ % alternatives.size()];
+               subdirectives_subs[ix]->substitution_map.insert(make_pair(
+                       attribute,
+                       new Replace { value }));
+       } 
+}
 
 Substitute::Substitute(const unordered_map<string, Directive*> &substitution_map)
        : substitution_map(substitution_map) {}
@@ -105,7 +142,8 @@ void Substitute::process(xmlNode *node, bool clean)
                        string id;
                        xmlAttr *id_attr = NULL;
                        for (xmlAttr *attr = child->properties; attr != NULL; attr = attr->next) {
-                               if (strcmp(reinterpret_cast<const char *>(attr->ns->href), "http://template.sesse.net/") == 0 &&
+                               if (attr->ns != NULL &&
+                                   strcmp(reinterpret_cast<const char *>(attr->ns->href), "http://template.sesse.net/") == 0 &&
                                    strcmp(reinterpret_cast<const char *>(attr->name), "id") == 0) {
                                        xmlChar *id_buf = xmlNodeGetContent(attr->children);
                                        id = reinterpret_cast<const char *>(id_buf);
@@ -119,11 +157,32 @@ void Substitute::process(xmlNode *node, bool clean)
 
                        // Check all substitutions to see if we found anything appropriate.
                        for (auto it : substitution_map) {
-                               if (it.first == reinterpret_cast<const char *>(child->name) ||
+                               string tag = reinterpret_cast<const char *>(child->name);
+
+                               // Attribute substitution.
+                               if (begins_with(it.first, tag + "/")) {
+                                       const xmlChar *attr_key = reinterpret_cast<const xmlChar *>(
+                                               it.first.substr(tag.size() + 1).c_str());
+                                       const xmlChar *attr_value = reinterpret_cast<const xmlChar *>(
+                                               it.second->get_contents().c_str());
+                                       xmlSetProp(child, attr_key, attr_value);
+                               } else if ((!id.empty() && begins_with(it.first, "#" + id + "/"))) {
+                                       const xmlChar *attr_key = reinterpret_cast<const xmlChar *>(
+                                               it.first.substr(tag.size() + 2).c_str());
+                                       const xmlChar *attr_value = reinterpret_cast<const xmlChar *>(
+                                               it.second->get_contents().c_str());
+                                       xmlSetProp(child, attr_key, attr_value);
+                               }
+
+                               if (processed) {
+                                       continue;
+                               }
+
+                               // Regular substitution.
+                               if (it.first == tag ||
                                    (!id.empty() && it.first == ("#" + id))) {
                                        it.second->process(child, clean);
                                        processed = true;
-                                       break;
                                }
                        }
                }
@@ -137,17 +196,21 @@ void Substitute::process(xmlNode *node, bool clean)
        }
 }
        
-void process_file(const string &input_filename,
-                  const string &output_filename,
-                  Directive *root_directive)
+xmlDocPtr process_file(const string &input_filename,
+                       Directive *root_directive)
 {
        LIBXML_TEST_VERSION
 
        xmlDocPtr doc = xmlParseFile(input_filename.c_str());
        root_directive->process(xmlDocGetRootElement(doc), true);
-       xmlSaveFile(output_filename.c_str(), doc);
-       xmlFreeDoc(doc);
-
        xmlCleanupParser();
        xmlMemoryDump();
+       return doc;
+}
+
+void output_to_fd_and_free(xmlDocPtr doc, int fd)
+{
+       xmlOutputBufferPtr buf = xmlOutputBufferCreateFd(fd, NULL);
+       xmlSaveFileTo(buf, doc, NULL);
+       xmlFreeDoc(doc);
 }