You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的lxml在XML的testcases节点下追加新节点?

问题描述

尝试用lxml的append函数在XML的testcases节点内追加新节点时,出现错误:

AttributeError: 'NoneType' object has no attribute 'append'

将节点追加到question父节点时无报错,但无法得到预期输出。

复现代码

from lxml import etree
    
tree = etree.parse("d_xml.xml")

d='<testcase testtype="0" useasexample="0" hiderestiffail="0" mark="1.0000000" > <testcode> <text>print(solve(' \
  'read_file("file_2.txt")))</text> </testcode><stdin><text></text></stdin><expected><text>status_2</text></expected' \
  '><extra><text></text></extra><display><text>SHOW</text> </display></testcase>'
# contentnav = tree.find("question")
contentnav = tree.find("testcases")
contentnav.append(etree.XML(d))
print(etree.tostring(tree))
tree.write('output.xml', pretty_print=True, xml_declaration=True,   encoding="utf-8")

原XML文件(d_xml.xml)

<?xml version="1.0" encoding="UTF-8"?>
<quiz>
  <!-- question: 0  -->
  <!-- question: 6675757  -->
  <question type="coderunner">
    <name>
      <text>test_code_runner</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<p dir="ltr" style="text-align: left;">ex_test<br></p>]]></text>
    </questiontext>
    <generalfeedback format="html">
      <text></text>
    </generalfeedback>
    <giveupallowed>0</giveupallowed>
    <prototypeextra></prototypeextra>
    <testcases>
      <testcase testtype="0" useasexample="0" hiderestiffail="0" mark="1.0000000">
        <testcode>
          <text>print(solve(read_file('file_1.txt')))</text>
        </testcode>
        <stdin>
          <text></text>
        </stdin>
        <expected>
          <text>status_1</text>
        </expected>
        <extra>
          <text></text>
        </extra>
        <display>
          <text>SHOW</text>
        </display>
      </testcase>


      <file name="fmlie.cpp" path="/" encoding="base64">aW1wb3J0IHJhbmRvbH</file>
      <file name="idfile.txt" path="/" encoding="base64">TnVA2DQoyICg==</file>
    </testcases>
  </question>

</quiz>

预期输出

<?xml version="1.0" encoding="UTF-8"?>
<quiz>
  <!-- question: 0  -->
  <!-- question: 6675757  -->
  <question type="coderunner">
    <name>
      <text>test_code_runner</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<p dir="ltr" style="text-align: left;">ex_test<br></p>]]></text>
    </questiontext>
    <generalfeedback format="html">
      <text></text>
    </generalfeedback>
    <giveupallowed>0</giveupallowed>
    <prototypeextra></prototypeextra>
    <testcases>
      <testcase testtype="0" useasexample="0" hiderestiffail="0" mark="1.0000000">
        <testcode>
          <text>print(solve(read_file('file_1.txt')))</text>
        </testcode>
        <stdin>
          <text></text>
        </stdin>
        <expected>
          <text>status_1</text>
        </expected>
        <extra>
          <text></text>
        </extra>
        <display>
          <text>SHOW</text>
        </display>
      </testcase>
      <testcase testtype="0" useasexample="0" hiderestiffail="0" mark="1.0000000">
        <testcode>
          <text>print(solve(read_file('file_2.txt')))</text>
        </testcode>
        <stdin>
          <text></text>
        </stdin>
        <expected>
          <text>status_2</text>
        </expected>
        <extra>
          <text></text>
        </extra>
        <display>
          <text>SHOW</text>
        </display>
      </testcase>


      <file name="fmlie.cpp" path="/" encoding="base64">aW1wb3J0IHJhbmRvbH</file>
      <file name="idfile.txt" path="/" encoding="base64">TnVA2DQoyICg==</file>
    </testcases>
  </question>

</quiz>
解决方法

错误原因是tree.find("testcases")返回None——find方法只会查找当前节点的直接子节点,而testcases是question节点的子节点,并非根节点quiz的直接子节点。

有两种修复方式:

  1. 先找到question节点,再从中查找testcases
  2. 使用XPath的递归查找语法.//testcases,直接定位所有层级下的testcases节点

修正后的代码

from lxml import etree
    
tree = etree.parse("d_xml.xml")

d='<testcase testtype="0" useasexample="0" hiderestiffail="0" mark="1.0000000" > <testcode> <text>print(solve(' \
  'read_file("file_2.txt")))</text> </testcode><stdin><text></text></stdin><expected><text>status_2</text></expected' \
  '><extra><text></text></extra><display><text>SHOW</text> </display></testcase>'

# 方式1:先找question,再找testcases
question = tree.find("question")
contentnav = question.find("testcases")

# 方式2:用XPath递归查找(二选一即可)
# contentnav = tree.find(".//testcases")

contentnav.append(etree.XML(d))
print(etree.tostring(tree))
tree.write('output.xml', pretty_print=True, xml_declaration=True, encoding="utf-8")

运行后即可将新的testcase节点追加到目标testcases节点内部,得到符合预期的XML输出。

内容的提问来源于stack exchange,提问作者rpb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:15:48