【问题标题】:How to replace the contents of a XML child element with a complement DOM document object from another xml file?如何用另一个 xml 文件中的补充 DOM 文档对象替换 XML 子元素的内容?
【发布时间】:2022-01-06 11:08:43
【问题描述】:

我已经使用下面的代码解析并存储了一个 xml 文件作为文档对象。

import xml.dom.minidom as DOM
import shutil
import xml.etree.ElementTree as ET
metadata_path=r"C:\Users\ar\DD2MI_result.xml"
new_metadata=DOM.parse(metadata_path)

现在我想用这个完整的文档对象来替换另一个xml文件中子节点的数据。我能够像这样获得子节点:

output_draft = r"C:\Users\ar\airquality.xml"
doc = DOM.parse(output_draft)
meta=doc.getElementsByTagName('XmlDoc')
for metadata in meta:
    if metadata.firstChild.data:
        metadata.firstChild.replaceData(0,len(new_metadata),new_metadata)
        print (metadata.firstChild.data)

当我运行上面的代码时,我得到了错误,TypeError: object of type 'Document' has no len() 我理解它是一个对象。如何使用完整的对象或文件来替换当前内容?

airquality.xml

<?xml version="1.0" encoding="UTF-8"?>
<gmd:MD_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:gco="http://www.isotc211.org/2005/gco"
                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
                 xmlns:srv="http://www.isotc211.org/2005/srv"
                 xmlns:gmx="http://www.isotc211.org/2005/gmx"
                 xmlns:gsr="http://www.isotc211.org/2005/gsr"
                 xmlns:gss="http://www.isotc211.org/2005/gss"
                 xmlns:gts="http://www.isotc211.org/2005/gts"
                 xmlns:gml="http://www.opengis.net/gml/3.2"
                 xmlns:xlink="http://www.w3.org/1999/xlink"
                 xmlns:xs="http://www.w3.org/2001/XMLSchema"
                 xsi:schemaLocation="http://www.isotc211.org/2005/gmd http://schemas.opengis.net/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd">
   <gmd:fileIdentifier>
      <gco:CharacterString>https://hdl.handle.net/20.500.12085/1f97f2a1-75fc-4110-ae22-f873d7d86565@metadata</gco:CharacterString>
   </gmd:fileIdentifier>
   <gmd:language>
      <gmd:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng">eng</gmd:LanguageCode>
   </gmd:language>
 </gmd:MD_Metadata>

替换前的DD2MI_result.xml

<SVCManifest xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:type="typens:SVCManifest">
<Databases xsi:type="typens:ArrayOfSVCDatabase" />
<Resources xsi:type="typens:ArrayOfSVCResource">
<SVCResource xsi:type="typens:SVCResource">
<ID>{429221BF-D0A1-40D8-9DC1-B41D269E95C7}</ID>
<Name>test.crf</Name>
<Metadata xsi:type="typens:XmlPropertySet">
<XmlDoc>&lt;?xml version="1.0"?&gt;
&lt;metadata xml:lang="en"&gt;&lt;Esri&gt;&lt;CreaDate&gt;20211219&lt;/metadata&gt;
</XmlDoc>
</Metadata>
</SVCManifest>

替换后的DD2MI_result.xml

