Repository: ansible/ansible

Issue:
xml module: Catch common mistake with missing namespace
##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
xml

##### ANSIBLE VERSION
```
ansible 2.5.0 (devel 1fe5171f1a) last updated 2017/09/13 11:08:43 (GMT +200)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/administrator/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/administrator/ansible/lib/ansible
  executable location = /home/administrator/ansible/bin/ansible
  python version = 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)]
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
N/A

##### SUMMARY
Common pitfall for users new with lxml is forgetting to define the namespace prefixes and to use them in XPath in cases when XML document has namespaces defined. Some examples: #29078, cmprescott/ansible-xml#102, cmprescott/ansible-xml#107, cmprescott/ansible-xml#112 and cmprescott/ansible-xml#117.

##### STEPS TO REPRODUCE
I propose (pull request coming soon) detecting a case when XML document root has at least one namespace defined, but no namespace prefix is found in XPath. In such case additional message would be prepended to the error message passed to `fail_json()`. Note: This wouldn't catch (special) cases where namespace is defined in non-root element, or when a namespace is defined but it's wrong.

##### EXPECTED RESULTS
User gets a clue for this common pitfall like this:

```
XML document has namespace(s) defined, but no namespace prefix(es) used in Xpath!
Xpath /a/b/c causes a failure: Invalid expression
  -- tree is <a xmlns="http://example.com/examplens"><b><c/></b></a>
```

##### ACTUAL RESULTS
There's no clue in error message:

```
Xpath /a/b/c causes a failure: Invalid expression
  -- tree is <a xmlns="http://example.com/examplens"><b><c/></b></a>
```
Edit: corrected the "Actual results"


Discussion:
cc @cmprescott @dagwieers @tbielawa
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/files/xml.py b/lib/ansible/modules/files/xml.py
--- a/lib/ansible/modules/files/xml.py
+++ b/lib/ansible/modules/files/xml.py
@@ -545,8 +545,13 @@ def set_target_inner(module, tree, xpath, namespaces, attribute, value):
         if not is_node(tree, xpath, namespaces):
             changed = check_or_make_target(module, tree, xpath, namespaces)
     except Exception as e:
-        module.fail_json(msg="Xpath %s causes a failure: %s\n  -- tree is %s" %
-                             (xpath, e, etree.tostring(tree, pretty_print=True)), exception=traceback.format_exc(e))
+        missing_namespace = ""
+        # NOTE: This checks only the namespaces defined in root element!
+        # TODO: Implement a more robust check to check for child namespaces' existance
+        if len(tree.getroot().nsmap) > 0 and ":" not in xpath:
+            missing_namespace = "XML document has namespace(s) defined, but no namespace prefix(es) used in xpath!\n"
+        module.fail_json(msg="%sXpath %s causes a failure: %s\n  -- tree is %s" %
+                             (missing_namespace, xpath, e, etree.tostring(tree, pretty_print=True)), exception=traceback.format_exc())
 
     if not is_node(tree, xpath, namespaces):
         module.fail_json(msg="Xpath %s does not reference a node! tree is %s" %


Test patch: