--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <libxml/parser.h>
+
+#include <string>
+#include <utility>
+#include <unordered_map>
+
+using namespace std;
+
+class Directive {
+ public:
+ virtual void process(xmlNode *node, bool clean) = 0;
+};
+
+class Replace : public Directive {
+ public:
+ Replace(const string &str) : str(str) {}
+ virtual void process(xmlNode *node, bool clean) {
+ node->children = xmlNewTextLen(reinterpret_cast<const xmlChar *>(str.data()), str.size());
+ }
+
+ private:
+ const string str;
+};
+
+class Substitute : public Directive {
+ public:
+ Substitute(const unordered_map<string, Directive*> &substitution_map)
+ : substitution_map(substitution_map) {}
+
+ virtual void process(xmlNode *node, bool clean) {
+ for (xmlNode *child = node->children; child != NULL; child = child->next) {
+ bool processed = false;
+
+ if (child->type == XML_ELEMENT_NODE) {
+ xmlElement *elem = reinterpret_cast<xmlElement *>(child);
+
+ // Find the ID, if any.
+ string id;
+#if 0
+ for (xmlAttribute *attr = elem->attributes; attr != NULL; attr = attr->nexth) {
+ // FIXME: namespace
+ if (strcmp(reinterpret_cast<const char *>(attr->name), "id") != 0) {
+ continue;
+ }
+ id = xmlNodeGetContent(attr->content);
+ }
+#endif
+
+ // Check all substitutions to see if we found anything appropriate.
+ for (auto it : substitution_map) {
+ if (it.first == reinterpret_cast<const char *>(child->name) ||
+ (!id.empty() && ("#" + it.first) == id)) {
+ it.second->process(child, clean);
+ processed = true;
+ break;
+ }
+ }
+ }
+
+ if (!processed) {
+ process(child, clean);
+ }
+ }
+ }
+
+ private:
+ const unordered_map<string, Directive*> &substitution_map;
+};
+
+int main(int argc, char **argv)
+{
+ LIBXML_TEST_VERSION
+
+ unordered_map<string, Directive*> master_map;
+ master_map.insert(make_pair("title", new Replace("A very basic example")));
+ master_map.insert(make_pair("#hello", new Replace("Hello world!")));
+
+ xmlDocPtr doc = xmlParseFile(argv[1]);
+ Substitute(master_map).process(xmlDocGetRootElement(doc), false);
+ xmlSaveFile("out.xml", doc);
+
+ xmlCleanupParser();
+ xmlMemoryDump();
+ return(0);
+}