Заменить элементы в XML со ссылкой на pandas фрейм данных - PullRequest
0 голосов
/ 24 апреля 2020

Я использую l xml, чтобы прочитать мой xml файл с:

tree = etree.parse(r'C:\Users\xxx\Desktop\misc work\xmledit\SalesTransactionCustom.xml')

и получить файл xml, например:

<?xml version="1.0" encoding="UTF-8"?>
<ProcessSalesTransactionCustom xmlns="http://schema.xxxx.com/xxxxx/2" releaseID="9.2">
  <ApplicationArea>
    <Sender>
      <LogicalID>xxxxxx.file.syncxxxxx5salesinvoice</LogicalID>
      <ComponentID>External</ComponentID>
      <ConfirmationCode>OnError</ConfirmationCode>
    </Sender>
    <CreationDateTime>2020-04-16T14:50:26.976Z</CreationDateTime>
    <BODID>xxxx-nid:xxxxx:1001::Default_1001#320000:?SalesTransactionCustom&amp;verb=Process</BODID>
  </ApplicationArea>
  <DataArea>
    <Process>
      <TenantID>xxx</TenantID>
      <AccountingEntityID>4710</AccountingEntityID>
      <LocationID>S_4710</LocationID>
      <ActionCriteria>
        <ActionExpression actionCode="Add"/>
      </ActionCriteria>
    </Process>
    <SalesTransactionCustom>
      <FinancialBatch>
        <TransactionDate>2019-09-27T00:00:00</TransactionDate>
        <BatchReference>KUKS_20190928052427</BatchReference>
      </FinancialBatch>
      <TransactionHeader>
        <TransactionType>HEI</TransactionType>
        <SalesInvoice>
          <Invoice>19001160</Invoice>
          <BusinessPartner>417B00</BusinessPartner>
          <DocumentDate>2019-09-27T00:00:00</DocumentDate>
          <DueDate>2019-11-20T00:00:00</DueDate>
          <Amount>152248.80</Amount>
          <Currency>EUR</Currency>
          <TaxCountry>DK</TaxCountry>
          <TaxCode>BESIT</TaxCode>
          <NonFinalizedTransaction>
            <TransactionReference>417B00 PC210LCI-11</TransactionReference>
            <LedgerAccount>50000400</LedgerAccount>
            <Dimension1>100</Dimension1>
            <Dimension2>KUK</Dimension2>
            <Dimension3/>
            <Dimension4/>
            <Dimension5/>
            <Dimension6/>
            <Dimension7/>
            <Dimension8/>
            <TaxAmount>0.00</TaxAmount>
            <DebitCreditFlag>credit</DebitCreditFlag>
            <Amount>152248.80</Amount>
          </NonFinalizedTransaction>
        </SalesInvoice>
      </TransactionHeader>
      <TransactionHeader>
        <TransactionType>HEI</TransactionType>
        <SalesInvoice>
          <Invoice>19001161</Invoice>
          <BusinessPartner>412600</BusinessPartner>
          <DocumentDate>2019-09-27T00:00:00</DocumentDate>
          <DueDate>2019-11-20T00:00:00</DueDate>
          <Amount>113848.17</Amount>
          <Currency>EUR</Currency>
          <TaxCountry>AT</TaxCountry>
          <TaxCode>GBSI</TaxCode>
          <NonFinalizedTransaction>
            <TransactionReference>412600 PC210NLC-11</TransactionReference>
            <LedgerAccount>50000400</LedgerAccount>
            <Dimension1>100</Dimension1>
            <Dimension2>KUK</Dimension2>
            <Dimension3/>
            <Dimension4/>
            <Dimension5/>
            <Dimension6/>
            <Dimension7/>
            <Dimension8/>
            <TaxAmount>0.00</TaxAmount>
            <DebitCreditFlag>credit</DebitCreditFlag>
            <Amount>113848.17</Amount>
          </NonFinalizedTransaction>
        </SalesInvoice>
      </TransactionHeader>
    </SalesTransactionCustom>
  </DataArea>
