使用Ansible community.general.xml模块编辑XML时的命名空间报错问题
问题与解决方案
问题背景
使用Ansible的community.general.xml模块操作带命名空间的XML文件(namespace-test.xml)时,尝试添加<xi:include>子节点报错,后续需要添加多个同类型节点。
原XML文件内容
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd"> <core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq:core "> </core> </configuration>
初始报错的Ansible任务
- name: include modular XML configuration file community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core input_type: xml add_children: - '<xi:include href="/conf/xmlconfig-to-include.xml"/>' namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" pretty_print: yes
报错信息
Error while parsing child element: Namespace prefix xi on include is not defined
后续需求
需要添加多个xi:include节点,最终XML效果如下:
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd"> <core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq:core "> <xi:include href="/conf/addresses.xml"/> <xi:include href="/conf/address-settings.xml"/> <xi:include href="/conf/security-settings.xml"/> </core> </configuration>
错误原因
add_children中传入的XML字符串未显式声明xi命名空间,尽管在任务的namespaces参数里定义了该命名空间,但解析子节点字符串时,上下文无法识别未声明的前缀,导致报错。
解决方案
方案1:给子节点字符串添加临时命名空间声明
在要添加的<xi:include>节点里直接声明xi命名空间,确保解析时能识别前缀:
- name: include modular XML configuration file community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core input_type: xml add_children: - '<xi:include href="/conf/xmlconfig-to-include.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>' namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" pretty_print: yes
注:添加后节点会多一个xmlns:xi属性,但父节点已存在该声明,不影响XML功能。
方案2:结构化定义子节点(推荐,支持多节点)
使用键值对形式定义节点,无需手写XML字符串,直接通过tag和attributes指定节点信息,同时利用namespaces里的定义识别前缀:
- name: add multiple xi:include nodes to core community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core input_type: xml add_children: - tag: xi:include attributes: href: "/conf/addresses.xml" - tag: xi:include attributes: href: "/conf/address-settings.xml" - tag: xi:include attributes: href: "/conf/security-settings.xml" namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" pretty_print: yes
方案3:保证幂等性(避免重复添加节点)
如果需要重复执行任务时不重复添加相同节点,可先检查节点是否存在,再执行添加操作:
- name: check if addresses include exists community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core/xi:include[@href="/conf/addresses.xml"] namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" register: addresses_include failed_when: addresses_include.failed and 'No matching nodes' not in addresses_include.msg - name: add addresses include if not exists community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core input_type: xml add_children: - tag: xi:include attributes: href: "/conf/addresses.xml" namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" pretty_print: yes when: not addresses_include.matches - name: check if address-settings include exists community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core/xi:include[@href="/conf/address-settings.xml"] namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" register: address_settings_include failed_when: address_settings_include.failed and 'No matching nodes' not in address_settings_include.msg - name: add address-settings include if not exists community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core input_type: xml add_children: - tag: xi:include attributes: href: "/conf/address-settings.xml" namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" pretty_print: yes when: not address_settings_include.matches - name: check if security-settings include exists community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core/xi:include[@href="/conf/security-settings.xml"] namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" register: security_settings_include failed_when: security_settings_include.failed and 'No matching nodes' not in security_settings_include.msg - name: add security-settings include if not exists community.general.xml: path: namespace-test.xml xpath: /conf:configuration/core:core input_type: xml add_children: - tag: xi:include attributes: href: "/conf/security-settings.xml" namespaces: conf: urn:activemq core: urn:activemq:core xi: "http://www.w3.org/2001/XInclude" pretty_print: yes when: not security_settings_include.matches
内容的提问来源于stack exchange,提问作者Gullah Geechee
相关产品推荐
相关产品推荐

