如何便捷分割指定QTI XML文件为4个目标片段?
分割XML为指定4部分的简便方法
针对你需要把目标XML分割成4个指定片段的需求,这里分享几个实用又高效的方法,还能轻松应对重复元素的问题:
方法1:用专业文本编辑器的正则定位提取(适合快速手动操作)
像VS Code、Sublime Text这类编辑器都支持强大的正则查找,能精准定位到你要的片段:
- 打开XML文件后,使用正则查找功能(VS Code快捷键
Ctrl+F,勾选正则模式) - 针对每个Part,编写匹配起始到结束标签的正则(注意利用元素的属性或唯一结构来避免匹配到重复元素):
- 比如匹配Part1:
<!DOCTYPE questestinterop.*?</material>\s*</material>(非贪婪模式确保只匹配到目标闭合标签) - 找到目标内容后,直接复制到新建的XML文件中,保存即可。
- 比如匹配Part1:
方法2:用Python脚本批量/精准提取(适合复杂场景或重复操作)
如果需要处理多个类似文件,或者担心手动提取出错,用Python脚本是最优解,能精准定位重复元素:
下面是一个简化的示例脚本(依赖lxml库,先安装pip install lxml):
from lxml import etree # 解析XML文件 tree = etree.parse("your_xml_file.xml") root = tree.getroot() # 提取Part1:从DOCTYPE到第二个material part1_content = etree.tostring(root.find(".//item"), encoding="unicode").split('<response_str')[0] # 补充DOCTYPE和根节点开头 part1 = '<!DOCTYPE questestinterop SYSTEM "ims_qtiasiv1p2p1.dtd"> <!--Generated by ILIAS XmlWriter--> <questestinterop>' + part1_content # 提取Part2:从第一个response_str到</flow></presentation> item_node = root.find(".//item") presentation_node = item_node.find(".//presentation") part2_content = etree.tostring(presentation_node.find(".//response_str[@ident='gap_0']").getparent(), encoding="unicode") part2 = part2_content.split('<resprocessing')[0].strip() # 提取Part3:resprocessing部分 part3 = etree.tostring(root.find(".//resprocessing"), encoding="unicode") # 提取Part4:指定的itemfeedback部分 part4 = etree.tostring(root.find(".//itemfeedback[@ident='response_onenotcorrect']"), encoding="unicode") # 保存每个部分到文件 with open("part1.xml", "w", encoding="utf-8") as f: f.write(part1) with open("part2.xml", "w", encoding="utf-8") as f: f.write(part2) with open("part3.xml", "w", encoding="utf-8") as f: f.write(part3) with open("part4.xml", "w", encoding="utf-8") as f: f.write(part4)
这个脚本通过元素的ident属性来定位重复元素,完全不用担心匹配错目标节点。
分割后的4个部分内容
Part 1
<!DOCTYPE questestinterop SYSTEM "ims_qtiasiv1p2p1.dtd"> <!--Generated by ILIAS XmlWriter--> <questestinterop> <item title="titel" maxattempts="0" ident="il_0_qst_152800"> <qticomment>beschreibung</qticomment> <duration>P0Y0M0DT0H1M0S</duration> <itemmetadata> <qtimetadata> <qtimetadatafield> <fieldlabel>ILIAS_VERSION</fieldlabel> <fieldentry>5.3.8 2018-08-29</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>QUESTIONTYPE</fieldlabel> <fieldentry>CLOZE QUESTION</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>AUTHOR</fieldlabel> <fieldentry>Patrick Maik Mächler</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>additional_cont_edit_mode</fieldlabel> <fieldentry>default</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>externalId</fieldlabel> <fieldentry>5c3f83ce4b6880.97213190</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>textgaprating</fieldlabel> <fieldentry>ci</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>fixedTextLength</fieldlabel> <fieldentry>1</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>identicalScoring</fieldlabel> <fieldentry>1</fieldentry> </qtimetadatafield> <qtimetadatafield> <fieldlabel>combinations</fieldlabel> <fieldentry>W10=</fieldentry> </qtimetadatafield> </qtimetadata> </itemmetadata> <presentation label="titel"> <flow> <material> <mattext texttype="text/xhtml"><p>text1</p> <div id="OKAYFREEDOM_INJECTED" style="display: none;"></div></mattext> </material> <material> <mattext texttype="text/xhtml"><p></p> <p>text2</p> <p></p> <p>auswahllücke</mattext> </material>
Part 2
<response_str ident="gap_0" rcardinality="Single"> <render_choice shuffle="No"> <response_label ident="0"> <material> <mattext>auswahl1</mattext> </material> </response_label> <response_label ident="1"> <material> <mattext>auswahl2</mattext> </material> </response_label> </render_choice> </response_str> <material> <mattext texttype="text/plain">textlücke</mattext> </material> <response_str ident="gap_1" rcardinality="Single"> <render_fib maxchars="2" columns="8" prompt="Box" fibtype="String"/> </response_str> <material> <mattext texttype="text/plain">numlücke</mattext> </material> <response_num ident="gap_2" rcardinality="Single" numtype="Decimal"> <render_fib maxchars="3" columns="2" prompt="Box" fibtype="Decimal" maxnumber="100" minnumber="1"/> </response_num> <material> <mattext texttype="text/xhtml"></p> <p></p> <div></div> <p></p> <div></div> <div></div></mattext> </material> </flow> </presentation>
Part 3
<resprocessing> <outcomes> <decvar/> </outcomes> <respcondition continue="Yes"> <conditionvar> <varequal respident="gap_0">auswahl1</varequal> </conditionvar> <setvar action="Add">1</setvar> <displayfeedback linkrefid="0_Response_0" feedbacktype="Response"/> </respcondition> <respcondition continue="Yes"> <conditionvar> <varequal respident="gap_0">auswahl2</varequal> </conditionvar> <setvar action="Add">2</setvar> <displayfeedback linkrefid="0_Response_1" feedbacktype="Response"/> </respcondition> <respcondition continue="Yes"> <conditionvar> <varequal respident="gap_1">antwort1</varequal> </conditionvar> <setvar action="Add">3</setvar> <displayfeedback linkrefid="1_Response_0" feedbacktype="Response"/> </respcondition> <respcondition continue="Yes"> <conditionvar> <varequal respident="gap_1">antwort2</varequal> </conditionvar> <setvar action="Add">4</setvar> <displayfeedback linkrefid="1_Response_1" feedbacktype="Response"/> </respcondition> <respcondition continue="Yes"> <conditionvar> <varequal respident="gap_2">99</varequal> </conditionvar> <setvar action="Add">5</setvar> <displayfeedback linkrefid="2_Response_0" feedbacktype="Response"/> </respcondition>
Part 4
<itemfeedback ident="response_onenotcorrect" view="All"> <flow_mat> <material> <mattext texttype="text/xhtml"><p>respnotcorrect</p> <div id="OKAYFREEDOM_INJECTED" style="display: none;"></div></mattext> </material> </flow_mat> </itemfeedback>
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