</ProcessSalesTransactionCustom>

У меня есть pandas dataframe like (здесь первая строка - имена столбцов):

Tag             Old Value   New Value
BusinessPartner 417B00      BPE000104
BusinessPartner 412600      BPE000153
LedgerAccount   50000400    108092200

Я хочу заменить атрибуты элементов в xml ссылкой на этот pandas dataframe. Я хочу иметь возможность найти комбинацию тега и старого значения и заменить атрибут новым значением. Мне также нужно иметь возможность записать отредактированный текст обратно на диск как XML.

Как я могу сделать это с l xml и pandas?

Спасибо advance

Редактировать: вот код, который работает благодаря @Partha Mandal

import pandas as pd
from lxml import etree

df=pd.read_excel("Sample.xlsx")
df.columns=['Tag','Old','New']
df['Old'] = df['Old'].astype(str)
df['New'] = df['New'].astype(str)

parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse(r'C:\Users\xxx\Desktop\misc work\xmledit\testxml2.xml',parser)
string = etree.tostring(tree)
string = bytes.decode(string)

tag = df.Tag; old = df.Old; new = df.New

for i in range(len(tag)):
   string = string.replace("<"+tag[i]+">"+old[i]+"</"+tag[i]+">","<"+tag[i]+">"+new[i]+"</"+tag[i]+">")

string=str.encode(string)

root = etree.fromstring(string)
my_tree = etree.ElementTree(root)
with open('testxml2.xml', 'wb') as f:
    f.write(etree.tostring(my_tree))

Ответы [ 2 ]

1 голос
/ 24 апреля 2020

Почему бы просто не прочитать XML как строку и не сделать str.replace?

tag = df.Tag; old = df.Old; new = df.New

for i in range(len(tag)):
   _str = _str.replace("<"+tag[i]+">"+old[i]+"</"+tag[i]+">","<"+tag[i]+">"+new[i]+"</"+tag[i]+">")
0 голосов
/ 25 апреля 2020

Поскольку вы используете lxml, рассмотрите XSLT , язык специального назначения, предназначенный для преобразования файлов XML в различные XML и поддерживающий передачу параметров из верхнего слоя, таких как Python. Поэтому интегрируйте параметризацию в al oop для всех записей фрейма данных:

Единственная задача состоит в том, чтобы жестко закодировать все уникальные значения Tag во втором совпадении шаблона XSLT (разрывы строк после канала в порядке):

doc:BusinessPartner|doc:LedgerAccount

, что вы можете сделать с

"|".join(['doc:'+ val for val in df['Tag'].unique()])

"|\n".join(['doc:'+ val for val in df['Tag'].unique()])

XSLT (сохранить как .xsl, специальный. xml файл )

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:doc="http://schema.xxxx.com/xxxxx/2">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!-- PARAMETERS -->
  <xsl:param name="tag" />
  <xsl:param name="old_value" />
  <xsl:param name="new_value" />

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

  <!-- CONDITIONALL ASSIGN PARAMS --> 
  <xsl:template match="doc:BusinessPartner|doc:LedgerAccount">
    <xsl:choose>
        <xsl:when test = "text() = $old_value">
            <xsl:copy>
                <xsl:value-of select="$new_value"/>
            </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy>
                <xsl:value-of select="text()"/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Python

import pandas as pd
import lxml.etree as et

df = pd.read_csv(...)

# LOAD XML AND XSL SCRIPT
xml = et.parse('Input.xml')
xsl = et.parse('Script.xsl')
transform = et.XSLT(xsl)

# PASS PARAMETER TO XSLT
df_list = df.to_dict('records')

for v in df_list:   
    result = transform(xml, tag = et.XSLT.strparam(v['Tag']), 
                            old_value = et.XSLT.strparam(v['Old Value']), 
                            new_value = et.XSLT.strparam(v['New Value']))

    xml = result

