用XML文档替换XML元素

时间:2015-09-28 20:59:27

标签: python xml

我正在编写为我们的程序创建配置文件的代码。配置文件采用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是只读的。)

1 个答案:

答案 0 :(得分:0)

注意!注意!同胞Pythoners,请将XSLT添加到您的日常实践中。我现在已经回答了很多这些问题(即使是其他语言-R,VBA,PHP)。与SQL(一种特殊用途的声明性语言)非常相似,XSLT也是一种特殊用途的声明性语言,用于在各种最终用途需求中重构,重新格式化,设计和转换XML文档。

话虽如此,请考虑以下XSLT解决方案。 Python的lxml模块维护着一个XSLT处理器。特别适合您,XSLT具有document()功能,允许从外部xml文件中提取内容以获取转换后的文件。此外,xsl:choose的{​​{1}},xsl:whenxsl: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()