我正在编写为我们的程序创建配置文件的代码。配置文件采用XML格式。
我使用Python的xml.dom.minidom模块来解析XML文件。我希望能够将配置文件分解为2个或更多较小的XML文件。
假设我有一个名为main_config.xml的文件:
<configuration>
<server name="my_servername" ip="10.10.10.10">
<disk>
<volume>/dev/sdc1</volume>
</disk>
</server>
<server>
<redirect loc="./child.xml"
</server>
<server name="server3" ip="10.10.10.13">
<disk>
<volume>/dev/sdf1</volume>
</disk>
</server>
&lt;&#34;重定向&#34;&gt;元素有一个&#34; loc&#34;指向名为&#34; child.xml&#34;
的文件的属性文件&#34; child.xml&#34;有这个
<server name="server2" ip="10.10.10.12">
<disk>
<volume>/dev/sde1</volume>
</disk>
</server>
{注意:这些是简单的小配置文件。我使用的那些更长,更长(5000行左右)并且难以编辑,因此,建议将配置文件分解为几个更小,更模块化的配置,因此编辑起来更容易}
我想用xml.dom.minidom做到
1)读入main_config.xml中的XML文档
2)从main_config.xml解析XML文档
3)如果我看到&lt;&#34;重定向&#34;&gt;元素,转到&#34; loc&#34;属性指向
4)从&#34; child.xml&#34;
中读取XML文档5)替换&lt;&#34;服务器&#34;&gt;带有孩子的元素&lt;&#34;重定向&#34;&gt; main_config.xml中的元素与&lt;&#34;服务器&#34;&gt;来自child.xml的元素,以便XML文档如下所示:
<configuration>
<server name="my_servername" ip="10.10.10.10">
<disk>
<volume>/dev/sdc1</volume>
</disk>
</server>
<server name="server2" ip="10.10.10.12">
<disk>
<volume>/dev/sde1</volume>
</disk>
</server>
<server name="server3" ip="10.10.10.13">
<disk>
<volume>/dev/sdf1</volume>
</disk>
</server>
使用xml.dom.minidom,我已经可以执行第1步到第4步。但是,我被困在第5步,因为&lt;&#34;服务器&#34;&gt; main_config.xml中的element被认为是ELEMENT_NODE类型的nodeType,但是&lt;&#34; server&#34;&gt; child.xml中的元素被视为DOCUMENT_TYPE_NODE。因此,我不能使用node.replaceChild()调用,因为xml.dom.minidom抱怨您不能将XML文档作为子文件放到&lt;&#34;配置&#34;&gt;。
我可以采用一种方法来执行此操作,即从child.xml文件中遍历XML文档中的XML树,删除&lt;&#34; server&#34;&gt;来自main_config.xml的XML文档中的元素,然后创建一个新的&lt;&#34;服务器&#34;&gt; main_config.xml中的元素,包含child.xml文件中的所有节点/属性。但我不愿意这样做,除非它是最后的手段。
还有其他方法可以用DOCUMENT_TYPE_NODE替换ELEMENT_NODE吗?有没有办法更改节点对象的nodeType,以便replaceChild()工作? (xml.dom.minidom表示nodeType是只读的。)
答案 0 :(得分:0)
注意!注意!同胞Pythoners,请将XSLT添加到您的日常实践中。我现在已经回答了很多这些问题(即使是其他语言-R,VBA,PHP)。与SQL(一种特殊用途的声明性语言)非常相似,XSLT也是一种特殊用途的声明性语言,用于在各种最终用途需求中重构,重新格式化,设计和转换XML文档。
话虽如此,请考虑以下XSLT解决方案。 Python的lxml模块维护着一个XSLT处理器。特别适合您,XSLT具有document()
功能,允许从外部xml文件中提取内容以获取转换后的文件。此外,xsl:choose
的{{1}},xsl:when
和xsl:choose
的布尔逻辑可用于处理不同的if/then/else
节点重定向。最后,可以传递动态变量(特别是位于server
属性中的文件名)。确保child.xml与main_config.xml位于同一目录中。
XSLT脚本(保存为.xsl或嵌入.py中,如果是,请使用lxml&#39; s redirect/@loc
)
fromstring()
Python脚本
<?xml version="1.0" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="configuration">
<configuration>
<xsl:for-each select="//server">
<xsl:choose>
<xsl:when test="count(redirect)>0">
<xsl:variable select="redirect/@loc" name="xmldoc"/>
<xsl:copy-of select="document($xmldoc)/server" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</configuration>
</xsl:template>
</xsl:transform>
<强>输出强>
import os
import lxml.etree as ET
# GET CURRENT PATH
cd = os.path.dirname(os.path.abspath(__file__))
# LOAD ORIGINAL XML AND XSL FILES
dom = ET.parse(os.path.join(cd, 'main_config.xml'))
xslt = ET.parse(os.path.join(cd, 'XSLTsript.xsl'))
# TRANSFORM XML
transform = ET.XSLT(xslt)
newdom = transform(dom)
# OUTPUT FINAL XML
tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True, xml_declaration=True)
xmlfile = open(os.path.join(cd, 'output.xml'),'wb')
xmlfile.write(tree_out)
xmlfile.close()