Как пройти через XML теги документа, используя l xml аналогично ElementTree - PullRequest
0 голосов
/ 28 апреля 2020

В настоящее время я редактирую XML документ, в котором мне нужно отредактировать несколько тегов и их атрибутов. До сих пор я использовал библиотеку ElementTree, однако у меня возникли проблемы с сохранением пространства имен, поэтому я пытаюсь переписать свой сценарий для использования lxml. ElementTree однако для меня было очень логично в случае обхода тегов документа. Ниже в качестве примера я приведу код, который удалит тег Ext в XML и изменит текст тега Resolution на другое значение.

ElementTree:

namespaces = dict([elem for _, elem in ET.iterparse(adiPath, events=['start-ns'])])
for ns in namespaces:
    ET.register_namespace(ns, namespaces[ns])
for asset in root.findall('.//{*}Asset'):
    if 'title:TitleType' in asset.attrib.values():
        ext = asset.find('.//{*}Ext')
        if ext != None:
            asset.remove(ext)
    if 'content:PreviewType' in asset.attrib.values():
            resolution = asset.find(".//{*}Resolution")
            resolution.text = 'different value'

Можно ли выполнить итерацию по файлу XML аналогично тому, как указано выше, но вместо ET используйте lxml?

XML Файл:

<?xml version="1.0" encoding="utf-8"?>
<ADI3 xmlns="urn:cablelabs:md:xsd:core:3.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:content="urn:cablelabs:md:xsd:content:3.0"
      xmlns:core="urn:cablelabs:md:xsd:core:3.0"
      xmlns:offer="urn:cablelabs:md:xsd:offer:3.0"
      xmlns:terms="urn:cablelabs:md:xsd:terms:3.0"
      xmlns:title="urn:cablelabs:md:xsd:title:3.0"
      xmlns:adb="urn:adb:md:xsd:adb:01"
      xmlns:schemaLocation="urn:adb:md:xsd:adb:01 ADB-EXT-C01.xsd urn:cablelabs:md:xsd:core:3.0 MD-SP-CORE-C01.xsd urn:cablelabs:md:xsd:content:3.0 MD-SP-CONTENT-C01.xsd urn:cablelabs:md:xsd:offer:3.0 MD-SP-OFFER-C01.xsd urn:cablelabs:md:xsd:terms:3.0 MD-SP-TERMS-C01.xsd urn:cablelabs:md:xsd:title:3.0 MD-SP-TITLE-C01.xsd"
      xmlns:xml="http://www.w3.org/XML/1998/namespace">
  <Asset xsi:type="title:TitleType" uriId="ID" providerVersionNum="5"
     internalVersionNum="0" creationDateTime="2020-04-22T00:00:00Z"
     startDateTime="2020-03-24T09:00:00Z" endDateTime="2022-10-06T23:59:00Z">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <ProviderQAContact>Contact</ProviderQAContact>
    <Ext>
      <adb:ExtensionType>
        <adb:TitleExt>
          <adb:SeriesInfo episodeNumber="16">
            <adb:series seriesId="106585" seasonCount="2"/>
            <adb:season seasonId="106586" number="1" episodeCount="22"/>
          </adb:SeriesInfo>
        </adb:TitleExt>
      </adb:ExtensionType>
    </Ext>
    <title:LocalizableTitle xml:lang="pol">
      <title:TitleLong>BATWOMAN EP. 16 - THROUGH THE LOOKING GLASS</title:TitleLong>
      <title:SummaryLong> Very long summary...</title:SummaryLong>
      <title:Actor fullName="Ruby Rose" firstName="Ruby" lastName="Rose"/>
      <title:Actor fullName="Rachel Skarsten" firstName="Rachel" lastName="Skarsten"/>
      <title:Actor fullName="Meagan Tandy" firstName="Meagan" lastName="Tandy"/>
      <title:Actor fullName="Camrus Johnson" firstName="Camrus" lastName="Johnson"/>
      <title:Director fullName="Sudz Sutherland" firstName="Sudz" lastName="Sutherland"/>
    </title:LocalizableTitle>
    <title:Rating ratingSystem="PL">12</title:Rating>
    <title:DisplayRunTime>00:40</title:DisplayRunTime>
    <title:Year>2019</title:Year>
    <title:CountryOfOrigin>US</title:CountryOfOrigin>
    <title:Genre>Genre</title:Genre>
    <title:ShowType>Movie</title:ShowType>
  </Asset>
  <Asset xsi:type="offer:CategoryType" uriId="ID">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <offer:CategoryPath>Path</offer:CategoryPath>
  </Asset>
  <Asset xsi:type="content:MovieType" uriId="namemp4">
    <AlternateId identifierSystem="VOD1.1">namemp4</AlternateId>
    <content:SourceUrl>name.mp4</content:SourceUrl>
    <content:Resolution>resolution</content:Resolution>
    <content:Duration>PT0H40M40S</content:Duration>
    <content:Language>pol</content:Language>
    <content:SubtitleLanguage>pol</content:SubtitleLanguage>
    <content:SubtitleLanguage>eng</content:SubtitleLanguage>
  </Asset>
  <Asset uriId="ID" xsi:type="content:MovieType">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <Provider>Prov</Provider>
    <content:SourceUrl>sub.srt</content:SourceUrl>
  </Asset>
  <Asset uriId="ID" xsi:type="content:MovieType">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <Provider>Prov</Provider>
    <content:SourceUrl>sub.srt</content:SourceUrl>
  </Asset>
  <Asset xsi:type="content:PosterType" uriId="ID">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <content:SourceUrl>poster.jpg</content:SourceUrl>
    <content:X_Resolution>700</content:X_Resolution>
    <content:Y_Resolution>1000</content:Y_Resolution>
    <content:Language>pol</content:Language>
  </Asset>
  <Asset xsi:type="offer:ContentGroupType" uriId="ID">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <offer:TitleRef uriId="ID"/>
    <offer:MovieRef uriId="namets"/>
    <offer:MovieRef uriId="subs"/>
    <offer:MovieRef uriId="subs"/>
  </Asset>
  <Asset xsi:type="offer:ContentGroupType" uriId="ID">
    <AlternateId identifierSystem="VOD1.1">ID</AlternateId>
    <offer:TitleRef uriId="ID"/>
    <offer:MovieRef uriId="poster"/> 
  </Asset>
