Прошу помощи в автоматизации редактирования файла *.xml

Здравствуйте уважаемые участники сообщества!

Передо мной стоит задача в уменьшении файла безопасности OVAL с целью оптимизации проверки и уменьшении нагрузки на серверные мощности. Он имеет формат xml, внушительный размер 164Mb и довольно понятную структуру, сейчас я постараюсь всё подробно описать. введите сюда описание изображения

<defenitions>
  <definition id="oval:org.opensuse.security:def:19990524"....>
    .....
  </defenition>
</defenitions>
<tests>
  <rpminfo_test id="oval:org.opensuse.security:tst:2009334017" ..... >
    .....
  </rpminfo_test>
</tests>
<object>
  <rpminfo_object id="oval:org.opensuse.security:obj:2009030416" ..... >
    .....
  </rpminfo_object>
</object>
<states>
  <rpminfo_state id="oval:org.opensuse.security:ste:2009079458" ... >
    .....
  </rpminfo_state>
</states>

Так вот нужно найти блоки в которых XXXXXXXX меньше определённого значения и удалить полностью его содержимое, вместе с тегами.

Вот например в блоке < defenitions> содержится огромное количество подблоков < defenition> каждый со своим id. И если его id меньше 20170000, то его нужно удалить полностью и повторить операцию со следующим блоком. А в блоке < tests> и в следующих двух поисковым числом должно быть 2017000000.

Помогите написать скрипт на python, использоваться он будет на SUSE Linux Enterprise


Небольшой кусочек файла до запуска скрипта

<?xml version="1.0" encoding="UTF-8"?>
    <oval_definitions
        xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux "
        xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5"
        xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5">
      <generator>
          <oval:product_name>Marcus Updateinfo to OVAL Converter</oval:product_name>
          <oval:schema_version>5.5</oval:schema_version>
          <oval:timestamp>2022-04-27T06:04:52</oval:timestamp>
      </generator>
<definitions>
<definition id="oval:org.opensuse.security:def:19990524" version="1" class="vulnerability">
 <metadata>
 <title>CVE-1999-0524</title>
   #Дальше идёт много строчек текста/кода обрезал их из-за большого количества символов
 </metadata>
</definition>
<definition id="oval:org.opensuse.security:def:20001254" version="1" class="vulnerability">
 <metadata>
 <title>CVE-2000-1254</title>
    #Дальше идёт много строчек текста/кода обрезал их из-за большого количества символов
 </metadata>
</definition>
<definition id="oval:org.opensuse.security:def:20170405" version="1" class="vulnerability">
 <metadata>
 <title>CVE-2017-0405</title>
 #Дальше идёт много строчек текста/кода обрезал их из-за большого количества символов
  </metadata>
</definition>

</definitions>
<tests>
    <rpminfo_test id="oval:org.opensuse.security:tst:2009334017" version="1" comment="kernel-default is ==0" check="all" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
        <object object_ref="oval:org.opensuse.security:obj:2009030416"/>
        <state state_ref="oval:org.opensuse.security:ste:2009079458"/>
    </rpminfo_test>
    <rpminfo_test id="oval:org.opensuse.security:tst:2017669873" version="1" comment="sled-release is ==15" check="at least one" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
        <object object_ref="oval:org.opensuse.security:obj:2017031917"/>
        <state state_ref="oval:org.opensuse.security:ste:2017061809"/>
    </rpminfo_test>
</tests>
<objects>
    <rpminfo_object id="oval:org.opensuse.security:obj:2009030416" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
        <name>kernel-default</name>
    </rpminfo_object>
    <rpminfo_object id="oval:org.opensuse.security:obj:2017030418" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
        <name>kernel-source</name>
    </rpminfo_object>
</objects>
<states>
  <rpminfo_state id="oval:org.opensuse.security:ste:2009079458" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
   <version operation="equals">0</version>
  </rpminfo_state>
  <rpminfo_state id="oval:org.opensuse.security:ste:2017061809" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
   <version operation="equals">15</version>
  </rpminfo_state>
 </states>
 </oval_definitions>

А вот это я хочу видеть после отрабатывания скрипта

<?xml version="1.0" encoding="UTF-8"?>
    <oval_definitions
        xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux "
        xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5"
        xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5">
      <generator>
          <oval:product_name>Marcus Updateinfo to OVAL Converter</oval:product_name>
          <oval:schema_version>5.5</oval:schema_version>
          <oval:timestamp>2022-04-27T06:04:52</oval:timestamp>
      </generator>
<definitions>
<definition id="oval:org.opensuse.security:def:20170405" version="1" class="vulnerability">
 <metadata>
 <title>CVE-2017-0405</title>
 #Дальше идёт много строчек текста/кода обрезал их из-за большого количества символов
  </metadata>
</definition>

</definitions>
<tests>
    <rpminfo_test id="oval:org.opensuse.security:tst:2017669873" version="1" comment="sled-release is ==15" check="at least one" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
        <object object_ref="oval:org.opensuse.security:obj:2017031917"/>
        <state state_ref="oval:org.opensuse.security:ste:2017061809"/>
    </rpminfo_test>
</tests>
<objects>
    <rpminfo_object id="oval:org.opensuse.security:obj:2017030418" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
        <name>kernel-source</name>
    </rpminfo_object>
</objects>
<states>
  <rpminfo_state id="oval:org.opensuse.security:ste:2017061809" version="1" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">
   <version operation="equals">15</version>
  </rpminfo_state>
 </states>
 </oval_definitions>

Как уже видно не осталось блоков с id меньше 2017000000


Ответы (1 шт):

Автор решения: Yitzhak Khabinsky

Пожалуйста, попробуйте следующий XSLT.

Оно использует так называемый Identity Transform шаблон.

XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5"
    xmlns:ns2="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5">
    <xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--delete not needed elements based on the trailing @id value-->
    <xsl:template match="oval-def:definition[number(substring(@id,32,8)) &lt; 20170000]" />
    <xsl:template match="ns2:rpminfo_test[number(substring(@id,32,10)) &lt; 2017000000]" />
    <xsl:template match="ns2:rpminfo_object[number(substring(@id,32,10)) &lt; 2017000000]" />
    <xsl:template match="ns2:rpminfo_state[number(substring(@id,32,10)) &lt; 2017000000]" />
</xsl:stylesheet>

Python

import os
import lxml.etree as ET
import sys
if sys.version_info[0] >= 3:
    unicode = str

inputfile = "D:\\temp\\input.xml"
xsltfile = "D:\\temp\\process.xslt"
outfile = "D:\\output\\output.xml"

dom = ET.parse(inputfile)
xslt = ET.parse(xsltfile)
transform = ET.XSLT(xslt)
newdom = transform(dom)
infile = unicode((ET.tostring(newdom, pretty_print=True)))
outfile = open(outfile, 'a')
outfile.write(infile)
→ Ссылка