# SAVE TO NEW XML
with open("Output.xml", 'wb') as f:
    f.write(result)

XML Выход

<?xml version="1.0"?>
<ProcessSalesTransactionCustom xmlns="http://schema.xxxx.com/xxxxx/2" releaseID="9.2">
  <ApplicationArea>
    <Sender>
      <LogicalID>xxxxxx.file.syncxxxxx5salesinvoice</LogicalID>
      <ComponentID>External</ComponentID>
      <ConfirmationCode>OnError</ConfirmationCode>
    </Sender>
    <CreationDateTime>2020-04-16T14:50:26.976Z</CreationDateTime>
    <BODID>xxxx-nid:xxxxx:1001::Default_1001#320000:?SalesTransactionCustom&amp;verb=Process</BODID>
  </ApplicationArea>
  <DataArea>
    <Process>
      <TenantID>infor</TenantID>
      <AccountingEntityID>4710</AccountingEntityID>
      <LocationID>S_4710</LocationID>
      <ActionCriteria>
        <ActionExpression actionCode="Add"/>
      </ActionCriteria>
    </Process>
    <SalesTransactionCustom>
      <FinancialBatch>
        <TransactionDate>2019-09-27T00:00:00</TransactionDate>
        <BatchReference>KUKS_20190928052427</BatchReference>
      </FinancialBatch>
      <TransactionHeader>
        <TransactionType>HEI</TransactionType>
        <SalesInvoice>
          <Invoice>19001160</Invoice>
          <BusinessPartner>BPE000104</BusinessPartner>
          <DocumentDate>2019-09-27T00:00:00</DocumentDate>
          <DueDate>2019-11-20T00:00:00</DueDate>
          <Amount>152248.80</Amount>
          <Currency>EUR</Currency>
          <TaxCountry>DK</TaxCountry>
          <TaxCode>BESIT</TaxCode>
          <NonFinalizedTransaction>
            <TransactionReference>417B00 PC210LCI-11</TransactionReference>
            <LedgerAccount>108092200</LedgerAccount>
            <Dimension1>100</Dimension1>
            <Dimension2>KUK</Dimension2>
            <Dimension3/>
            <Dimension4/>
            <Dimension5/>
            <Dimension6/>
            <Dimension7/>
            <Dimension8/>
            <TaxAmount>0.00</TaxAmount>
            <DebitCreditFlag>credit</DebitCreditFlag>
            <Amount>152248.80</Amount>
          </NonFinalizedTransaction>
        </SalesInvoice>
      </TransactionHeader>
      <TransactionHeader>
        <TransactionType>HEI</TransactionType>
        <SalesInvoice>
          <Invoice>19001161</Invoice>
          <BusinessPartner>BPE000153</BusinessPartner>
          <DocumentDate>2019-09-27T00:00:00</DocumentDate>
          <DueDate>2019-11-20T00:00:00</DueDate>
          <Amount>113848.17</Amount>
          <Currency>EUR</Currency>
          <TaxCountry>AT</TaxCountry>
          <TaxCode>GBSI</TaxCode>
          <NonFinalizedTransaction>
            <TransactionReference>412600 PC210NLC-11</TransactionReference>
            <LedgerAccount>108092200</LedgerAccount>
            <Dimension1>100</Dimension1>
            <Dimension2>KUK</Dimension2>
            <Dimension3/>
            <Dimension4/>
            <Dimension5/>
            <Dimension6/>
            <Dimension7/>
            <Dimension8/>
            <TaxAmount>0.00</TaxAmount>
            <DebitCreditFlag>credit</DebitCreditFlag>
            <Amount>113848.17</Amount>
          </NonFinalizedTransaction>
        </SalesInvoice>
      </TransactionHeader>
    </SalesTransactionCustom>
  </DataArea>
</ProcessSalesTransactionCustom>
...