</ADI3>

1 Ответ

2 голосов
/ 28 апреля 2020

Замечания относительно вашего входного документа:

  • Документ определяет пространство имен по умолчанию (xmlns="...") как urn:cablelabs:md:xsd:core:3.0.
  • Он определяет то же пространство имен во второй раз, что и " core "(xmlns:core="urn:cablelabs:md:xsd:core:3.0").
  • xmlns:schemaLocation неверно и должно быть xsi:schemaLocation.
  • пространство имен с именем" term "(urn:cablelabs:md:xsd:terms:3.0) вообще не используется.

Когда вы читаете этот документ и пишете его снова, как это делает ваш пример кода, вся информация сохраняется.

Но нет никакой гарантии, что выходной документ является символьным. побочная копия входного документа. Это не то, как XML работает, и это необоснованное ожидание. Гарантия, которая имеет значение, заключается в том, что выходной документ семантически эквивалентен входному документу.

Когда Ваш код выполняется, он выдает следующие выходные данные (сокращенно):

<core:ADI3
  xmlns:adb="urn:adb:md:xsd:adb:01"
  xmlns:content="urn:cablelabs:md:xsd:content:3.0"
  xmlns:core="urn:cablelabs:md:xsd:core:3.0" 
  xmlns:offer="urn:cablelabs:md:xsd:offer:3.0"
  xmlns:title="urn:cablelabs:md:xsd:title:3.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
  <core:Asset xsi:type="title:TitleType" uriId="ID" providerVersionNum="5" internalVersionNum="0" creationDateTime="2020-04-22T00:00:00Z" startDateTime="2020-03-24T09:00:00Z" endDateTime="2022-10-06T23:59:00Z">
    <core:AlternateId identifierSystem="VOD1.1">ID</core:AlternateId>

    <!-- ... -->

  </core:Asset>
</core:ADI3>

Элемент ADI3 по-прежнему находится в пространстве имен urn:cablelabs:md:xsd:core:3.0, как и раньше. Достигается ли это через пространство имен по умолчанию или через явный префикс, не имеет значения. ElementTree знал префикс для этого пространства имен - «ядро» - и решил использовать его. В этом нет ничего плохого, это все то же самое.

Пространство имен urn:cablelabs:md:xsd:terms:3.0 («термины») отсутствует в выходных данных, поскольку оно не использовалось во входных данных, а хранить неиспользуемые объявления бессмысленно.

То же самое относится и к "schemaLocation" - поскольку вы написали это как объявление пространства имен (xmlns:schemaLocation), ElementTree увидел, что это "пространство имен" не использовалось, и удалил его. Правильным был бы атрибут с пространством имен (xsi:schemaLocation). Когда вы исправите эту ошибку, этот элемент останется в выходных данных.

Подведем итог: у вас нет проблем. Выходной документ совпадает.

...