使用Python中的ElementTree按顺序将标签分配给XML

问题描述

我有一个带有多个带有嵌套子项的父项的XML文件,我想添加一个新的“ order”标签来指示他们的订单。

此刻我有类似的东西

<root>
      <level id='FRUITS'>
        <level id='APPLE'>
          <heading>APPLE HEADER </heading>
          <level id='APPLE_ONE'>
            <file fileName='APPLE_ONE_I' />
            <heading>This is Apple One I.</heading>
            <file fileName='APPLE_ONE_II' />
            <heading>This is Apple One II.</heading>
          </level>
          <level id='APPLE_TWO'>
            <file fileName='APPLE_TWO_II' />
            <heading>This is Apple One I.</heading>
          </level>
        </level>
        <level id='ORANGE'>
          <heading>ORANGE HEADER</heading>
          <level id='ORANGE_ONE'>
            <file fileName='ORANGE_ONE_I' />
            <heading>This is Orange One I.</heading>
          </level>
        </level>
      </level>
    </root>

我需要为ID的顺序添加一个指示符,而不是文件的指示符。这样看起来就像

<root>
      <level id='FRUITS' order='1'>
        <level id='APPLE' order='1'>
          <heading>APPLE HEADER</heading>
          <level id='APPLE_ONE' order='1'>
            <file fileName='APPLE_ONE_I' />
            <heading>This is Apple One I.</heading>
            <file fileName='APPLE_ONE_II' />
            <heading>This is Apple One II.</heading>
          </level>
          <level id='APPLE_TWO' order='2'>
            <file fileName='APPLE_TWO_II' />
            <heading>This is Apple One I.</heading>
          </level>
        </level>
        <level id='ORANGE' order='2'>
          <heading>ORANGE HEADER</heading>
          <level id='ORANGE_ONE' order='1'>
            <file fileName='ORANGE_ONE_I' />
            <heading>This is Orange One I.</heading>
          </level>
        </level>
      </level>
    </root>

解决方法

一种方法是在lxml中使用xpath()来获取前一个同级level的数量,以确定“ order”的值...

from lxml import etree

xml = """<root>
      <level id='FRUITS'>
        <level id='APPLE'>
          <heading>APPLE HEADER </heading>
          <level id='APPLE_ONE'>
            <file fileName='APPLE_ONE_I' />
            <heading>This is Apple One I.</heading>
            <file fileName='APPLE_ONE_II' />
            <heading>This is Apple One II.</heading>
          </level>
          <level id='APPLE_TWO'>
            <file fileName='APPLE_TWO_II' />
            <heading>This is Apple One I.</heading>
          </level>
        </level>
        <level id='ORANGE'>
          <heading>ORANGE HEADER</heading>
          <level id='ORANGE_ONE'>
            <file fileName='ORANGE_ONE_I' />
            <heading>This is Orange One I.</heading>
          </level>
        </level>
      </level>
    </root>
"""

tree = etree.fromstring(xml)

for level in tree.xpath(".//level"):
    level.set("order",str(len(level.xpath("preceding-sibling::level")) + 1))

print(etree.tostring(tree).decode())

打印输出...

<root>
      <level id="FRUITS" order="1">
        <level id="APPLE" order="1">
          <heading>APPLE HEADER </heading>
          <level id="APPLE_ONE" order="1">
            <file fileName="APPLE_ONE_I"/>
            <heading>This is Apple One I.</heading>
            <file fileName="APPLE_ONE_II"/>
            <heading>This is Apple One II.</heading>
          </level>
          <level id="APPLE_TWO" order="2">
            <file fileName="APPLE_TWO_II"/>
            <heading>This is Apple One I.</heading>
          </level>
        </level>
        <level id="ORANGE" order="2">
          <heading>ORANGE HEADER</heading>
          <level id="ORANGE_ONE" order="1">
            <file fileName="ORANGE_ONE_I"/>
            <heading>This is Orange One I.</heading>
          </level>
        </level>
      </level>
    </root>