<SVCManifest xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:type="typens:SVCManifest">
<Databases xsi:type="typens:ArrayOfSVCDatabase" />
<Resources xsi:type="typens:ArrayOfSVCResource">
<SVCResource xsi:type="typens:SVCResource">
<ID>{429221BF-D0A1-40D8-9DC1-B41D269E95C7}</ID>
<Name>test.crf</Name>
<Metadata xsi:type="typens:XmlPropertySet">
<XmlDoc><?xml version="1.0" encoding="UTF-8"?>
<gmd:MD_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:gco="http://www.isotc211.org/2005/gco"
                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
                 xmlns:srv="http://www.isotc211.org/2005/srv"
                 xmlns:gmx="http://www.isotc211.org/2005/gmx"
                 xmlns:gsr="http://www.isotc211.org/2005/gsr"
                 xmlns:gss="http://www.isotc211.org/2005/gss"
                 xmlns:gts="http://www.isotc211.org/2005/gts"
                 xmlns:gml="http://www.opengis.net/gml/3.2"
                 xmlns:xlink="http://www.w3.org/1999/xlink"
                 xmlns:xs="http://www.w3.org/2001/XMLSchema"
                 xsi:schemaLocation="http://www.isotc211.org/2005/gmd http://schemas.opengis.net/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd">
   <gmd:fileIdentifier>
      <gco:CharacterString>https://hdl.handle.net/20.500.12085/1f97f2a1-75fc-4110-ae22-f873d7d86565@metadata</gco:CharacterString>
   </gmd:fileIdentifier>
   <gmd:language>
      <gmd:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng">eng</gmd:LanguageCode>
   </gmd:language>
 </gmd:MD_Metadata>
</XmlDoc>
</Metadata>
</SVCManifest>

【问题讨论】:

  • 请编辑您的问题并在替换前后添加DD2MI_result.xmlairquality.xml简化版本。
  • @JackFleeting 我已经添加了简化版的文件
  • 由于多种原因,您问题中的DD2MI_result.xml 格式不正确。特别有问题的是&lt;XmlDoc&gt;&amp;lt;?xml version="1.0"?&amp;gt; &amp;lt;metadata xml:lang="en"&amp;gt;&amp;lt;Esri&amp;gt;&amp;lt;CreaDate&amp;gt;20211219&amp;lt;/metadata&amp;gt;&lt;/XmlDoc&gt;。请重新检查。另请注意,您不能在同一个 xml 文件中包含两个 xml 声明,这会使您的问题中的预期输出也不是格式正确的。
  • @JackFleeting 我更新了代码。 DD2MI_result.xml 文件是一个清单文件,但可以像普通 xml 文件一样对其进行操作。您提到的第一个问题不是问题,因为元素中的内容实际上引用了文件中的其他元素,这就是为什么它显示很多&amp;。我只想删除所有这些内容并将其替换为其他文件的内容。至于第二个问题,我在上面的例子中已经解决了,我错误地做了多个声明。开始时没有声明。
  • 替换后的标记格式不正确,因此不是 XML。特别是 XML 标头,&lt;?xml ...?&gt; 必须是第一行,或者如果是嵌入式 XML,则必须将其标记符号替换为 XML 实体(如原始文档)。甚至可以考虑将 CData 用于嵌入式文档!

标签: python xml


【解决方案1】:

您的DD2MI_result.xml 格式仍然不正确 - 例如,有几个标签没有关闭。因此,作为第一步,此答案假定文档如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<SVCManifest xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="typens:SVCManifest">
   <Databases xsi:type="typens:ArrayOfSVCDatabase" />
   <Resources xsi:type="typens:ArrayOfSVCResource">
      <SVCResource xsi:type="typens:SVCResource">
         <ID>{429221BF-D0A1-40D8-9DC1-B41D269E95C7}</ID>
         <Name>test.crf</Name>
         <Metadata xsi:type="typens:XmlPropertySet">
            <XmlDoc>&lt;?xml version="1.0"?&gt;
&lt;metadata xml:lang="en"&gt;&lt;Esri&gt;&lt;CreaDate&gt;20211219&lt;/metadata&gt;</XmlDoc>
         </Metadata>
      </SVCResource>
   </Resources>
</SVCManifest>

另外,正如我所提到的,你不能在一个格式良好的 xml 中包含两个 xml 声明,如果你有一个声明,它必须在文档的开头,而不是在中间的某个地方。

接下来,我们开始实际的过程,但使用 lxml 库。这应该让您足够接近我认为您的预期输出。如果它不是 100% 那里,你将不得不修改一下:

