【问题标题】:How to traverse through XML document tags using lxml similarly to ElementTree如何使用类似于 ElementTree 的 lxml 遍历 XML 文档标签
【发布时间】:2020-04-28 13:50:05
【问题描述】:

目前我正在编辑 XML 文档,我必须在其中编辑一些标签及其属性。到目前为止,我一直在使用ElementTree 库,但是我遇到了命名空间保存的问题,所以我正在尝试重写我的脚本以使用lxmlElementTree 但是在遍历文档标签的情况下对我来说是非常合乎逻辑的。下面作为示例,我将提供将删除 XML 中的 Ext 标签并将 Resolution 标签文本更改为不同值的代码。

元素树:

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 文件,但使用 lxml 而不是 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>

【问题讨论】:

  • 如果使用lxml并且需要修改XML,可以考虑XSLT。不需要for 循环!我已经在Python questions 上回答了很多次。

标签: python xml lxml elementtree


【解决方案1】:

关于您的输入文档的意见:

  • 文档将默认命名空间 (xmlns="...") 定义为 urn:cablelabs:md:xsd:core:3.0
  • 它第二次将相同的命名空间定义为“核心”(xmlns:core="urn:cablelabs:md:xsd:core:3.0")。
  • xmlns:schemaLocation 是错误的,应该是 xsi:schemaLocation
  • 根本没有使用名为“terms”(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 知道这个命名空间的前缀——“core”——并决定使用它。这没有什么问题,还是一样的。

输出中缺少命名空间 urn:cablelabs:md:xsd:terms:3.0(“terms”),因为它在输入中未使用,并且保留未使用的声明毫无意义。

同样的事情也适用于“schemaLocation”——因为你把它写成一个命名空间声明 (xmlns:schemaLocation),ElementTree 发现这个“命名空间”没有被使用并剥离它。正确的应该是具有命名空间 (xsi:schemaLocation) 的属性。当您更正该错误时,此项目将保留在输出中。

总而言之:您没有问题。输出文档是一样的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 2016-03-08
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    相关资源
    最近更新 更多