pidgin: 5cd85b37: xmlnode: Add xmlnode_strip_prefixes
darkrain42 at pidgin.im
darkrain42 at pidgin.im
Sun Sep 4 17:15:49 EDT 2011
----------------------------------------------------------------------
Revision: 5cd85b37b438c361ff191199de99c6ba9b7b0e49
Parent: d9b2d73b4d6e64c7768adff67303cfa8816d6d2e
Author: darkrain42 at pidgin.im
Date: 09/04/11 17:06:26
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/5cd85b37b438c361ff191199de99c6ba9b7b0e49
Changelog:
xmlnode: Add xmlnode_strip_prefixes
This is largely based on a patch from Thijs (sphynx/xnyhps) Alkemade, with
some modifications by me to try to maintain namespaces of elements
as best as we can.
I also rewrote xmlnode_get_default_namespace not to use recursion.
References #14529
Changes against parent d9b2d73b4d6e64c7768adff67303cfa8816d6d2e
patched libpurple/tests/test_xmlnode.c
patched libpurple/xmlnode.c
patched libpurple/xmlnode.h
-------------- next part --------------
============================================================
--- libpurple/xmlnode.c aee6abd361df1eb41d15d5ce1333f73a26723fa6
+++ libpurple/xmlnode.c 788fc4f961ccbbd827cecb0c0fca0b164de0520d
@@ -262,10 +262,18 @@ void xmlnode_set_namespace(xmlnode *node
void xmlnode_set_namespace(xmlnode *node, const char *xmlns)
{
+ char *tmp;
g_return_if_fail(node != NULL);
- g_free(node->xmlns);
+ tmp = node->xmlns;
node->xmlns = g_strdup(xmlns);
+
+ if (node->namespace_map) {
+ g_hash_table_insert(node->namespace_map,
+ g_strdup(""), g_strdup(xmlns));
+ }
+
+ g_free(tmp);
}
const char *xmlnode_get_namespace(const xmlnode *node)
@@ -277,22 +285,27 @@ const char *xmlnode_get_default_namespac
const char *xmlnode_get_default_namespace(const xmlnode *node)
{
+ const xmlnode *current_node;
const char *ns = NULL;
+
g_return_val_if_fail(node != NULL, NULL);
- /* If this node does *not* have a prefix, node->xmlns is the default
- * namespace. Otherwise, it's the prefix namespace.
- */
- if (!node->prefix && node->xmlns) {
- return node->xmlns;
- } else if (node->namespace_map) {
- ns = g_hash_table_lookup(node->namespace_map, "");
+ current_node = node;
+ while (current_node) {
+ /* If this node does *not* have a prefix, node->xmlns is the default
+ * namespace. Otherwise, it's the prefix namespace.
+ */
+ if (!current_node->prefix && current_node->xmlns) {
+ return current_node->xmlns;
+ } else if (current_node->namespace_map) {
+ ns = g_hash_table_lookup(current_node->namespace_map, "");
+ if (ns && *ns)
+ return ns;
+ }
+
+ current_node = current_node->parent;
}
- /* No default ns found? Walk up the tree looking for one */
- if (!(ns && *ns) && node->parent)
- ns = xmlnode_get_default_namespace(node->parent);
-
return ns;
}
@@ -310,6 +323,53 @@ const char *xmlnode_get_prefix(const xml
return node->prefix;
}
+const char *xmlnode_get_prefix_namespace(const xmlnode *node, const char *prefix)
+{
+ const xmlnode *current_node;
+
+ g_return_val_if_fail(node != NULL, NULL);
+ g_return_val_if_fail(prefix != NULL, xmlnode_get_default_namespace(node));
+
+ current_node = node;
+ while (current_node) {
+ if (current_node->prefix && g_str_equal(prefix, current_node->prefix) &&
+ current_node->xmlns) {
+ return current_node->xmlns;
+ } else if (current_node->namespace_map) {
+ const char *ns = g_hash_table_lookup(current_node->namespace_map, prefix);
+ if (ns && *ns) {
+ return ns;
+ }
+ }
+
+ current_node = current_node->parent;
+ }
+
+ return NULL;
+}
+
+void xmlnode_strip_prefixes(xmlnode *node)
+{
+ xmlnode *child;
+ const char *prefix;
+
+ g_return_if_fail(node != NULL);
+
+ for (child = node->child; child; child = child->next) {
+ if (child->type == XMLNODE_TYPE_TAG)
+ xmlnode_strip_prefixes(child);
+ }
+
+ prefix = xmlnode_get_prefix(node);
+ if (prefix) {
+ const char *ns = xmlnode_get_prefix_namespace(node, prefix);
+ xmlnode_set_namespace(node, ns);
+ xmlnode_set_prefix(node, NULL);
+ } else {
+ xmlnode_set_namespace(node, xmlnode_get_default_namespace(node));
+ }
+}
+
xmlnode *xmlnode_get_parent(const xmlnode *child)
{
g_return_val_if_fail(child != NULL, NULL);
============================================================
--- libpurple/xmlnode.h c2dc393a2b8e3667e6b762a942f25f6c1db453dc
+++ libpurple/xmlnode.h 549855bb896a6d1ef06998c61f089d0adee65d6e
@@ -243,6 +243,15 @@ const char *xmlnode_get_default_namespac
const char *xmlnode_get_default_namespace(const xmlnode *node);
/**
+ * Returns the defined namespace for a prefix.
+ *
+ * @param node The node from which to start the search.
+ * @param prefix The prefix for which to return the associated namespace.
+ * @return The namespace for this prefix.
+ */
+const char *xmlnode_get_prefix_namespace(const xmlnode *node, const char *prefix);
+
+/**
* Sets the prefix of a node
*
* @param node The node to qualify
@@ -259,6 +268,19 @@ const char *xmlnode_get_prefix(const xml
const char *xmlnode_get_prefix(const xmlnode *node);
/**
+ * Remove all element prefixes from an xmlnode tree. The prefix's
+ * namespace is transformed into the default namespace for an element.
+ *
+ * Note that this will not necessarily remove all prefixes in use
+ * (prefixed attributes may still exist), and that this usage may
+ * break some applications (SOAP / XPath apparently often rely on
+ * the prefixes having the same name.
+ *
+ * @param node The node from which to strip prefixes
+ */
+void xmlnode_strip_prefixes(xmlnode *node);
+
+/**
* Gets the parent node.
*
* @param child The child node.
============================================================
--- libpurple/tests/test_xmlnode.c a64c414376163c6a17fb2bb21b31fd782e6061d8
+++ libpurple/tests/test_xmlnode.c 15242821df719edc44b882586ccfface0905aa11
@@ -81,6 +81,41 @@ END_TEST
}
END_TEST
+
+START_TEST(test_strip_prefixes)
+{
+ const char *xml_doc = "<message xmlns='jabber:client' from='user at gmail.com/resource' to='another_user at darkrain42.org' type='chat' id='purple'>"
+ "<cha:active xmlns:cha='http://jabber.org/protocol/chatstates'/>"
+ "<body>xvlc xvlc</body>"
+ "<im:html xmlns:im='http://jabber.org/protocol/xhtml-im'>"
+ "<xht:body xmlns:xht='http://www.w3.org/1999/xhtml'>"
+ "<xht:p>xvlc <xht:span style='font-weight: bold;'>xvlc</xht:span></xht:p>"
+ "</xht:body>"
+ "</im:html>"
+ "</message>";
+ const char *out = "<message xmlns='jabber:client' from='user at gmail.com/resource' to='another_user at darkrain42.org' type='chat' id='purple'>"
+ "<active xmlns:cha='http://jabber.org/protocol/chatstates' xmlns='http://jabber.org/protocol/chatstates'/>"
+ "<body>xvlc xvlc</body>"
+ "<html xmlns:im='http://jabber.org/protocol/xhtml-im' xmlns='http://jabber.org/protocol/xhtml-im'>"
+ "<body xmlns:xht='http://www.w3.org/1999/xhtml' xmlns='http://www.w3.org/1999/xhtml'>"
+ "<p>xvlc <span style='font-weight: bold;'>xvlc</span></p>"
+ "</body>"
+ "</html>"
+ "</message>";
+ char *str;
+ xmlnode *xml;
+
+ xml = xmlnode_from_str(xml_doc, -1);
+ fail_if(xml == NULL, "Failed to parse XML");
+
+ xmlnode_strip_prefixes(xml);
+ str = xmlnode_to_str(xml, NULL);
+ assert_string_equal_free(out, str);
+
+ xmlnode_free(xml);
+}
+END_TEST
+
Suite *
xmlnode_suite(void)
{
@@ -89,6 +124,7 @@ xmlnode_suite(void)
TCase *tc = tcase_create("xmlnode");
tcase_add_test(tc, test_xmlnode_billion_laughs_attack);
tcase_add_test(tc, test_xmlnode_prefixes);
+ tcase_add_test(tc, test_strip_prefixes);
suite_add_tcase(s, tc);
More information about the Commits
mailing list