如何遍历XML文件为重复特定标签添加序号以保证唯一性?
问题
现有一个较大的studentinfo.xml文件,需要遍历该文件,对每个stu:StudentScreening节点下的重复st:name标签添加递增序号,使每个标签名称唯一。
原始XML示例
<?xml version="1.0" encoding="UTF-8"?> <stu:StudentBreakdown> <stu:Studentdata> <stu:StudentScreening> <st:name>Sam Davies</st:name> <st:age>15</st:age> <st:hair>Black</st:hair> <st:eyes>Blue</st:eyes> <st:grade>10</st:grade> <st:teacher>Draco Malfoy</st:teacher> <st:dorm>Innovation Hall</st:dorm> <st:name>Master Splinter</st:name> </stu:StudentScreening> <stu:StudentScreening> <st:name>Cassie Stone</st:name> <st:age>14</st:age> <st:hair>Science</st:hair> <st:grade>9</st:grade> <st:teacher>Luna Lovegood</st:teacher> <st:name>Kelly Clarkson</st:name> </stu:StudentScreening> <stu:StudentScreening> <st:name>Derek Brandon</st:name> <st:age>17</st:age> <st:eyes>green</st:eyes> <st:teacher>Ron Weasley</st:teacher> <st:dorm>Hogtie Manor</st:dorm> <st:name>Miley Cyrus</st:name> </stu:StudentScreening> </stu:Studentdata> </stu:StudentBreakdown>
期望输出XML示例
<?xml version="1.0" encoding="UTF-8"?> <stu:StudentBreakdown> <stu:Studentdata> <stu:StudentScreening> <st:name0>Sam Davies</st:name0> <st:age>15</st:age> <st:hair>Black</st:hair> <st:eyes>Blue</st:eyes> <st:grade>10</st:grade> <st:teacher>Draco Malfoy</st:teacher> <st:dorm>Innovation Hall</st:dorm> <st:name1>Master Splinter</st:name1> <st:name2>Peter Griffin</st:name2> <st:name3>Louis Griffin</st:name3> </stu:StudentScreening> <stu:StudentScreening> <st:name0>Cassie Stone</st:name0> <st:age>14</st:age> <st:hair>Science</st:hair> <st:grade>9</st:grade> <st:teacher>Luna Lovegood</st:teacher> <st:name1>Kelly Clarkson</st:name1> <st:name2>Stewie Griffin</st:name2> </stu:StudentScreening> <stu:StudentScreening> <st:name0>Derek Brandon</st:name0> <st:age>17</st:age> <st:eyes>green</st:eyes> <st:teacher>Ron Weasley</st:teacher> <st:dorm>Hogtie Manor</st:dorm> <st:name1>Miley Cyrus</st:name1> </stu:StudentScreening> </stu:Studentdata> </stu:StudentBreakdown>
解决方案
方法1:使用Python的lxml库(高效处理大文件)
针对大文件,采用迭代解析方式避免内存过载,代码如下:
from lxml import etree # 替换为实际XML文件中的命名空间URI namespaces = {'stu': 'http://example.com/stu', 'st': 'http://example.com/st'} input_path = 'studentinfo.xml' output_path = 'modified_studentinfo.xml' parser = etree.iterparse(input_path, events=('start', 'end')) root = None with open(output_path, 'wb') as out_file: for event, elem in parser: if event == 'start' and root is None: root = elem out_file.write(b'<?xml version="1.0" encoding="UTF-8"?>\n') out_file.write(etree.tostring(root, encoding='utf-8', xml_declaration=False, with_tail=False)) elif event == 'end': if elem.tag == etree.QName(namespaces['stu'], 'StudentScreening'): name_elements = elem.findall('st:name', namespaces=namespaces) for idx, name_elem in enumerate(name_elements): new_tag = etree.QName(namespaces['st'], f'name{idx}') name_elem.tag = new_tag out_file.write(etree.tostring(elem, encoding='utf-8', xml_declaration=False, with_tail=True)) elem.clear() while elem.getprevious() is not None: del elem.getparent()[0] elif elem.tag != root.tag: out_file.write(etree.tostring(elem, encoding='utf-8', xml_declaration=False, with_tail=True)) elem.clear() while elem.getprevious() is not None: del elem.getparent()[0] out_file.write(b'</' + root.tag.encode('utf-8') + b'>\n')
执行前需安装lxml:pip install lxml,注意替换代码中的命名空间URI为实际值。
方法2:使用XSLT转换
编写XSLT样式表批量处理,样式表代码:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:stu="http://example.com/stu" xmlns:st="http://example.com/st"> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="stu:StudentScreening/st:name"> <xsl:element name="st:name{position()-1}" namespace="http://example.com/st"> <xsl:apply-templates select="@*|node()"/> </xsl:element> </xsl:template> </xsl:stylesheet>
以xsltproc工具为例,执行转换的命令:
xsltproc -o output.xml transform.xsl studentinfo.xml
需替换样式表中的命名空间URI为实际值。
内容的提问来源于stack exchange,提问作者PickleRick
相关产品推荐
相关产品推荐