from lxml import etree
source = """[the content of airquality.xml, from the question]"""
target = """[the content of DD2MI_result.xml, as corrected above]"""

s_doc = etree.XML(source.encode())
t_doc = etree.XML(target.encode())

#first, we get rid of the ugly XmlDoc element in target doc (DD2MI_result.xml)
for t in t_doc.xpath('//XmlDoc'):
    t.getparent().remove(t)

#we then create an empty replacement for it
new_xd = etree.Element("XmlDoc")

#next, the replacement element is inserted in the target document in the correct place  
for m in t_doc.xpath('//Metadata'):
    m.addnext(new_xd)

#finally, we insert in the new XmlDoc element the contents of the source document (airquality.xml)
for t in t_doc.xpath('//XmlDoc'):
    t.insert(0,s_doc.xpath('//*')[0])

#confirm that the output is what you are looking for:
print(etree.tostring(t_doc, xml_declaration=True, pretty_print=True).decode())

正如我所说,这可能不是你想要做的 100%,但应该让你更接近。

【讨论】:

  • 我不想将 xml 文件作为字符串传递。我想把它作为输入文件,因为文件会改变。我怎样才能做到这一点。其余的工作正常
【解决方案2】:

考虑XSLT,这是一种专用于转换XML 文件的语言,它维护document() 函数以读取其他XML 文档。您甚至可以避免任何 for 循环和 if 逻辑。

Python 的第三方 lxml 可以运行 XSLT 1.0 脚本(不是内置的 etreeminidom)。或者,Python可以调用第三方XSLT 1.0, 2.0, even 3.0 processors

XSLT (另存为.xsl,一个特殊的.xml文件)

以下假设 airquality.xml 与 DD2MI_result.xml 位于同一文件夹中。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" encoding="utf-8" indent="yes" />
    <xsl:strip-space elements="*"/>

    <!-- IDENTITY TRANSFORM -->
    <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
    </xsl:template>

    <!-- REPLACE XMLDoc -->
    <xsl:template match="XmlDoc">
     <xsl:copy>
       <xsl:apply-templates select="document('airquality.xml')"/>
     </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Python

import lxml.etree as et 

doc = et.parse('DD2MI_result.xml') 
xsl = et.parse('MyScript.xsl') 

# CONFIGURE TRANSFORMER 
transform = et.XSLT(xsl) 

# TRANSFORM SOURCE DOC 
result = transform(doc) 

# OUTPUT TO CONSOLE 
print(result) 

# SAVE TO FILE 
result.write_output('Output.xml')

输出

<SVCManifest xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="typens:SVCManifest">
  <Databases xsi:type="typens:ArrayOfSVCDatabase"/>
  <Resources xsi:type="typens:ArrayOfSVCResource"/>
  <SVCResource xsi:type="typens:SVCResource"/>
  <ID>{429221BF-D0A1-40D8-9DC1-B41D269E95C7}</ID>
  <Name>test.crf</Name>
  <Metadata xsi:type="typens:XmlPropertySet">
    <XmlDoc>
      <gmd:MD_Metadata xmlns:gco="http://www.isotc211.org/2005/gco" xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:srv="http://www.isotc211.org/2005/srv" xmlns:gmx="http://www.isotc211.org/2005/gmx" xmlns:gsr="http://www.isotc211.org/2005/gsr" xmlns:gss="http://www.isotc211.org/2005/gss" xmlns:gts="http://www.isotc211.org/2005/gts" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.isotc211.org/2005/gmd http://schemas.opengis.net/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd">
        <gmd:fileIdentifier>
          <gco:CharacterString>https://hdl.handle.net/20.500.12085/1f97f2a1-75fc-4110-ae22-f873d7d86565@metadata</gco:CharacterString>
        </gmd:fileIdentifier>
        <gmd:language>
          <gmd:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng">eng</gmd:LanguageCode>
        </gmd:language>
      </gmd:MD_Metadata>
    </XmlDoc>
  </Metadata>
</SVCManifest>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多