Я хочу удалить все пиды, которые соответствуют 302-310.
Я думаю, что ваша логика регулярных выражений неверна. Если у вас был pidNumber 319
(или 312
, 313
и т. Д.), Эти элементы pid также будут удалены.
Кроме того, вместо полного удаления pid
ваш код просто удаляет дочерние элементы, оставляя пустой элемент pid
. (Может быть, это и желательно, но это не звучало так, как будто " Я хотел бы удалить базу элементов на основании совпадения подэлемента. ".)
Вместо использования getroot()
попробуйте использовать find()
, чтобы получить элемент profile
. Это родительский элемент pid
, который нам нужен для удаления самого pid
.
И вместо использования регулярного выражения для сопоставления pidNumber
, просто сделайте базовое сравнение.
Пример ...
file.xml (добавлены дополнительные pid
элементы для тестирования)
<entry>
<title>TEST1</title>
<profile>
<title>Default</title>
<pid>
<pidNumber>1880</pidNumber>
<ContentType>PMT</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>201</pidNumber>
<ContentType>Video</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>301</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>302</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>303</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>309</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>310</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>319</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
</profile>
</entry>
Python
from xml.etree import ElementTree as ET
tree = ET.parse("file.xml")
profile = tree.find("profile")
for pid in profile.findall(".//pid"):
nbr = int(pid.find("pidNumber").text)
if 302 <= nbr <= 310:
profile.remove(pid)
tree.write('out.xml')
out.xml
<entry>
<title>TEST1</title>
<profile>
<title>Default</title>
<pid>
<pidNumber>1880</pidNumber>
<ContentType>PMT</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>201</pidNumber>
<ContentType>Video</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>301</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
<pid>
<pidNumber>319</pidNumber>
<ContentType>Audio</ContentType>
<isScrambled>0</isScrambled>
</pid>
</profile>
</entry>
Другой вариант - использовать lxml вместо ElementTree. Это обеспечит вам полную поддержку xpath, чтобы вы могли выполнять сравнение в предикате.
Используя приведенный выше ввод file.xml
, следующий питон выдает тот же вывод out.xml
, что и выше.
from lxml import etree
tree = etree.parse("file.xml")
for pid in tree.xpath(".//pid[pidNumber[. >= 302][310 >= .]]"):
pid.getparent().remove(pid)
tree.write("out.xml")
Третий вариант - использовать XSLT (спасибо за предложение @Parfait) ...
Python
from lxml import etree
tree = etree.parse("file.xml")
xslt = etree.parse("test.xsl")
new_tree = tree.xslt(xslt)
new_tree.write_output("out_xslt.xml")
XSLT 1.0 (test.xsl)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pid[pidNumber[. >= 302][310 >= .]]"/>
</xsl:stylesheet>
Опять же, это дает те же результаты, что и другие опции, использующие тот же ввод.