The objective was to append a node within the node testcases
using the lxml
append function.
However, the compiler return the following error
AttributeError: 'NoneType' object has no attribute 'append'
But, append the new node into the super node such as question
does not produce any error. But as expected, this does not produce the intended output.
May I know how to address this issue?
The code to reproduce the above issue is
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")
The d_xml.xml
content is a below or downloadable via the link
<?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>
The expected output is as below
<?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>
<testcases>
<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>
CodePudding user response:
find()
method finds the first child of the context element, in this case, root element. But testcases
is not a direct child so it returns None.
Two solutions:
Find question
and then testcases
out of it.
contentnav = doc.find("question").find("testcases")
Use Xpath
contentnav = doc.xpath("//testcases")[0]
CodePudding user response:
You are almost there; try:
d=etree.fromstring('<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>')
dest = tree.xpath('//question//testcases//testcase')[-1]
#this makes sure d is inserted as the last testcase
dest.addnext(d)
print(etree.tostring(tree).decode())