Index: pjproject/trunk/pjlib-util/include/pjlib-util/xml.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/xml.h	(revision 2726)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/xml.h	(revision 2727)
@@ -150,5 +150,5 @@
 
 /**
- * Find first node with the specified name.
+ * Find first direct child node with the specified name.
  *
  * @param parent    Parent node.
@@ -157,8 +157,9 @@
  * @return	    XML node found or NULL.
  */
-PJ_DECL(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name);
-
-/**
- * Find first node with the specified name.
+PJ_DECL(pj_xml_node*) pj_xml_find_node(const pj_xml_node *parent, 
+				       const pj_str_t *name);
+
+/**
+ * Find next direct child node with the specified name.
  *
  * @param parent    Parent node.
@@ -168,9 +169,24 @@
  * @return	    XML node found or NULL.
  */
-PJ_DECL(pj_xml_node*) pj_xml_find_next_node(pj_xml_node *parent, pj_xml_node *node,
+PJ_DECL(pj_xml_node*) pj_xml_find_next_node(const pj_xml_node *parent, 
+					    const pj_xml_node *node,
 					    const pj_str_t *name);
 
 /**
- * Find first attribute within a node with the specified name and optional value.
+ * Recursively find the first node with the specified name in the child nodes
+ * and their children.
+ *
+ * @param parent    Parent node.
+ * @param name	    Node name to find.
+ *
+ * @return	    XML node found or NULL.
+ */
+PJ_DECL(pj_xml_node*) pj_xml_find_node_rec(const pj_xml_node *parent, 
+					   const pj_str_t *name);
+
+
+/**
+ * Find first attribute within a node with the specified name and optional 
+ * value.
  *
  * @param node	    XML Node.
@@ -180,5 +196,6 @@
  * @return	    XML attribute found, or NULL.
  */
-PJ_DECL(pj_xml_attr*) pj_xml_find_attr(pj_xml_node *node, const pj_str_t *name,
+PJ_DECL(pj_xml_attr*) pj_xml_find_attr(const pj_xml_node *node, 
+				       const pj_str_t *name,
 				       const pj_str_t *value);
 
@@ -188,5 +205,6 @@
  *
  * @param parent    Parent node.
- * @param name	    Optional name.
+ * @param name	    Optional name. If this is NULL, the name will not be
+ *		    matched.
  * @param data	    Data to be passed to matching function.
  * @param match	    Optional matching function.
@@ -194,7 +212,28 @@
  * @return	    The first matched node, or NULL.
  */
-PJ_DECL(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,
+PJ_DECL(pj_xml_node*) pj_xml_find( const pj_xml_node *parent, 
+				   const pj_str_t *name,
 				   const void *data, 
-				   pj_bool_t (*match)(pj_xml_node *, const void*));
+				   pj_bool_t (*match)(const pj_xml_node *, 
+						      const void*));
+
+
+/**
+ * Recursively find a child node with the specified name and match the 
+ * function.
+ *
+ * @param parent    Parent node.
+ * @param name	    Optional name. If this is NULL, the name will not be
+ *		    matched.
+ * @param data	    Data to be passed to matching function.
+ * @param match	    Optional matching function.
+ *
+ * @return	    The first matched node, or NULL.
+ */
+PJ_DECL(pj_xml_node*) pj_xml_find_rec(const pj_xml_node *parent, 
+				      const pj_str_t *name,
+				      const void *data, 
+				      pj_bool_t (*match)(const pj_xml_node*, 
+							 const void*));
 
 
Index: pjproject/trunk/pjlib-util/src/pjlib-util/xml.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/xml.c	(revision 2726)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/xml.c	(revision 2727)
@@ -341,7 +341,8 @@
 }
 
-PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name)
-{
-    pj_xml_node *node = parent->node_head.next;
+PJ_DEF(pj_xml_node*) pj_xml_find_node(const pj_xml_node *parent, 
+				      const pj_str_t *name)
+{
+    const pj_xml_node *node = parent->node_head.next;
 
     PJ_CHECK_STACK();
@@ -349,5 +350,5 @@
     while (node != (void*)&parent->node_head) {
 	if (pj_stricmp(&node->name, name) == 0)
-	    return node;
+	    return (pj_xml_node*)node;
 	node = node->next;
     }
@@ -355,6 +356,25 @@
 }
 
-
-PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node,
+PJ_DEF(pj_xml_node*) pj_xml_find_node_rec(const pj_xml_node *parent, 
+					  const pj_str_t *name)
+{
+    const pj_xml_node *node = parent->node_head.next;
+
+    PJ_CHECK_STACK();
+
+    while (node != (void*)&parent->node_head) {
+	pj_xml_node *found;
+	if (pj_stricmp(&node->name, name) == 0)
+	    return (pj_xml_node*)node;
+	found = pj_xml_find_node_rec(node, name);
+	if (found)
+	    return (pj_xml_node*)found;
+	node = node->next;
+    }
+    return NULL;
+}
+
+PJ_DEF(pj_xml_node*) pj_xml_find_next_node( const pj_xml_node *parent, 
+					    const pj_xml_node *node,
 					    const pj_str_t *name)
 {
@@ -364,5 +384,5 @@
     while (node != (void*)&parent->node_head) {
 	if (pj_stricmp(&node->name, name) == 0)
-	    return node;
+	    return (pj_xml_node*)node;
 	node = node->next;
     }
@@ -371,15 +391,16 @@
 
 
-PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name,
+PJ_DEF(pj_xml_attr*) pj_xml_find_attr( const pj_xml_node *node, 
+				       const pj_str_t *name,
 				       const pj_str_t *value)
 {
-    pj_xml_attr *attr = node->attr_head.next;
+    const pj_xml_attr *attr = node->attr_head.next;
     while (attr != (void*)&node->attr_head) {
 	if (pj_stricmp(&attr->name, name)==0) {
 	    if (value) {
 		if (pj_stricmp(&attr->value, value)==0)
-		    return attr;
+		    return (pj_xml_attr*)attr;
 	    } else {
-		return attr;
+		return (pj_xml_attr*)attr;
 	    }
 	}
@@ -391,19 +412,29 @@
 
 
-PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,
+PJ_DEF(pj_xml_node*) pj_xml_find( const pj_xml_node *parent, 
+				  const pj_str_t *name,
 				  const void *data, 
-				  pj_bool_t (*match)(pj_xml_node *, const void*))
-{
-    pj_xml_node *head = (pj_xml_node*) &parent->node_head, *node = head->next;
-
-    while (node != (void*)head) {
-	if (name && pj_stricmp(&node->name, name)==0) {
-	    if (match) {
-		if (match(node, data))
-		    return node;
-	    } else {
-		return node;
+				  pj_bool_t (*match)(const pj_xml_node *, 
+						     const void*))
+{
+    const pj_xml_node *node = (const pj_xml_node *)parent->node_head.next;
+
+    if (!name && !match)
+	return NULL;
+
+    while (node != (const pj_xml_node*) &parent->node_head) {
+	if (name) {
+	    if (pj_stricmp(&node->name, name)!=0) {
+		node = node->next;
+		continue;
 	    }
 	}
+	if (match) {
+	    if (match(node, data))
+		return (pj_xml_node*)node;
+	} else {
+	    return (pj_xml_node*)node;
+	}
+
 	node = node->next;
     }
@@ -411,4 +442,41 @@
 }
 
+PJ_DEF(pj_xml_node*) pj_xml_find_rec( const pj_xml_node *parent, 
+				      const pj_str_t *name,
+				      const void *data, 
+				      pj_bool_t (*match)(const pj_xml_node*, 
+							 const void*))
+{
+    const pj_xml_node *node = (const pj_xml_node *)parent->node_head.next;
+
+    if (!name && !match)
+	return NULL;
+
+    while (node != (const pj_xml_node*) &parent->node_head) {
+	pj_xml_node *found;
+
+	if (name) {
+	    if (pj_stricmp(&node->name, name)==0) {
+		if (match) {
+		    if (match(node, data))
+			return (pj_xml_node*)node;
+		} else {
+		    return (pj_xml_node*)node;
+		}
+	    }
+
+	} else if (match) {
+	    if (match(node, data))
+		return (pj_xml_node*)node;
+	}
+
+	found = pj_xml_find_rec(node, name, data, match);
+	if (found)
+	    return found;
+
+	node = node->next;
+    }
+    return NULL;
+}
 
 PJ_DEF(pj_xml_node*) pj_xml_clone( pj_pool_t *pool, const pj_xml_node *rhs)
