在Python中从ElementTree中删除空白的lxml元素

问题描述

我已经为此苦苦挣扎了几天,我想我会在这里问。

我正在准备一个XML有效载荷,以便过帐到包含财务数据的Oracle端点。我已经按照Oracle规范构造了大多数XML,但是我在其中的一个方面苦苦挣扎。这些数据将提供给总帐财务系统,并且xml结构在下面(一些元素已被省略以减少篇幅。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/apps/financials/generalLedger/journals/desktopEntry/journalImportService/types/" xmlns:jour="http://xmlns.oracle.com/apps/financials/generalLedger/journals/desktopEntry/journalImportService/">
  <soapenv:Header/>
  <soapenv:Body>
    <typ:importJournals>
      <typ:interfaceRows>
        <jour:BatchName>batch</jour:BatchName>
        <jour:AccountingPeriodName>Aug-20</jour:AccountingPeriodName>
        <jour:AccountingDate>2020-08-31</jour:AccountingDate>
        <jour:GlInterface>
          <jour:LedgerId>1234567890</jour:LedgerId>
          <jour:PeriodName>Aug-20</jour:PeriodName>
          <jour:AccountingDate>2020-08-31</jour:AccountingDate>
          <jour:Segment1>1</jour:Segment1>
          <jour:Segment2>1</jour:Segment2>
          <jour:Segment3>1</jour:Segment3>
          <jour:Segment4>1</jour:Segment4>
          <jour:Segment5>0</jour:Segment5>
          <jour:Segment6>0</jour:Segment6>
          <jour:CurrencyCode>USD</jour:CurrencyCode>
          <jour:EnteredCrAmount currencyCode="USD">10.0000</jour:EnteredCrAmount>
        </jour:GlInterface>
        <jour:GlInterface>
          <jour:LedgerId>1234567890</jour:LedgerId>
          <jour:PeriodName>Aug-20</jour:PeriodName>
          <jour:AccountingDate>2020-08-31</jour:AccountingDate>
          <jour:Segment1>2</jour:Segment1>
          <jour:Segment2>2</jour:Segment2>
          <jour:Segment3>2</jour:Segment3>
          <jour:Segment4>2</jour:Segment4>
          <jour:Segment5>0</jour:Segment5>
          <jour:Segment6>0</jour:Segment6>
          <jour:CurrencyCode>USD</jour:CurrencyCode>
          <jour:EnteredDrAmount currencyCode="USD">10.0000</jour:EnteredCrAmount>
        </jour:GlInterface>
      </typ:interfaceRows>
    </typ:importJournals>
  </soapenv:Body>
</soapenv:Envelope>

因此,如果您查看上面的XML,则在GlInterface标记内,每笔交易有2个(一个是借方,一个是贷方,如果您查看细分(帐户代码)不同),则一个GlInterface标签作为EnteredDrAmount标签,而另一个具有EnteredCrAmount标签

在源数据中,Cr或Dr标签为空,具体取决于行是借方还是贷方,在python中为“ None”。

我使用此方法的方式是调用两个调用获取数据,一个调用中Cr不为空,另一个调用Dr不为空,并且此过程可以正常工作,但是在Python中,我收到一个错误“只有一个*允许”。代码在下面。

    xmlOracle = x_Envelope(
        x_Header,x_Body(
            x_importJournals(
                x_interfaceRows(
                    x_h_BatchName(str(batch[0])),x_h_AccountingPeriodName(str(batch[3])),x_h_AccountingDate(str(batch[4])),*[x_GlInterface(
                        x_d_LedgerId(str(adid[0])),x_d_PeriodName(str(adid[1])),x_d_AccountingDate(str(adid[2])),x_d_Segment1(str(adid[5])),x_d_Segment2(str(adid[6])),x_d_Segment3(str(adid[7])),x_d_Segment4(str(adid[8])),x_d_Segment5(str(adid[9])),x_d_Segment6(str(adid[10])),x_d_CurrencyCode(str(adid[11])),x_d_EnteredCrAmount(str(adid[14]),currencyCode=str(adid[11]))
                    ) for adid in CrAdidToProcess],x_d_EnteredDrAmount(str(adid[14]),currencyCode=str(adid[11]))
                    ) for adid in DrAdidToProcess]
                )
            )
        )
    )

我还尝试过一次调用获取行的详细信息,然后删除或过滤掉标记(Cr或Dr)(如果标记为“ None”,但我对此没有运气。)

尽管上述过程有效,但是我的代码中有一个错误,并且我希望我的代码中没有错误

谢谢大家。

解决方法

经过进一步测试,我相信我已经找到解决方案。我相信我试图从ElementTree对象中删除一个元素,但它没有任何元素。当我将元素传递给remove方法/函数时,它终于可以工作了。

这是用于删除“无”条目的函数的代码。

def removeCrDrEmptyElements(element):
    for removeElement in element.xpath('/soapenv:Envelope/soapenv:Body/typ:importJournals/typ:interfaceRows/jour:GlInterface/jour:EnteredCrAmount',namespaces = { 'soapenv' : 'http://schemas.xmlsoap.org/soap/envelope/','typ' : 'http://xmlns.oracle.com/apps/financials/generalLedger/journals/desktopEntry/journalImportService/types/','jour' : 'http://xmlns.oracle.com/apps/financials/generalLedger/journals/desktopEntry/journalImportService/'
                                                      }):
        if removeElement.text == 'None':
            removeElement.getparent().remove(removeElement)

    for removeElement in element.xpath('/soapenv:Envelope/soapenv:Body/typ:importJournals/typ:interfaceRows/jour:GlInterface/jour:EnteredDrAmount','jour' : 'http://xmlns.oracle.com/apps/financials/generalLedger/journals/desktopEntry/journalImportService/'
                                                      }):
        if removeElement.text == 'None':
            removeElement.getparent().remove(removeElement)

    return element

显然,这可以更好地重写(我将这样做),但是我只想检查GlInterface标记中的两个元素EnteredCrAmount和EnteredDrAmount,如果文本为None则删除这些元素。

然后,您可以使用下面的代码来调用该函数,以返回带有已删除的Null / Nones的元素类型

xmlWithoutNull = removeCrDrEmptyElements(xmlElement)

在运行函数结果之前输出:

        <jour:GlInterface>
          # omitted elements
          <jour:EnteredCrAmount currencyCode="USD">1.000000</jour:EnteredCrAmount>
          <jour:EnteredDrAmount currencyCode="USD">None</jour:EnteredDrAmount>
          # omitted elements
        </jour:GlInterface>
        <jour:GlInterface>
          # omitted elements
          <jour:EnteredCrAmount currencyCode="USD">None</jour:EnteredCrAmount>
          <jour:EnteredDrAmount currencyCode="USD">1.000000</jour:EnteredDrAmount>
          # omitted elements
        </jour:GlInterface>

运行函数结果后的输出:

        <jour:GlInterface>
          # omitted elements
          <jour:EnteredCrAmount currencyCode="USD">1.000000</jour:EnteredCrAmount>
          # omitted elements
        </jour:GlInterface>
        <jour:GlInterface>
          # omitted elements
          <jour:EnteredDrAmount currencyCode="USD">1.000000</jour:EnteredDrAmount>
          # omitted elements
        </jour:GlInterface>